From 62c2e3fd47574df8987f878b96e57a1482cbd25c Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Fri, 1 Nov 2024 23:24:53 +0900 Subject: [PATCH 001/138] =?UTF-8?q?[fix]=20StableIcon=20@Stable=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designsystem/component/icon/StableIcon.kt | 2 + .../feature/timetable/component/LectureBox.kt | 14 +-- .../timetable/component/TimetableSearchBox.kt | 89 ++++++++++--------- 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/icon/StableIcon.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/icon/StableIcon.kt index 0dcfd8400..7573dd688 100644 --- a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/icon/StableIcon.kt +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/icon/StableIcon.kt @@ -4,10 +4,12 @@ import androidx.annotation.DrawableRes import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +@Stable @Composable fun StableIcon( modifier: Modifier = Modifier, diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt index 068755e12..9feeb5e1e 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectable +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -109,12 +110,13 @@ fun LectureBox( Spacer(modifier = Modifier.height(4.dp)) } - StableIcon( - drawableResId = R.drawable.ic_plus, - tint = KoinTheme.colors.primary500, - modifier = Modifier - .size(24.dp) - .clickable { onAddLecture() }) + IconButton(onClick = onAddLecture) { + StableIcon( + drawableResId = R.drawable.ic_plus, + tint = KoinTheme.colors.primary500, + modifier = Modifier.size(24.dp) + ) + } } } diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableSearchBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableSearchBox.kt index 466598042..5df94c58d 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableSearchBox.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableSearchBox.kt @@ -1,14 +1,15 @@ package `in`.koreatech.koin.feature.timetable.component import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults @@ -34,55 +35,57 @@ fun TimetableSearchBox( onClickSettingIcon: () -> Unit = {}, onClickSearchIcon: () -> Unit = {} ) { - Column( - modifier = modifier - .fillMaxWidth(), - verticalArrangement = Arrangement.Center + Row( + modifier = modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { + IconButton(onClick = onClickSettingIcon) { StableIcon( drawableResId = R.drawable.ic_filter, tint = Color(0xFFB5C1CD), - modifier = Modifier.clickable { onClickSettingIcon() } + modifier = Modifier.size(29.dp) ) - Spacer(modifier = Modifier.width(31.dp)) - TextField( - value = searchText, - onValueChange = onSearchTextChange, - colors = TextFieldDefaults.colors( - unfocusedContainerColor = Color.White, // 배경색 (클릭 X) - focusedContainerColor = Color.White, // 배경색 (클릭 O) - unfocusedIndicatorColor = Color.Transparent, // 밑줄색 (클릭 X) - focusedIndicatorColor = Color.Transparent, // 밑줄색 (클릭 O) - cursorColor = Color.Black, // 클릭 시, 커서색 - focusedTextColor = Color.Black, // 클릭 시, 입력 텍스트 색 - ), - maxLines = 1, - placeholder = { - Text( - text = "입력해주세요.", - style = KoinTheme.typography.regular15, - color = Color(0xFFE1E1E1) - ) - }, - trailingIcon = { + } + Spacer(modifier = Modifier.width(31.dp)) + TextField( + value = searchText, + onValueChange = onSearchTextChange, + colors = TextFieldDefaults.colors( + unfocusedContainerColor = Color.White, // 배경색 (클릭 X) + focusedContainerColor = Color.White, // 배경색 (클릭 O) + unfocusedIndicatorColor = Color.Transparent, // 밑줄색 (클릭 X) + focusedIndicatorColor = Color.Transparent, // 밑줄색 (클릭 O) + cursorColor = Color.Black, // 클릭 시, 커서색 + focusedTextColor = Color.Black, // 클릭 시, 입력 텍스트 색 + ), + maxLines = 1, + placeholder = { + Text( + text = "입력해주세요.", + style = KoinTheme.typography.regular15, + color = Color(0xFFE1E1E1) + ) + }, + trailingIcon = { + IconButton(onClick = onClickSearchIcon) { StableIcon( drawableResId = R.drawable.ic_search, tint = Color(0xFFB5C1Cd), - modifier = Modifier.clickable { onClickSearchIcon() } + modifier = Modifier.size(24.dp) ) - }, - modifier = Modifier - .fillMaxWidth() - .border( - width = 1.dp, - color = Color(0xFFD2DAE2), - shape = RoundedCornerShape(4.dp) - ), - ) - } + } + }, + modifier = Modifier + .fillMaxWidth() + .defaultMinSize( + minHeight = 52.dp + ) + .border( + width = 1.dp, + color = Color(0xFFD2DAE2), + shape = RoundedCornerShape(4.dp) + ), + ) } } From 6508b8adf572875bd18888ba7cdf7f26ca1830e9 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Fri, 1 Nov 2024 23:26:08 +0900 Subject: [PATCH 002/138] =?UTF-8?q?[fix]=20=EC=8B=9C=EA=B0=84=ED=91=9C=20r?= =?UTF-8?q?adius=20=ED=95=98=EB=8B=A8=EB=8F=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/feature/timetable/section/TimetableContent.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt index e7c140b49..9bfdec3d5 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt @@ -104,11 +104,11 @@ fun TimetableContent( }, modifier = modifier .background(Color.White) - .clip(RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp)) + .clip(RoundedCornerShape(10.dp)) .border( width = 1.dp, color = KoinTheme.colors.neutral300, - shape = RoundedCornerShape(topStart = 10.dp, topEnd = 10.dp) + shape = RoundedCornerShape(10.dp) ) .drawBehind { repeat(range * 2 + 1) { // 가로축 From caf0a88db6a28c10c5e41946cd633d990b91e083 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Fri, 1 Nov 2024 23:39:44 +0900 Subject: [PATCH 003/138] =?UTF-8?q?[fix]=20=ED=81=B4=EB=A6=AD=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/component/LectureBox.kt | 4 ++-- .../section/TimetableBottomSheetHeader.kt | 8 ++++---- .../timetable/view/TimetableBottomSheet.kt | 19 +++++++++---------- .../feature/timetable/view/TimetableScreen.kt | 14 +++++++++++--- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt index 9feeb5e1e..befd8258c 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt @@ -36,7 +36,7 @@ fun LectureBox( lecture: Lecture, selectedLecture: Lecture?, modifier: Modifier = Modifier, - onAddLecture: () -> Unit = {}, + onClickAddLecture: () -> Unit = {}, onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onClickLecture: (timetableEvents: List) -> Unit = {}, ) { @@ -110,7 +110,7 @@ fun LectureBox( Spacer(modifier = Modifier.height(4.dp)) } - IconButton(onClick = onAddLecture) { + IconButton(onClick = onClickAddLecture) { StableIcon( drawableResId = R.drawable.ic_plus, tint = KoinTheme.colors.primary500, diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt index 66fb458ef..a246bde93 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt @@ -14,8 +14,8 @@ import `in`.koreatech.koin.core.designsystem.theme.KoinTheme fun TimetableBottomSheetHeader( modifier: Modifier = Modifier, onComplete: () -> Unit = {}, - onAddLecture: () -> Unit = {}, - onAddCustomLecture: () -> Unit = {}, + onClickAddLectureMode: () -> Unit = {}, + onClickAddCustomLectureMode: () -> Unit = {}, ) { Row( modifier = modifier @@ -27,7 +27,7 @@ fun TimetableBottomSheetHeader( style = KoinTheme.typography.medium18, color = KoinTheme.colors.primary500, modifier = Modifier.clickable { - onAddCustomLecture() + onClickAddCustomLectureMode() } ) Text( @@ -35,7 +35,7 @@ fun TimetableBottomSheetHeader( style = KoinTheme.typography.bold18, color = KoinTheme.colors.primary600, modifier = Modifier.clickable { - onAddLecture() + onClickAddLectureMode() } ) Text( diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt index d1979ea76..95948a1d8 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt @@ -2,10 +2,8 @@ package `in`.koreatech.koin.feature.timetable.view import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.HorizontalDivider @@ -31,15 +29,16 @@ fun TimetableBottomSheet( modifier: Modifier = Modifier, selectedLecture: Lecture? = null, colors: List = defaultColors, + onClickAddCustomLectureMode: () -> Unit = {}, + onClickAddLectureMode: () -> Unit = {}, onComplete: () -> Unit = {}, - onAddLecture: () -> Unit = {}, - onAddCustomLecture: () -> Unit = {}, + onClickSettingIcon: () -> Unit = {}, + onClickSearchIcon: () -> Unit = {}, onSearchTextChange: (text: String) -> Unit = {}, + onClickAddLecture: () -> Unit = {}, + onClickLecture: (events: List) -> Unit = {}, onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onBottomSheetHeightChange: (height: Float) -> Unit = {}, - onClickLecture: (events: List) -> Unit = {}, - onClickSearchIcon: () -> Unit = {}, - onClickSettingIcon: () -> Unit = {}, ) { Column( modifier = modifier @@ -57,8 +56,8 @@ fun TimetableBottomSheet( TimetableBottomSheetHeader( modifier = Modifier.padding(bottom = 4.dp), onComplete = onComplete, - onAddLecture = onAddLecture, - onAddCustomLecture = onAddCustomLecture + onClickAddLectureMode = onClickAddLectureMode, + onClickAddCustomLectureMode = onClickAddCustomLectureMode ) HorizontalDivider(thickness = 1.dp, color = KoinTheme.colors.neutral300) TimetableSearchBox( @@ -78,7 +77,7 @@ fun TimetableBottomSheet( selectedLecture = selectedLecture, onClickLecture = onClickLecture, onSelectedLecture = onSelectedLecture, - onAddLecture = onAddLecture + onClickAddLecture = onClickAddLecture ) HorizontalDivider(thickness = 1.dp, color = KoinTheme.colors.neutral300) } diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt index da41bae76..421dea016 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -31,6 +32,7 @@ import `in`.koreatech.koin.feature.timetable.component.TimetableDownloadBox import `in`.koreatech.koin.feature.timetable.component.TimetableScheduleBox import `in`.koreatech.koin.feature.timetable.model.dummyEvent import `in`.koreatech.koin.feature.timetable.model.dummyLecture +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterialApi::class) @Composable @@ -44,19 +46,25 @@ fun TimetableScreen( onClickDownloadTimetable: () -> Unit = {} ) { var bottomSheetHeight by remember { mutableStateOf(0f) } + val scope = rememberCoroutineScope() BottomSheetScaffold( modifier = modifier, scaffoldState = scaffoldState, sheetContent = { TimetableBottomSheet( - lectures = listOf(dummyLecture, dummyLecture.copy(name = "컴퓨터개발"),dummyLecture,dummyLecture,dummyLecture,dummyLecture,dummyLecture,dummyLecture,dummyLecture,dummyLecture,dummyLecture), + lectures = listOf(dummyLecture), selectedLecture = dummyLecture, searchText = searchText, + onClickAddLectureMode = {}, + onComplete = { scope.launch { sheetState.collapse() } }, + onClickSettingIcon = {}, + onClickSearchIcon = {}, onSearchTextChange = onSearchTextChange, + onClickAddLecture = {}, + onClickLecture = {}, + onSelectedLecture = {}, onBottomSheetHeightChange = { bottomSheetHeight = it }, - onClickSettingIcon = {}, - onClickSearchIcon = {} ) }, sheetPeekHeight = 0.dp, From c255955e88991bee2016f2f25bfadebcb921d060 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:15:38 +0900 Subject: [PATCH 004/138] =?UTF-8?q?[add]=20=EB=84=A4=EB=B9=84=EA=B2=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=BD=94=EB=93=9C=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KoinNavigationDrawerActivity.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt index 326284ba6..5822d523d 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt @@ -472,6 +472,29 @@ abstract class KoinNavigationDrawerActivity : ActivityBase(), } } + /** + * 완성되면 아래 함수 주석 풀고 연결 + */ +// private fun goToTimetableActivity() { +// if (menuState != MenuState.Main) { +// goToActivityFinish(Intent(this, TimetableActivity::class.java)) +// } else { +// val intent = Intent(this, TimetableActivity::class.java).apply { +// if (koinNavigationDrawerViewModel.userInfoFlow.value.isAnonymous) { +// putExtra("isAnonymous", true) +// } else { +// putExtra("isAnonymous", false) +// } +// } +// EventLogger.logClickEvent( +// action = EventAction.USER, +// label = "hamburger", +// value = "시간표" +// ) +// startActivity(intent) +// } +// } + private fun goToTimetableActivity() { if (menuState != MenuState.Main) { goToActivityFinish(Intent(this, TimetableActivity::class.java)) From b184e50aca7ea4aad5bab6e96d80868ab67d5d27 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:16:08 +0900 Subject: [PATCH 005/138] =?UTF-8?q?[add]=20compose=20lifecycle=20=EC=A2=85?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- koin/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/koin/build.gradle.kts b/koin/build.gradle.kts index 62830d695..1c28bd992 100644 --- a/koin/build.gradle.kts +++ b/koin/build.gradle.kts @@ -135,4 +135,6 @@ dependencies { implementation(libs.feature.delivery.ktx) implementation(libs.timber) + + implementation(libs.compose.lifecycle) } From c6272acdc70b4b314871cb61631fb9e9e6506023 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:18:35 +0900 Subject: [PATCH 006/138] =?UTF-8?q?[add]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=A2=85?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/timetable/build.gradle.kts | 3 +++ gradle/libs.versions.toml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/feature/timetable/build.gradle.kts b/feature/timetable/build.gradle.kts index 6565c8f13..9b20400a8 100644 --- a/feature/timetable/build.gradle.kts +++ b/feature/timetable/build.gradle.kts @@ -30,6 +30,9 @@ dependencies { implementation(libs.timber) + testImplementation(libs.coroutines.test) + testImplementation(libs.turbine) debugImplementation(libs.bundles.compose.debug.test) androidTestImplementation(libs.compose.ui.test.manifest) + androidTestImplementation(libs.coroutines.test) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48b5f228b..5fb82d155 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -67,6 +67,7 @@ ossLicensesVersion = "17.1.0" navigation = "2.7.7" jsoup = "1.18.1" timber = "5.0.1" +kotlinxCoroutinesTestVersion = "1.9.0" [libraries] @@ -101,6 +102,7 @@ compose-ui-test = { module = "androidx.compose.ui:ui-test-junit4" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" } compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "composeNavigationVersion" } +compose-lifecycle = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycleRuntimeKtxVersion" } security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCryptoVersion" } android-gradle-tool = { module = "com.android.tools.build:gradle", version.ref = "androidGradleVersion" } @@ -191,6 +193,8 @@ oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", v timber = { module = "com.jakewharton.timber:timber", version.ref = "timber"} +coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTestVersion" } + [plugins] android-application = { id = "com.android.application", version.ref = "androidGradleVersion" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } From 8b55c6694d41068f796124c73a260410c0da65df Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:18:58 +0900 Subject: [PATCH 007/138] =?UTF-8?q?[add]=20=ED=94=8C=EB=A1=9C=EC=9A=B0=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20turbine=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle/libs.versions.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5fb82d155..f5eb8da42 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,6 +68,7 @@ navigation = "2.7.7" jsoup = "1.18.1" timber = "5.0.1" kotlinxCoroutinesTestVersion = "1.9.0" +turbineVersion = "1.2.0" [libraries] @@ -194,6 +195,7 @@ oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", v timber = { module = "com.jakewharton.timber:timber", version.ref = "timber"} coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTestVersion" } +turbine = { module = "app.cash.turbine:turbine", version.ref = "turbineVersion" } [plugins] android-application = { id = "com.android.application", version.ref = "androidGradleVersion" } From cc5eab4e7bfb4c92e9c201b8677127944a85fb9f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:19:55 +0900 Subject: [PATCH 008/138] =?UTF-8?q?[add]=20timetables=20Datastore=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/di/datastore/DataStoreModule.kt | 13 ++++++++++ .../source/datastore/TimetableDataStore.kt | 24 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 data/src/main/java/in/koreatech/koin/data/source/datastore/TimetableDataStore.kt diff --git a/data/src/main/java/in/koreatech/koin/data/di/datastore/DataStoreModule.kt b/data/src/main/java/in/koreatech/koin/data/di/datastore/DataStoreModule.kt index ebb34f951..83bcb494b 100644 --- a/data/src/main/java/in/koreatech/koin/data/di/datastore/DataStoreModule.kt +++ b/data/src/main/java/in/koreatech/koin/data/di/datastore/DataStoreModule.kt @@ -10,6 +10,7 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import `in`.koreatech.koin.data.source.datastore.ArticleDataStore +import `in`.koreatech.koin.data.source.datastore.TimetableDataStore import javax.inject.Singleton @Module @@ -20,6 +21,10 @@ object DataStoreModule { name = "article_data_store" ) + private val Context.timetableDataStore: DataStore by preferencesDataStore( + name = "timetables" + ) + @Provides @Singleton fun provideArticleDataStore( @@ -27,4 +32,12 @@ object DataStoreModule { ): ArticleDataStore { return ArticleDataStore(context.articleDataStore) } + + @Provides + @Singleton + fun provideTimetableDataStore( + @ApplicationContext context: Context + ): TimetableDataStore { + return TimetableDataStore(context.timetableDataStore) + } } \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/source/datastore/TimetableDataStore.kt b/data/src/main/java/in/koreatech/koin/data/source/datastore/TimetableDataStore.kt new file mode 100644 index 000000000..b38f0ce98 --- /dev/null +++ b/data/src/main/java/in/koreatech/koin/data/source/datastore/TimetableDataStore.kt @@ -0,0 +1,24 @@ +package `in`.koreatech.koin.data.source.datastore + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class TimetableDataStore @Inject constructor( + private val dataStore: DataStore +) { + fun getString(key: String): Flow = + dataStore.data.map { preferences -> + preferences[stringPreferencesKey(key)] ?: "" + } + + suspend fun putString(key: String, value: String) { + dataStore.edit { preferences -> + preferences[stringPreferencesKey(key)] = value + } + } +} \ No newline at end of file From f746c0a322b93009d6a870aa35c60aba0e3c26ed Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:20:21 +0900 Subject: [PATCH 009/138] =?UTF-8?q?[add]=20frame=20id=20=EC=BF=BC=EB=A6=AC?= =?UTF-8?q?=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt index 1a068ef3a..5fd2dabd9 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt @@ -15,7 +15,9 @@ import retrofit2.http.Query interface TimetableAuthApi { @GET("/v2/timetables/lecture") - suspend fun getTimetableLectures(): TimetableLecturesResponse + suspend fun getTimetableLectures( + @Query("timetable_frame_id") timetableFrameId: Int + ): TimetableLecturesResponse @PUT("/v2/timetables/lecture") suspend fun putTimetableLectures( From 6b8ad1e7f619a0d8778f084a0c9744d39e96e076 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:21:35 +0900 Subject: [PATCH 010/138] =?UTF-8?q?[add]=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20&?= =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=AA=A8=EB=8D=B8=20=EB=A9=94?= =?UTF-8?q?=ED=8D=BC=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimetableLecturesQueryRequest.kt | 18 +++++++++++++++++ .../response/timetable/LectureResponse.kt | 19 +++++++++++++++++- .../response/timetable/SemesterResponse.kt | 10 ++++++++-- .../timetable/TimetableFrameResponse.kt | 9 ++++++++- .../timetable/TimetableLectureResponse.kt | 20 ++++++++++++++++++- .../timetable/TimetableLecturesResponse.kt | 10 +++++++++- 6 files changed, 80 insertions(+), 6 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/request/timetable/TimetableLecturesQueryRequest.kt b/data/src/main/java/in/koreatech/koin/data/request/timetable/TimetableLecturesQueryRequest.kt index ad78ae475..0106bf7d2 100644 --- a/data/src/main/java/in/koreatech/koin/data/request/timetable/TimetableLecturesQueryRequest.kt +++ b/data/src/main/java/in/koreatech/koin/data/request/timetable/TimetableLecturesQueryRequest.kt @@ -1,6 +1,8 @@ package `in`.koreatech.koin.data.request.timetable import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLectureQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery data class TimetableLecturesQueryRequest( @SerializedName("timetable_frame_id") @@ -27,3 +29,19 @@ data class TimetableLectureQueryRequest( @SerializedName("memo") val memo: String, ) + +fun TimetableLecturesQuery.toTimetableLecturesQueryRequest() = TimetableLecturesQueryRequest( + timetableFrameId = timetableFrameId, + timetableLecture = timetableLecture.map { it.toTimetableLectureQueryRequest() } +) + +fun TimetableLectureQuery.toTimetableLectureQueryRequest() = TimetableLectureQueryRequest( + id = id, + lectureId = lectureId, + classTitle = classTitle, + classTime = classTime, + classPlace = classPlace, + professor = professor, + grades = grades, + memo = memo +) diff --git a/data/src/main/java/in/koreatech/koin/data/response/timetable/LectureResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/timetable/LectureResponse.kt index c6c0ae540..b140e8a8b 100644 --- a/data/src/main/java/in/koreatech/koin/data/response/timetable/LectureResponse.kt +++ b/data/src/main/java/in/koreatech/koin/data/response/timetable/LectureResponse.kt @@ -1,6 +1,7 @@ package `in`.koreatech.koin.data.response.timetable import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.response.Lecture data class LectureResponse( @SerializedName("id") @@ -29,4 +30,20 @@ data class LectureResponse( val isElearning: String?, @SerializedName("class_time") val classTime: List, -) \ No newline at end of file +) { + fun toLecture() = Lecture( + id = id, + code = code.orEmpty(), + name = name.orEmpty(), + grades = grades.orEmpty(), + lectureClass = lectureClass.orEmpty(), + regularNumber = regularNumber.orEmpty(), + department = department.orEmpty(), + target = target.orEmpty(), + professor = professor.orEmpty(), + isEnglish = isEnglish.orEmpty(), + designScore = designScore.orEmpty(), + isElearning = isElearning.orEmpty(), + classTime = classTime + ) +} \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterResponse.kt index 21794156e..99934902c 100644 --- a/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterResponse.kt +++ b/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterResponse.kt @@ -1,10 +1,16 @@ package `in`.koreatech.koin.data.response.timetable import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.response.Semester data class SemesterResponse( @SerializedName("id") - val id :Int, + val id: Int, @SerializedName("semester") val semester: String? -) \ No newline at end of file +) { + fun toSemester() = Semester( + id = id, + semester = semester.orEmpty() + ) +} \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableFrameResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableFrameResponse.kt index 2d0898441..ff51ffa1b 100644 --- a/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableFrameResponse.kt +++ b/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableFrameResponse.kt @@ -1,6 +1,7 @@ package `in`.koreatech.koin.data.response.timetable import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame data class TimetableFrameResponse( @SerializedName("id") @@ -9,4 +10,10 @@ data class TimetableFrameResponse( val timetableName: String?, @SerializedName("is_main") val isMain: Boolean, -) +) { + fun toTimetableFrameResponse(): TimetableFrame = TimetableFrame( + id = id, + timetableName = timetableName.orEmpty(), + isMain = isMain + ) +} diff --git a/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLectureResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLectureResponse.kt index 330e3b306..9752c3fde 100644 --- a/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLectureResponse.kt +++ b/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLectureResponse.kt @@ -1,6 +1,7 @@ package `in`.koreatech.koin.data.response.timetable import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture data class TimetableLectureResponse( @SerializedName("id") @@ -31,4 +32,21 @@ data class TimetableLectureResponse( val professor: String?, @SerializedName("department") // "디자인ㆍ건축공학부" val department: String?, -) +) { + fun toTimetableLecture() = TimetableLecture( + id = id, + lectureId = lectureId, + regularNumber = regularNumber.orEmpty(), + code = code.orEmpty(), + designScore = designScore.orEmpty(), + classTime = classTime, + classPlace = classPlace.orEmpty(), + memo = memo.orEmpty(), + grades = grades.orEmpty(), + classTitle = classTitle.orEmpty(), + lectureClass = lectureClass.orEmpty(), + target = target.orEmpty(), + professor = professor.orEmpty(), + department = department.orEmpty() + ) +} diff --git a/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLecturesResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLecturesResponse.kt index 76c3ecafe..bf8827c41 100644 --- a/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLecturesResponse.kt +++ b/data/src/main/java/in/koreatech/koin/data/response/timetable/TimetableLecturesResponse.kt @@ -1,6 +1,7 @@ package `in`.koreatech.koin.data.response.timetable import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures data class TimetableLecturesResponse( @SerializedName("timetable_frame_id") @@ -11,5 +12,12 @@ data class TimetableLecturesResponse( val grades: Int?, @SerializedName("total_grades") val totalGrades: Int?, -) +) { + fun toTimetableLectures() = TimetableLectures( + timetableFrameId = timetableFrameId, + timetable = timetable.map { it.toTimetableLecture() }, + grades = grades ?: 0, + totalGrades = totalGrades ?: 0 + ) +} From 5ae0863fd77b88f0eff8cddc1f7730a2c12fb50f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:22:08 +0900 Subject: [PATCH 011/138] =?UTF-8?q?[add]=20=EC=95=84=EC=9D=B4=EC=BD=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/timetable/src/main/res/drawable/ic_minus.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 feature/timetable/src/main/res/drawable/ic_minus.xml diff --git a/feature/timetable/src/main/res/drawable/ic_minus.xml b/feature/timetable/src/main/res/drawable/ic_minus.xml new file mode 100644 index 000000000..e2822ec3e --- /dev/null +++ b/feature/timetable/src/main/res/drawable/ic_minus.xml @@ -0,0 +1,11 @@ + + + From 149c0731fd197dbd241da96fce8450e1ae258d7f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:23:15 +0900 Subject: [PATCH 012/138] =?UTF-8?q?[add]=20=EB=B9=84=EC=A6=88=EB=8B=88?= =?UTF-8?q?=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/TimetableRepositoryImpl.kt | 61 ++++++++++++++----- .../remote/TimetableRemoteDataSource.kt | 18 +++--- .../domain/repository/TimetableRepository.kt | 34 ++++------- 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt index cc23622d0..5299ce298 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt @@ -1,5 +1,9 @@ package `in`.koreatech.koin.data.repository +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import `in`.koreatech.koin.data.request.timetable.toTimetableLecturesQueryRequest +import `in`.koreatech.koin.data.source.datastore.TimetableDataStore import `in`.koreatech.koin.data.source.remote.TimetableRemoteDataSource import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery @@ -9,44 +13,71 @@ import `in`.koreatech.koin.domain.model.timetable.response.Semester import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures import `in`.koreatech.koin.domain.repository.TimetableRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.flow +import java.lang.NullPointerException import javax.inject.Inject class TimetableRepositoryImpl @Inject constructor( - private val timetableRemoteDataSource: TimetableRemoteDataSource -): TimetableRepository { - override suspend fun getSemesters(): List { - TODO("Not yet implemented") + private val timetableRemoteDataSource: TimetableRemoteDataSource, + private val timetableDataStore: TimetableDataStore, +) : TimetableRepository { + private val gson = Gson() + + override fun getSemesters(): Flow> = flow { + emit(timetableRemoteDataSource.getSemesters().map { it.toSemester() }) } - override suspend fun getLectures(semesterDate: String): List { - TODO("Not yet implemented") + override fun getLectures(semesterDate: String): Flow> = flow { + emit(timetableRemoteDataSource.getLectures(semesterDate).map { it.toLecture() }) } - override suspend fun getTimetableLectures(): TimetableLectures { - TODO("Not yet implemented") + override fun getTimetableFrames(semester: String): Flow> = flow { + emit(timetableRemoteDataSource.getTimetableFrames(semester).map { it.toTimetableFrameResponse() }) } - override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { - TODO("Not yet implemented") + override suspend fun getTimetableLectures(timetableFrameId: Int): Result = runCatching { + timetableRemoteDataSource.getTimetableLectures(timetableFrameId).toTimetableLectures() } - override suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { - TODO("Not yet implemented") + override suspend fun getTimetableLectures(semester: String): Result = runCatching{ + val timetableLecturesString = timetableDataStore.getString(semester).firstOrNull().orEmpty() + val timetableLecturesType = object : TypeToken() {}.type + try { + gson.fromJson(timetableLecturesString, timetableLecturesType) + } catch (e: NullPointerException) { + TimetableLectures(0, emptyList(), 0, 0) + } + } + + override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures = + timetableRemoteDataSource.postTimetableLectures(lectures.toTimetableLecturesQueryRequest()) + .toTimetableLectures() + + override suspend fun putTimetableLectures(key: String, value: TimetableLectures): Result = runCatching { + timetableDataStore.putString(key, gson.toJson(value)) + return getTimetableLectures(semester = key).onSuccess { + Result.success(it) + }.onFailure { + Result.failure(it) + } } override suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame { TODO("Not yet implemented") } - override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame { + override suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { TODO("Not yet implemented") } - override suspend fun deleteTimetableFrame() { + + override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame { TODO("Not yet implemented") } - override suspend fun getTimetableFrames(semester: String): List { + override suspend fun deleteTimetableFrame() { TODO("Not yet implemented") } diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt index 279b7291c..e9b7be9ca 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt @@ -20,20 +20,25 @@ class TimetableRemoteDataSource @Inject constructor( suspend fun getLectures(semesterDate: String): List = timetableApi.getLectures(semesterDate) - suspend fun getTimetableLectures(): TimetableLecturesResponse = - timetableAuthApi.getTimetableLectures() + suspend fun getTimetableLectures(timetableFrameId: Int): TimetableLecturesResponse = + timetableAuthApi.getTimetableLectures(timetableFrameId) + + suspend fun getTimetableFrames( + semester: String + ): List = timetableAuthApi.getTimetableFrames(semester) suspend fun putTimetableLectures( lectures: TimetableLecturesQueryRequest ): TimetableLecturesResponse = timetableAuthApi.putTimetableLectures(lectures) + suspend fun putTimetableFrame( + id: Int, frame: TimetableFrameQueryRequest + ): TimetableFrameResponse = timetableAuthApi.putTimetableFrame(id, frame) + suspend fun postTimetableLectures( lectures: TimetableLecturesQueryRequest ): TimetableLecturesResponse = timetableAuthApi.postTimetableLectures(lectures) - suspend fun putTimetableFrame( - id: Int, frame: TimetableFrameQueryRequest - ): TimetableFrameResponse = timetableAuthApi.putTimetableFrame(id, frame) suspend fun postTimetableFrame( frame: TimetableFrameCreateQueryRequest @@ -41,9 +46,6 @@ class TimetableRemoteDataSource @Inject constructor( suspend fun deleteTimetableFrame() = timetableAuthApi.deleteTimetableFrame() - suspend fun getTimetableFrames( - semester: String - ): List = timetableAuthApi.getTimetableFrames(semester) suspend fun deleteTimetableLecture( id: Int diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt index 2a1f86c34..9fcdc2342 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt @@ -7,36 +7,24 @@ import `in`.koreatech.koin.domain.model.timetable.response.Lecture import `in`.koreatech.koin.domain.model.timetable.response.Semester import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import kotlinx.coroutines.flow.Flow interface TimetableRepository { - suspend fun getSemesters(): List + fun getSemesters(): Flow> + fun getLectures(semesterDate: String): Flow> + fun getTimetableFrames(semester: String): Flow> - suspend fun getLectures(semesterDate: String): List + suspend fun getTimetableLectures(timetableFrameId: Int): Result + suspend fun getTimetableLectures(semester: String): Result - suspend fun getTimetableLectures(): TimetableLectures + suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures + suspend fun putTimetableLectures(key: String, value: TimetableLectures): Result + suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame - suspend fun putTimetableLectures( - lectures: TimetableLecturesQuery - ): TimetableLectures - - suspend fun postTimetableLectures( - lectures: TimetableLecturesQuery - ): TimetableLectures - - suspend fun putTimetableFrame( - id: Int, frame: TimetableFrameQuery - ): TimetableFrame - - suspend fun postTimetableFrame( - frame: TimetableFrameCreateQuery - ): TimetableFrame + suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures + suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame suspend fun deleteTimetableFrame() - - suspend fun getTimetableFrames( - semester: String - ): List - suspend fun deleteTimetableLecture(id: Int) suspend fun deleteAllTimetableFrame() } \ No newline at end of file From 63e6cb51bd4ad8765173ebcea681755f77e6afd2 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:25:07 +0900 Subject: [PATCH 013/138] =?UTF-8?q?[add]=20=EC=97=B0=EC=82=B0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/response/TimetableLecture.kt | 40 ++++- .../timetable/response/TimetableLectures.kt | 29 +++- .../feature/timetable/TimetableLectureTest.kt | 44 ++++++ .../timetable/TimetableLecturesTest.kt | 149 ++++++++++++++++++ 4 files changed, 255 insertions(+), 7 deletions(-) create mode 100644 feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLectureTest.kt create mode 100644 feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLecturesTest.kt diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLecture.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLecture.kt index 4515bd157..5052b0428 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLecture.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLecture.kt @@ -1,5 +1,8 @@ package `in`.koreatech.koin.domain.model.timetable.response +import java.time.DayOfWeek +import java.time.LocalTime + data class TimetableLecture( val id: Int, val lectureId: Int, @@ -15,4 +18,39 @@ data class TimetableLecture( val target: String = "", val professor: String = "", val department: String = "", -) +) { + /** + * @reference : TimetableLectureTest.kt + */ + fun findDayOfWeekAndTime(): Map> { + return classTime.groupBy { it / 100 } + .mapValues { entry -> + /** + * @input : [0,1,100,101] + */ + entry.value.sorted().map { value -> + val timeIndex = if (entry.key == 0) value else value % (entry.key * 100) + LocalTime.of(9 + timeIndex / 2, (timeIndex % 2) * 30) + } + /** + * @output : [09:00, 09:30], [09:00, 09:30] + */ + } + .mapKeys { + /** + * @input : {0=[09:00, 09:30], 1=[09:00, 09:30]} + */ + when (it.key) { + 0 -> DayOfWeek.MONDAY + 1 -> DayOfWeek.TUESDAY + 2 -> DayOfWeek.WEDNESDAY + 3 -> DayOfWeek.THURSDAY + 4 -> DayOfWeek.FRIDAY + else -> null + } + /** + * @output : {MONDAY=[09:00, 09:30], TUESDAY=[09:00, 09:30]} + */ + } + } +} diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLectures.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLectures.kt index 64444374b..0ab6b468b 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLectures.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/TimetableLectures.kt @@ -7,13 +7,30 @@ data class TimetableLectures( val totalGrades: Int, ){ /** - * 기본 범위는 9시~18시로 range(범위) = 9 - * 추가 범위는 24시까지 가능하기 때문에 range(범위)가 15까지 가능함. - * - * @return 9 ~ 15 + * @reference : TimetableLecturesTest.kt 파일 참고 */ - fun timeRange(): Int { - return 1 + fun formatTimeRange(): Int { + val a = timetable.map { it.classTime } + var maxItem = 0 + a.forEach {items -> + items.forEach { + if (maxItem < it) { + maxItem = it + } + } + } + + val range = (maxItem % 100) - 9 + + return if (range < 9) { + 9 + } else { + if (range % 2 == 1) { + range + 1 + } else { + range + } + } } } diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLectureTest.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLectureTest.kt new file mode 100644 index 000000000..61e2d930c --- /dev/null +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLectureTest.kt @@ -0,0 +1,44 @@ +package `in`.koreatech.koin.feature.timetable + +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Test +import java.time.DayOfWeek +import java.time.LocalTime + +class TimetableLectureTest { + val dummyTimetableLecture = TimetableLecture( + id = 1, + lectureId = 1, + code = "HRD011", + classTitle = "직업능력개발훈련평가", + professor = "우성민", + grades = "2", + lectureClass = "01", + regularNumber = "40", + department = "HRD학과", + target = "전기3", + classPlace = "", + designScore = "0", + classTime = listOf( + 0, 1 + ) + ) + + @Test + fun `classTime이 0,1,101,102가 주어질때, map(월=list(9시,9시 30분), 화=list(9시,9시 30분))을 반환한다`() = runTest { + val lecture = dummyTimetableLecture.copy( + classTime = listOf(0, 1, 100, 101) + ) + + val formatDayOfWeekAndClassTime = lecture.findDayOfWeekAndTime() + + assertEquals( + formatDayOfWeekAndClassTime, mapOf( + DayOfWeek.MONDAY to listOf(LocalTime.of(9, 0), LocalTime.of(9, 30)), + DayOfWeek.TUESDAY to listOf(LocalTime.of(9, 0), LocalTime.of(9, 30)) + ) + ) + } +} \ No newline at end of file diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLecturesTest.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLecturesTest.kt new file mode 100644 index 000000000..bf53a40ae --- /dev/null +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableLecturesTest.kt @@ -0,0 +1,149 @@ +package `in`.koreatech.koin.feature.timetable + +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertEquals +import org.junit.Test + +class TimetableLecturesTest { + val dummyTimetableLecture = TimetableLecture( + id = 1, + lectureId = 1, + code = "HRD011", + classTitle = "직업능력개발훈련평가", + professor = "우성민", + grades = "2", + lectureClass = "01", + regularNumber = "40", + department = "HRD학과", + target = "전기3", + classPlace = "", + designScore = "0", + classTime = listOf( + 0, + ) + ) + val dummyTimetables = TimetableLectures( + timetableFrameId = 1, + timetable = listOf(dummyTimetableLecture), + grades = 1, + totalGrades = 1 + ) + + @Test + fun `classTime이 emptyList() 로 주어졌을 때, 화면에 보이는 시간 범위 9(9시~18시)를 반환한다`() = runTest { + val timetables = dummyTimetables.copy( + timetable = listOf( + dummyTimetableLecture.copy(classTime = emptyList()) + ) + ) // given + + val range = timetables.formatTimeRange() + + assertEquals(range, 9) + } + + @Test + fun `classTime이 0~17로 주어졌을 때, 화면에 보이는 시간 범위 9(9시~18시)를 반환한다`() = runTest { + val timetables = dummyTimetables.copy( + timetable = listOf( + dummyTimetableLecture.copy(classTime = listOf(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) + ) + ) // given + + val range = timetables.formatTimeRange() + + assertEquals(range, 9) + } + + @Test + fun `classTime이 18과 19로 주어졌을 때, 화면에 보이는 시간 범위 10(9시~19시)을 반환한다`() = runTest { + val t1 = dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(18)))) // given + + val range1 = t1.formatTimeRange() + + assertEquals(range1, 10) + + val t2= dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(19)))) // given + + val range2 = t2.formatTimeRange() + + assertEquals(range2, 10) + } + + @Test + fun `classTime이 20과 21로 주어졌을 때, 화면에 보이는 시간 범위 11(9시~20시)을 반환한다`() = runTest { + val t1 = dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(20)))) // given + + val range1 = t1.formatTimeRange() + + assertEquals(range1, 11) + + val t2= dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(21)))) // given + + val range2 = t2.formatTimeRange() + + assertEquals(range2, 11) + } + + @Test + fun `classTime이 22과 23로 주어졌을 때, 화면에 보이는 시간 범위 12(9시~21시)을 반환한다`() = runTest { + val t1 = dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(22)))) // given + + val range1 = t1.formatTimeRange() + + assertEquals(range1, 12) + + val t2= dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(23)))) // given + + val range2 = t2.formatTimeRange() + + assertEquals(range2, 12) + } + + @Test + fun `classTime이 24과 25로 주어졌을 때, 화면에 보이는 시간 범위 13(9시~22시)을 반환한다`() = runTest { + val t1 = dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(24)))) // given + + val range1 = t1.formatTimeRange() + + assertEquals(range1, 13) + + val t2= dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(25)))) // given + + val range2 = t2.formatTimeRange() + + assertEquals(range2, 13) + } + + @Test + fun `classTime이 26과 27로 주어졌을 때, 화면에 보이는 시간 범위 14(9시~23시)을 반환한다`() = runTest { + val t1 = dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(26)))) // given + + val range1 = t1.formatTimeRange() + + assertEquals(range1, 14) + + val t2= dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(27)))) // given + + val range2 = t2.formatTimeRange() + + assertEquals(range2, 14) + } + + @Test + fun `classTime이 28과 29로 주어졌을 때, 화면에 보이는 시간 범위 15(9시~24시)을 반환한다`() = runTest { + val t1 = dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(28)))) // given + + val range1 = t1.formatTimeRange() + + assertEquals(range1, 15) + + val t2= dummyTimetables.copy(timetable = listOf(dummyTimetableLecture.copy(classTime = listOf(29)))) // given + + val range2 = t2.formatTimeRange() + + assertEquals(range2, 15) + } +} From 0219fe98595e04b4b6c8b5fb56919e71f2133928 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:25:59 +0900 Subject: [PATCH 014/138] =?UTF-8?q?[fix]=20Lecture=20=EC=BA=A1=EC=8A=90?= =?UTF-8?q?=ED=99=94=20=ED=95=A8=EC=88=98=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/timetable/response/Lecture.kt | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt index 18bfc5489..7f8654057 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt @@ -16,8 +16,25 @@ data class Lecture( val isEnglish: String = "", val designScore: String = "", val isElearning: String = "", - val classTime: List, + val classTime: List ) { + fun toTimetableLecture() = TimetableLecture( + id = id, + lectureId = 0, + regularNumber = regularNumber, + code = code, + designScore = designScore, + classTime = classTime, + classPlace = "", // Lecture에 없는데 어쩌자고? + memo = "", // Lecture에 없다고. + grades = grades, + classTitle = name, // 데이터 이름이 다른거냐 + lectureClass = lectureClass, + target = target, + professor = professor, + department = department + ) + fun findDayOfWeekAndTime(): Map> { return classTime.groupBy { it / 100 } .mapValues { entry -> @@ -77,17 +94,15 @@ data class Lecture( } } - fun doesMatchDepartmentSearchQuery(departments: List): Boolean { - val matchingCombination = department.toDepartmentString() + fun doesMatchDepartmentSearchQuery(query: String): Boolean { + val matchingCombination = query.toDepartmentString() - return departments.any { - it.contains(matchingCombination, ignoreCase = true) - } + return department.contains(matchingCombination, ignoreCase = true) } /** * 시간표 강의 중복 - * @example : 강의 시간 겹침 + 완전 준복 + * @example : 강의 시간 겹침 + 완전 중복 */ fun duplicate(lectures: List): Boolean { var flag = false @@ -100,18 +115,18 @@ data class Lecture( } } -fun String.toDepartmentString(): String = when(this) { +fun String.toDepartmentString(): String = when (this) { "HRD학과" -> "HRD" - "고용서비스정책학과" -> "고용서비스" + "고용서비스정책학과" -> "고용서비스정책학과" "교양학부" -> "교양" - "디자인ㆍ건축공학부" -> "디자인" - "메카트로닉스공학부" -> "메카트로닉스" - "산업경영학부" -> "산업경영" - "에너지신소재화학공학부" -> "에너지신소재" + "디자인ㆍ건축공학부" -> "디자인공학부" + "메카트로닉스공학부" -> "메카트로닉스공학부" + "산업경영학부" -> "산업경영학부" + "에너지신소재화학공학부" -> "에너지신소재공학부" "융합학과" -> "융합" "전기ㆍ전자ㆍ통신공학부" -> "전기" - "컴퓨터공학부" -> "컴퓨터" + "컴퓨터공학부" -> "컴퓨터공학부" "안전공학과" -> "안전" "기계공학부" -> "기계" else -> "" -} \ No newline at end of file +} From a1c7c99cf1b1dae283fd838448be4fe794d545d9 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:26:29 +0900 Subject: [PATCH 015/138] =?UTF-8?q?[add]=20TimetableEventTime=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/component/TimetableEventTime.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableEventTime.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableEventTime.kt index c49535e15..49a58053a 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableEventTime.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableEventTime.kt @@ -40,12 +40,12 @@ fun TimetableEventTime( when (eventType) { TimetableEventType.BASIC -> TimetableBasicEventTime( event = event, - modifier = modifier, + modifier = modifier.padding((0.5).dp), onEventTimeClick = onEventTimeClick ) TimetableEventType.SELECTED -> TimetableSelectedEventTime( - modifier = modifier + modifier = modifier.padding(start = (0.5).dp , top = (0.5).dp, end = (0.6).dp, bottom = (0.65).dp) ) } } @@ -59,10 +59,10 @@ private fun TimetableBasicEventTime( Column( modifier = modifier .fillMaxSize() - .background(color = event.color) + .background(color = event.color.content) .clickable { onEventTimeClick(event) } ) { - HorizontalDivider(color = KoinTheme.colors.neutral800, thickness = 2.dp) + HorizontalDivider(color = event.color.header, thickness = 2.dp) Spacer(modifier = Modifier.height(2.dp)) Text( text = event.name, From 98b6b1e060a34dc9101eb3b3fca197680f80b8ad Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:27:57 +0900 Subject: [PATCH 016/138] =?UTF-8?q?[add]=20TimetableColor=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EB=8D=94=EB=AF=B8=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/model/TimetableConstants.kt | 32 ++++++++++++------- .../feature/timetable/model/TimetableEvent.kt | 7 +++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt index 48674cfe6..de206eaab 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt @@ -2,6 +2,8 @@ package `in`.koreatech.koin.feature.timetable.model import androidx.compose.ui.graphics.Color import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture import java.time.DayOfWeek import java.time.LocalTime @@ -13,7 +15,7 @@ object TimetableConstants { val dummyEvent = TimetableEvent( id = 1, name = "강의 제목", - color = Color(0xFFAFBBF2), + color = TimetableColor(Color(0xFF890000),Color(0x33890000)), dayOfWeek = DayOfWeek.FRIDAY, start = LocalTime.of(16, 0), end = LocalTime.of(18, 0), @@ -41,16 +43,22 @@ val dummyLecture = Lecture( ) ) +val dummySemester = Semester(id = 1, semester = "20242") + val defaultColors = listOf( - Color(0xfffdbcf5), - Color(0xfffdbcf5), - Color(0xfffedb8f), - Color(0xffc2eead), - Color(0xffffb588), - Color(0xffffa9b7), - Color(0xff8ae9ff), - Color(0xff60e4c1), - Color(0xffb4bfff), - Color(0xff72b0ff), - Color(0xffe0e5eb) + TimetableColor(Color(0xFF890000),Color(0x33890000)), + TimetableColor(Color(0xFFFF4444),Color(0x33FF4444)), + TimetableColor(Color(0xFFFF993B),Color(0x33FF993B)), + TimetableColor(Color(0xFFE8D52A),Color(0x33E8D52A)), + TimetableColor(Color(0xFFD0AE00),Color(0x33D0AE00)), + TimetableColor(Color(0xFF513A00),Color(0x33513A00)), + TimetableColor(Color(0xFF0C9D61),Color(0x330C9D61)), + TimetableColor(Color(0xFF7ABA78),Color(0x337ABA78)), + TimetableColor(Color(0xFF366718),Color(0x33366718)), + TimetableColor(Color(0xFF80C4E9),Color(0x3380C4E9)), + TimetableColor(Color(0xFF1679AB),Color(0x331679AB)), + TimetableColor(Color(0xFF074173),Color(0x33074173)), + TimetableColor(Color(0xFF523AE2),Color(0x33523AE2)), + TimetableColor(Color(0xFF6F6F6F),Color(0x336F6F6F)), + TimetableColor(Color(0xFFCBCBCB),Color(0x33CBCBCB)), ) \ No newline at end of file diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt index 81ba5817c..07809556d 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt @@ -17,10 +17,15 @@ enum class DayOfWeekKorean( SUNDAY("일") } +data class TimetableColor( + val header: Color, + val content: Color +) + data class TimetableEvent( val id: Int, val name: String, - val color: Color, + val color: TimetableColor, val dayOfWeek: DayOfWeek? = null, val start: LocalTime, val end: LocalTime, From 9fd56c5d5a2ea9da4813eae8782c7c81454dd47b Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:29:36 +0900 Subject: [PATCH 017/138] =?UTF-8?q?[fix]=20=ED=99=95=EC=9E=A5=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/utils/Extensions.kt | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt index de97b7a05..741fedcb6 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt @@ -2,10 +2,43 @@ package `in`.koreatech.koin.feature.timetable.utils import androidx.compose.ui.graphics.Color import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import `in`.koreatech.koin.feature.timetable.model.TimetableColor import `in`.koreatech.koin.feature.timetable.model.TimetableEvent +import `in`.koreatech.koin.feature.timetable.model.defaultColors import java.time.LocalTime -fun Lecture.toTimetableEvents(index: Int? = null, colors: List): List { +fun TimetableLectures.getTimetableEvents() = timetable.flatMapIndexed { index, timetableLecture -> timetableLecture.toTimetableEvents(index) } + +fun TimetableLecture.toTimetableEvents(index: Int): List { + val events = mutableListOf() + /** + * @input : {MONDAY=[09:00, 09:30], TUESDAY=[09:00, 09:30]} + */ + findDayOfWeekAndTime().forEach { (key, value) -> + val timetableEvent = TimetableEvent( + id = id, + name = classTitle, + color = defaultColors[index % defaultColors.size], + dayOfWeek = key, + start = value.firstOrNull() ?: LocalTime.of(0, 0), + end = value.lastOrNull()?.plusMinutes(30) ?: LocalTime.of(0, 0), + description = professor + ) + events.add(timetableEvent) + } + /** + * @output : + * [ + * TimetableEvent(0, "강의이름1", 색상1, MONDAY, 09:00, 09:30, null), + * TimetableEvent(0, "강의이름2", 색상2, TUESDAY, 09:00, 09:30, null), + * ] + */ + return events +} + +fun Lecture.toTimetableEvents(): List { val events = mutableListOf() /** * @input : {MONDAY=[09:00, 09:30], TUESDAY=[09:00, 09:30]} @@ -14,11 +47,11 @@ fun Lecture.toTimetableEvents(index: Int? = null, colors: List): List Date: Sat, 2 Nov 2024 23:29:52 +0900 Subject: [PATCH 018/138] =?UTF-8?q?[fix]=20Department=20=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=EA=B7=B8=EB=9E=A8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/view/dialog/SelectDepartmentDialog.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/dialog/SelectDepartmentDialog.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/dialog/SelectDepartmentDialog.kt index 6d7e53255..b2a4e9e78 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/dialog/SelectDepartmentDialog.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/dialog/SelectDepartmentDialog.kt @@ -32,12 +32,13 @@ import `in`.koreatech.koin.feature.timetable.component.FilledTextButton @OptIn(ExperimentalMaterial3Api::class) @Composable fun SelectDepartmentDialog( + department: String, departments: List, onConfirm: (String) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier ) { - var selectedDepartment by remember { mutableStateOf("") } + var selectedDepartment by remember { mutableStateOf(department) } BasicAlertDialog( modifier = modifier, @@ -120,6 +121,7 @@ fun DepartmentRadioButtons( private fun SelectDepartmentDialogPreview() { KoinTheme { SelectDepartmentDialog( + department = "", departments = listOf( "건축공학부", "고용서비스정책학과", From 5d403ccefd728ddb0d6170edaf4a143b28a9dcda Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:33:06 +0900 Subject: [PATCH 019/138] =?UTF-8?q?[fix]=20=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/feature/timetable/view/Timetable.kt | 28 ++++++++----------- .../timetable/view/TimetableBottomSheet.kt | 10 ++++--- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt index 665e355f9..52d148942 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt @@ -30,7 +30,7 @@ fun Timetable( (event: TimetableEvent, eventType: TimetableEventType, onEventTimeClick: (TimetableEvent) -> Unit) -> Unit = { event, eventType, onEventTimeClick -> TimetableEventTime( event = event, - modifier = Modifier.padding(bottom = (1.5).dp), + modifier = Modifier, eventType = eventType, onEventTimeClick = onEventTimeClick ) @@ -39,23 +39,17 @@ fun Timetable( ) { val verticalScrollState: ScrollState = rememberScrollState() - Column( + TimetableContent( modifier = modifier - .background(Color.White), - horizontalAlignment = Alignment.CenterHorizontally - ) { - TimetableContent( - modifier = Modifier - .verticalScroll(verticalScrollState) - .padding(vertical = 14.dp), - range = range, - horizontalPadding = 48.dp, - events = events, - clickEvent = clickEvent, - content = content, - onEventClick = onEventClick - ) - } + .verticalScroll(verticalScrollState) + .padding(vertical = 14.dp), + range = range, + horizontalPadding = 48.dp, + events = events, + clickEvent = clickEvent, + content = content, + onEventClick = onEventClick + ) } diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt index 95948a1d8..80612b321 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt @@ -28,14 +28,15 @@ fun TimetableBottomSheet( lectures: List, modifier: Modifier = Modifier, selectedLecture: Lecture? = null, - colors: List = defaultColors, + timetableEvents: List = emptyList(), onClickAddCustomLectureMode: () -> Unit = {}, onClickAddLectureMode: () -> Unit = {}, onComplete: () -> Unit = {}, onClickSettingIcon: () -> Unit = {}, onClickSearchIcon: () -> Unit = {}, onSearchTextChange: (text: String) -> Unit = {}, - onClickAddLecture: () -> Unit = {}, + onClickAddLecture: (lecture: Lecture) -> Unit = {}, + onClickRemoveLecture: (lecture: Lecture) -> Unit = {}, onClickLecture: (events: List) -> Unit = {}, onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onBottomSheetHeightChange: (height: Float) -> Unit = {}, @@ -72,12 +73,13 @@ fun TimetableBottomSheet( items(lectures.size) { LectureBox( position = it, - colors = colors, lecture = lectures[it], selectedLecture = selectedLecture, + timetableEvents = timetableEvents, onClickLecture = onClickLecture, onSelectedLecture = onSelectedLecture, - onClickAddLecture = onClickAddLecture + onClickAddLecture = onClickAddLecture, + onClickRemoveLecture = onClickRemoveLecture ) HorizontalDivider(thickness = 1.dp, color = KoinTheme.colors.neutral300) } From 6b9d4f8bc66bc55dc563279c2c9933b816837d4b Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sat, 2 Nov 2024 23:33:26 +0900 Subject: [PATCH 020/138] =?UTF-8?q?[add]=20=EB=A1=9C=EB=94=A9=20=EB=B0=94?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20TimetableScreen=20=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/component/CircleLoadingBar.kt | 43 +++++++++++++++ .../feature/timetable/view/TimetableScreen.kt | 55 +++++++++++++++---- 2 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/CircleLoadingBar.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/CircleLoadingBar.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/CircleLoadingBar.kt new file mode 100644 index 000000000..783e8170a --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/CircleLoadingBar.kt @@ -0,0 +1,43 @@ +package `in`.koreatech.koin.feature.timetable.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.width +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme + +@Composable +fun CircleLoadingBar( + loading: Boolean, + modifier: Modifier = Modifier +) { + if (loading.not()) return + + Box( + modifier = modifier + .background(Color(0x80FFFFFF)) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.width(64.dp), + color = KoinTheme.colors.primary500, + trackColor = Color.LightGray + ) + } +} + +@Preview +@Composable +private fun CircleLoadingBarPreview() { + KoinTheme { + CircleLoadingBar(loading = true) + } +} \ No newline at end of file diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt index 421dea016..8334c7499 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt @@ -2,6 +2,7 @@ package `in`.koreatech.koin.feature.timetable.view import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -9,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.material.BottomSheetScaffold import androidx.compose.material.BottomSheetScaffoldState import androidx.compose.material.BottomSheetState @@ -16,6 +18,7 @@ import androidx.compose.material.BottomSheetValue import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material.rememberBottomSheetState +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -28,22 +31,39 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.util.pxToDp +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.feature.timetable.component.CircleLoadingBar import `in`.koreatech.koin.feature.timetable.component.TimetableDownloadBox import `in`.koreatech.koin.feature.timetable.component.TimetableScheduleBox -import `in`.koreatech.koin.feature.timetable.model.dummyEvent +import `in`.koreatech.koin.feature.timetable.model.TimetableEvent import `in`.koreatech.koin.feature.timetable.model.dummyLecture +import `in`.koreatech.koin.feature.timetable.model.dummySemester import kotlinx.coroutines.launch @OptIn(ExperimentalMaterialApi::class) @Composable fun TimetableScreen( + loading: Boolean, + range: Int, + lectures: List, + semesters: List, + selectedLecture: Lecture?, searchText: String, sheetState: BottomSheetState, scaffoldState: BottomSheetScaffoldState, modifier: Modifier = Modifier, + timetableEvents: List = emptyList(), + clickedTimetableEvents: List = emptyList(), onSearchTextChange: (text: String) -> Unit = {}, onClickTimetableSchedule: () -> Unit = {}, - onClickDownloadTimetable: () -> Unit = {} + onClickDownloadTimetable: () -> Unit = {}, + onClickAddLecture: (lecture: Lecture) -> Unit = {}, + onClickRemoveLecture: (lecture: Lecture) -> Unit = {}, + onClickLecture: (timetableEvents: List) -> Unit = {}, + onSelectedLecture: (lecture: Lecture?) -> Unit = {}, + onClickSettingIcon: () -> Unit = {}, + onClickSearchIcon: () -> Unit = {} ) { var bottomSheetHeight by remember { mutableStateOf(0f) } val scope = rememberCoroutineScope() @@ -53,17 +73,19 @@ fun TimetableScreen( scaffoldState = scaffoldState, sheetContent = { TimetableBottomSheet( - lectures = listOf(dummyLecture), - selectedLecture = dummyLecture, + lectures = lectures, + selectedLecture = selectedLecture, searchText = searchText, + timetableEvents = timetableEvents, onClickAddLectureMode = {}, onComplete = { scope.launch { sheetState.collapse() } }, - onClickSettingIcon = {}, - onClickSearchIcon = {}, + onClickSettingIcon = onClickSettingIcon, + onClickSearchIcon = onClickSearchIcon, onSearchTextChange = onSearchTextChange, - onClickAddLecture = {}, - onClickLecture = {}, - onSelectedLecture = {}, + onClickAddLecture = onClickAddLecture, + onClickRemoveLecture = onClickRemoveLecture, + onClickLecture = onClickLecture, + onSelectedLecture = onSelectedLecture, onBottomSheetHeightChange = { bottomSheetHeight = it }, ) }, @@ -88,14 +110,18 @@ fun TimetableScreen( TimetableDownloadBox(onClick = onClickDownloadTimetable) } Timetable( - range = 15, - events = listOf(dummyEvent) + range = range, + modifier = Modifier, + events = timetableEvents, + clickEvent = clickedTimetableEvents ) } + CircleLoadingBar(loading = loading) } - } + + @OptIn(ExperimentalMaterialApi::class) private fun Modifier.dynamicPadding( sheetState: BottomSheetState, @@ -121,6 +147,11 @@ private fun Modifier.dynamicPadding( @Composable private fun TimetableScreenPreview() { TimetableScreen( + loading = false, + range = 9, + lectures = listOf(dummyLecture), + semesters = listOf(dummySemester), + selectedLecture = null, searchText = "", sheetState = rememberBottomSheetState( initialValue = BottomSheetValue.Collapsed From cdfc447a85d2d8366001fad621be2f57857c0946 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:15:18 +0900 Subject: [PATCH 021/138] =?UTF-8?q?[add]=20UseCase=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/usecase/timetable/GetLecturesUseCase.kt | 13 +++++++++++++ .../domain/usecase/timetable/GetSemesterUseCase.kt | 13 +++++++++++++ .../usecase/timetable/GetTimetableFramesUseCase.kt | 13 +++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetLecturesUseCase.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetTimetableFramesUseCase.kt diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetLecturesUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetLecturesUseCase.kt new file mode 100644 index 000000000..df0ba2f11 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetLecturesUseCase.kt @@ -0,0 +1,13 @@ +package `in`.koreatech.koin.domain.usecase.timetable + +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.repository.TimetableRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetLecturesUseCase @Inject constructor( + private val timetableRepository: TimetableRepository +) { + operator fun invoke(semesterDate: String): Flow> = + timetableRepository.getLectures(semesterDate) +} \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt new file mode 100644 index 000000000..4ce254259 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt @@ -0,0 +1,13 @@ +package `in`.koreatech.koin.domain.usecase.timetable + +import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.domain.repository.TimetableRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetSemesterUseCase @Inject constructor( + private val timetableRepository: TimetableRepository +) { + operator fun invoke(): Flow> = + timetableRepository.getSemesters() +} \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetTimetableFramesUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetTimetableFramesUseCase.kt new file mode 100644 index 000000000..13c05337c --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetTimetableFramesUseCase.kt @@ -0,0 +1,13 @@ +package `in`.koreatech.koin.domain.usecase.timetable + +import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame +import `in`.koreatech.koin.domain.repository.TimetableRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetTimetableFramesUseCase @Inject constructor( + private val timetableRepository: TimetableRepository +) { + suspend operator fun invoke(semester: String): Flow> = + timetableRepository.getTimetableFrames(semester) +} \ No newline at end of file From a3f4bdf8fa7ffcf9a758c98d6f9c66ce5e168718 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:15:38 +0900 Subject: [PATCH 022/138] =?UTF-8?q?[fix]=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EC=88=98=EC=A0=95=EC=9C=BC=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/koin/feature/timetable/TimetableEventTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableEventTest.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableEventTest.kt index b6aa4a345..da0087442 100644 --- a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableEventTest.kt +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableEventTest.kt @@ -1,6 +1,7 @@ package `in`.koreatech.koin.feature.timetable import androidx.compose.ui.graphics.Color +import `in`.koreatech.koin.feature.timetable.model.TimetableColor import `in`.koreatech.koin.feature.timetable.model.TimetableEvent import org.junit.Assert.assertEquals import org.junit.Test @@ -11,7 +12,7 @@ class TimetableEventTest { val sampleEvent = TimetableEvent( // given id = 1, name = "강의 제목", - color = Color(0xFFAFBBF2), + color = TimetableColor(Color(0xFFAFBBF2),Color(0xFFAFBBF2)), dayOfWeek = DayOfWeek.FRIDAY, start = LocalTime.of(9, 30), end = LocalTime.of(10, 30), From ae837e11d353f4efd535db626bebdc1859b5f4cd Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:15:53 +0900 Subject: [PATCH 023/138] =?UTF-8?q?[add]=20=EB=B7=B0=20=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/viewmodel/TimetableViewModel.kt | 304 +++++++++++++++++- .../timetable/FakeTimetableRepository.kt | 75 +++++ .../feature/timetable/MainCoroutineRule.kt | 36 +++ .../koin/feature/timetable/SampleTimetable.kt | 15 + .../timetable/TimetableViewModelTest.kt | 107 ++++++ 5 files changed, 535 insertions(+), 2 deletions(-) create mode 100644 feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt create mode 100644 feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/MainCoroutineRule.kt create mode 100644 feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/SampleTimetable.kt create mode 100644 feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt index 1db33c423..56b255993 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt @@ -1,5 +1,305 @@ package `in`.koreatech.koin.feature.timetable.viewmodel -class TimetableViewModel { +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import `in`.koreatech.koin.domain.repository.TimetableRepository +import `in`.koreatech.koin.domain.usecase.timetable.GetLecturesUseCase +import `in`.koreatech.koin.domain.usecase.timetable.GetSemesterUseCase +import `in`.koreatech.koin.domain.usecase.timetable.GetTimetableFramesUseCase +import `in`.koreatech.koin.feature.timetable.model.TimetableEvent +import `in`.koreatech.koin.feature.timetable.utils.getTimetableEvents +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject -} \ No newline at end of file +@HiltViewModel +class TimetableViewModel @Inject constructor( + private val getLecturesUseCase: GetLecturesUseCase, + private val getSemesterUseCase: GetSemesterUseCase, + private val getTimetableFramesUseCase: GetTimetableFramesUseCase, + private val timetableRepository: TimetableRepository +) : ViewModel() { + private val _uiState = MutableStateFlow(TimetableUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _searchText = MutableStateFlow("") + val searchText = _searchText.asStateFlow() + + private val _department = MutableStateFlow("") + val department = _department.asStateFlow() + + private val _lectures = MutableStateFlow>(emptyList()) + val lectures = searchText + .combine(_department) { text, department -> + SearchEngineState(text, department) + } + .combine(_lectures) { searchEngineState, lectures -> + searchEngineState to lectures + }.map { (searchEngineState, lectures) -> + if (searchEngineState.text.isBlank() && searchEngineState.department.isBlank()) { + lectures + } else if (searchEngineState.department.isBlank()) { + lectures.filter { lecture -> + lecture.doesMatchSearchQuery(searchEngineState.text) + } + } else { + lectures.filter { lecture -> + lecture.doesMatchDepartmentSearchQuery(searchEngineState.department) && (searchEngineState.text.isBlank() || lecture.doesMatchSearchQuery( + searchEngineState.text + )) + } + } + }.stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(5_000), + emptyList() + ) + + + fun getUser(isAnonymous: Boolean) { + _uiState.value = _uiState.value.copy(isAnonymous = isAnonymous) + } + + fun getInitData() { + viewModelScope.launch { + _uiState.value = _uiState.value.copy(loading = true) + val semesters = getSemester() + val semester = semesters.firstOrNull()?.semester.orEmpty() + val lectures = getLectures(semester) + _lectures.value = lectures + + when (_uiState.value.isAnonymous) { + true -> { + timetableRepository.getTimetableLectures(semester) + .onSuccess { timetableLectures -> + _uiState.value = _uiState.value.copy( + range = timetableLectures.formatTimeRange(), + semesters = semesters, + timetableEvents = timetableLectures.getTimetableEvents(), + currentSemester = semester, + timetableLectures = timetableLectures, + loading = false + ) + }.onFailure { + _uiState.value = _uiState.value.copy( + loading = false + ) + Timber.e("getTimetableLectures Local Error Message : ${it.message}") + } + } + + false -> { + // TODO : 로그인 시 시간표 수업 불러오기 + val timetableFrames = getTimetableFrames(semester) + timetableRepository.getTimetableLectures(timetableFrames.firstOrNull()?.id ?: 0) + .onSuccess { timetableLectures -> + _uiState.value = _uiState.value.copy( + range = timetableLectures.formatTimeRange(), + semesters = semesters, + timetableEvents = timetableLectures.getTimetableEvents(), + currentSemester = semester, + timetableLectures = timetableLectures, + loading = false + ) + }.onFailure { + _uiState.value = _uiState.value.copy( + loading = false + ) + Timber.e("getTimetableLectures Remote Error Message : ${it.message}") + } + } + } + + + } + } + + private suspend fun getSemester(): List { + return getSemesterUseCase().catch { + Timber.e("getSemester Error Message : ${it.message}") + }.firstOrNull().orEmpty() + } + + private suspend fun getLectures(semester: String): List { + return getLecturesUseCase(semester).catch { + Timber.e("Get Lectures Error Message : ${it.message}") + }.firstOrNull().orEmpty() + } + + private suspend fun getTimetableFrames(semester: String): List { + return getTimetableFramesUseCase(semester).catch { + Timber.e("Get TimetableFrames Error Message : ${it.message}") + }.firstOrNull().orEmpty() + } + + fun updateSearchText(text: String) { + _searchText.value = text + } + + fun updateDepartment(text: String) { + _department.value = text + _uiState.value = _uiState.value.copy( + isSelectDepartmentDialogVisible = false + ) + } + + fun updateClickedTimetableEvents(timetableEvents: List) { + _uiState.value = _uiState.value.copy( + clickedTimetableEvents = timetableEvents + ) + } + + fun updateSelectedLecture(lecture: Lecture?) { + _uiState.value = _uiState.value.copy( + selectedLecture = lecture + ) + } + + fun updateIsSelectDepartmentDialogVisible() { + _uiState.value = _uiState.value.copy( + isSelectDepartmentDialogVisible = !_uiState.value.isSelectDepartmentDialogVisible + ) + } + + fun updateIsLectureDuplicationDialogVisible() { + _uiState.value = _uiState.value.copy( + isLectureDuplicationDialogVisible = false + ) + } + + fun updateTimetableLectures(lecture: Lecture) { + when (isDuplicateClassTime(lecture)) { + true -> { + _uiState.value = _uiState.value.copy( + duplicationLecture = lecture, + isLectureDuplicationDialogVisible = true + ) + } + + false -> { + when (_uiState.value.isAnonymous) { + true -> { + addTimetableLectures(lecture) + } + false -> { + // TODO : 로그인 시 강의 추가 (중복 X) + } + } + } + } + } + + + fun updateDuplicationTimetableLecture() { + val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() + + _uiState.value.duplicationLecture?.classTime?.forEach { time -> + _uiState.value.timetableLectures.timetable.filter { it.classTime.contains(time) } + .forEach { lecture -> + updatedTimetableLectures.remove(lecture) + } + } + + _uiState.value.duplicationLecture?.toTimetableLecture()?.let { timetableLecture -> + updatedTimetableLectures.add(timetableLecture) + } + + val timetables = _uiState.value.timetableLectures.copy( + timetable = updatedTimetableLectures + ) + + when(_uiState.value.isAnonymous) { + true -> { + postTimetableLectures(timetables) + } + false -> { + // TODO : 로그인 시 중복에 대한 강의 업데이트 + } + } + } + + fun addTimetableLectures(lecture: Lecture) { + val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() + updatedTimetableLectures.add(lecture.toTimetableLecture()) + val timetables = _uiState.value.timetableLectures.copy( + timetable = updatedTimetableLectures + ) + + postTimetableLectures(timetables) + } + + fun removeTimetableLectures(lecture: Lecture) { + val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() + updatedTimetableLectures.remove(lecture.toTimetableLecture()) + val timetables = _uiState.value.timetableLectures.copy( + timetable = updatedTimetableLectures + ) + + postTimetableLectures(timetables) + } + + private fun postTimetableLectures(timetables: TimetableLectures) { + viewModelScope.launch { + timetableRepository.putTimetableLectures(_uiState.value.currentSemester, timetables) + .onSuccess { timetableLectures -> + _uiState.value = _uiState.value.copy( + range = timetableLectures.formatTimeRange(), + timetableLectures = timetableLectures, + timetableEvents = timetableLectures.getTimetableEvents(), + clickedTimetableEvents = emptyList(), + isLectureDuplicationDialogVisible = false, + selectedLecture = null, + ) + }.onFailure { + _uiState.value = _uiState.value.copy( + isLectureDuplicationDialogVisible = false, + loading = false + ) + Timber.e("putTimetableLectures Local Error Message : ${it.message}") + } + } + } + + private fun isDuplicateClassTime(lecture: Lecture): Boolean { + lecture.classTime.forEach { time -> + _uiState.value.timetableLectures.timetable.forEach { timetableLecture -> + if (timetableLecture.classTime.any { it == time }) return true + } + } + return false + } +} + +data class SearchEngineState( + val text: String, + val department: String +) + +data class TimetableUiState( + val range: Int = 9, + val duplicationLecture: Lecture? = null, + val semesters: List = emptyList(), + val currentSemester: String = "", + val timetableEvents: List = emptyList(), + val clickedTimetableEvents: List = emptyList(), + val selectedLecture: Lecture? = null, + val timetableLectures: TimetableLectures = TimetableLectures(0, emptyList(), 0, 0), + val loading: Boolean = false, + val isLectureDuplicationDialogVisible: Boolean = false, + val isSelectDepartmentDialogVisible: Boolean = false, + val isAnonymous: Boolean = true, +) diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt new file mode 100644 index 000000000..744c31b4d --- /dev/null +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt @@ -0,0 +1,75 @@ +package `in`.koreatech.koin.feature.timetable + +import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import `in`.koreatech.koin.domain.repository.TimetableRepository +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + + + +class FakeTimetableRepository() : TimetableRepository { + override fun getSemesters(): Flow> = flow { + delay(400) + emit(listOf(SampleTimetable.semester)) + } + + override fun getLectures(semesterDate: String): Flow> = flow { + delay(600) + emit(listOf(SampleTimetable.lecture)) + } + + override fun getTimetableFrames(semester: String): Flow> { + TODO("Not yet implemented") + } + + override suspend fun getTimetableLectures(timetableFrameId: Int): Result { + TODO("Not yet implemented") + } + + override suspend fun getTimetableLectures(semester: String): Result { + TODO("Not yet implemented") + } + + override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { + TODO("Not yet implemented") + } + + override suspend fun putTimetableLectures( + key: String, + value: TimetableLectures + ): Result { + TODO("Not yet implemented") + } + + override suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame { + TODO("Not yet implemented") + } + + override suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { + TODO("Not yet implemented") + } + + override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame { + TODO("Not yet implemented") + } + + override suspend fun deleteTimetableFrame() { + TODO("Not yet implemented") + } + + override suspend fun deleteTimetableLecture(id: Int) { + TODO("Not yet implemented") + } + + override suspend fun deleteAllTimetableFrame() { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/MainCoroutineRule.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/MainCoroutineRule.kt new file mode 100644 index 000000000..8541e31dd --- /dev/null +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/MainCoroutineRule.kt @@ -0,0 +1,36 @@ +package `in`.koreatech.koin.feature.timetable + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestCoroutineScheduler +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +class MainCoroutineRule: TestWatcher() { + lateinit var scheduler: TestCoroutineScheduler + private set + lateinit var dispatcher: TestDispatcher + private set + + override fun starting(description: Description) { + scheduler = TestCoroutineScheduler() + dispatcher = StandardTestDispatcher(scheduler) + Dispatchers.setMain(dispatcher) + } + + override fun finished(description: Description) { + Dispatchers.resetMain() + } +} + +/** + * @example how to use + * + * class MainViewModelTests { + * @get:Rule + * var mainCoroutineRule = MainCoroutineRule() + * } + */ \ No newline at end of file diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/SampleTimetable.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/SampleTimetable.kt new file mode 100644 index 000000000..beb862e14 --- /dev/null +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/SampleTimetable.kt @@ -0,0 +1,15 @@ +package `in`.koreatech.koin.feature.timetable + +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.Semester + +object SampleTimetable { + val semester = Semester(id = 1, semester = "20242") + + val lecture = Lecture( + id = 1, code = "HRD011", name = "직업능력개발훈련평가", + professor = "우성민", grades = "2", lectureClass = "01", regularNumber = "40", + department = "HRD학과", target = "전기3", isEnglish = "", isElearning = "", + designScore = "0", classTime = listOf(310, 311, 312, 313) + ) +} \ No newline at end of file diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt new file mode 100644 index 000000000..8eba7ef65 --- /dev/null +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt @@ -0,0 +1,107 @@ +package `in`.koreatech.koin.feature.timetable + +import app.cash.turbine.test +import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import `in`.koreatech.koin.domain.repository.TimetableRepository +import `in`.koreatech.koin.domain.usecase.timetable.GetLecturesUseCase +import `in`.koreatech.koin.domain.usecase.timetable.GetSemesterUseCase +import `in`.koreatech.koin.domain.usecase.timetable.GetTimetableFramesUseCase +import `in`.koreatech.koin.feature.timetable.viewmodel.TimetableViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.flatMapConcat +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.currentTime +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runTest +import okhttp3.Dispatcher +import org.junit.After +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import retrofit2.http.GET + +/** + * 뷰모델, 유즈케이스, 레포지토리 테스트 연습해보기 + * 추가로 플로우 테스트도 진행해보기 + */ + +class TimetableViewModelTest { + @get: Rule + var mainCoroutineRule = MainCoroutineRule() + + private lateinit var viewModel: TimetableViewModel + private lateinit var timetableRepository: TimetableRepository + private lateinit var getLectureUseCase: GetLecturesUseCase + private lateinit var getSemesterUseCase: GetSemesterUseCase + private lateinit var getTimetableFrameUseCase: GetTimetableFramesUseCase + + @Before + fun setUp() { + timetableRepository = FakeTimetableRepository() + getLectureUseCase = GetLecturesUseCase(timetableRepository) + getSemesterUseCase = GetSemesterUseCase(timetableRepository) + getTimetableFrameUseCase = GetTimetableFramesUseCase(timetableRepository) + + viewModel = TimetableViewModel( + getLecturesUseCase = getLectureUseCase, + getSemesterUseCase = getSemesterUseCase, + getTimetableFramesUseCase = getTimetableFrameUseCase, + timetableRepository = timetableRepository + ) + } + + @Test + fun `학기(semester) 받아오는 플로우`() = runTest { + getSemesterUseCase().test { + advanceTimeBy(400) + assertEquals(currentTime, 400) + assertEquals(awaitItem(), listOf(SampleTimetable.semester)) + awaitComplete() + } + } + + @Test + fun `수업(lecture) 받아오는 플로우`() = runTest { + getLectureUseCase("20242").test { + advanceTimeBy(600) + assertEquals(currentTime, 600) + assertEquals(awaitItem(), listOf(SampleTimetable.lecture)) + awaitComplete() + } + } + + + @Test + fun `학기(semester), 수업(lecture)을 순서대로 받아오는 플로우`() = runTest { + val semesters = getSemesterUseCase().firstOrNull().orEmpty() + val semester = semesters.firstOrNull()?.semester.orEmpty() + val lecture = getLectureUseCase(semester).firstOrNull().orEmpty() + + advanceUntilIdle() + assertEquals(currentTime, 1000) + assertEquals(lecture, SampleTimetable.lecture) + // 샘플 코드를 싱글톤을 사용해서 다른 곳에 있는데 이게 실질적으로 맞는가? + // 위와 같은 질문을 한 이유는? 여기에다가 직접적으로 넣어서 테스트 해보는 것이 더 직관적일 것 같다는 생각이 든다. + } + + @Test + fun `뷰모델 테스트하기`() = runTest { + // 뷰모델은 어떻게 테스트 하는가? + } +} \ No newline at end of file From 64e9eff2cfaa136d627c7a2b4814d00ba57fb85b Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:16:12 +0900 Subject: [PATCH 024/138] =?UTF-8?q?[add]=20LectureBox=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/component/LectureBox.kt | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt index befd8258c..aa6587e22 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt @@ -1,7 +1,6 @@ package `in`.koreatech.koin.feature.timetable.component import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -32,19 +31,21 @@ import `in`.koreatech.koin.feature.timetable.utils.toTimetableEvents @Composable fun LectureBox( position: Int, - colors: List, lecture: Lecture, selectedLecture: Lecture?, modifier: Modifier = Modifier, - onClickAddLecture: () -> Unit = {}, + timetableEvents: List = emptyList(), + onClickAddLecture: (lecture: Lecture) -> Unit = {}, + onClickRemoveLecture: (lecture: Lecture) -> Unit = {}, onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onClickLecture: (timetableEvents: List) -> Unit = {}, ) { val isSelected = selectedLecture == lecture + val isAdded = timetableEvents.any { lecture.id == it.id } + val events = lecture.toTimetableEvents() // val isSelected by remember(lecture, selectedLecture) { // derivedStateOf { selectedLecture == lecture } // } - val events = lecture.toTimetableEvents(colors = colors) Row( modifier = modifier @@ -52,10 +53,11 @@ fun LectureBox( .selectable( selected = isSelected, onClick = { - onClickLecture(events) if (isSelected) { + onClickLecture(emptyList()) onSelectedLecture(null) } else { + onClickLecture(events) onSelectedLecture(lecture) } } @@ -110,11 +112,13 @@ fun LectureBox( Spacer(modifier = Modifier.height(4.dp)) } - IconButton(onClick = onClickAddLecture) { + IconButton(onClick = { + if (isAdded) onClickRemoveLecture(lecture) else onClickAddLecture(lecture) + }) { StableIcon( - drawableResId = R.drawable.ic_plus, - tint = KoinTheme.colors.primary500, - modifier = Modifier.size(24.dp) + drawableResId = if (isAdded) R.drawable.ic_minus else R.drawable.ic_plus, + tint = if (isAdded) KoinTheme.colors.danger700 else KoinTheme.colors.primary500, + modifier = Modifier.size(if (isAdded) 20.dp else 24.dp) ) } } @@ -126,7 +130,6 @@ private fun LectureBoxPreview() { KoinTheme { LectureBox( position = 1, - colors = listOf(Color.Blue), lecture = dummyLecture.copy( classTime = listOf(310, 311, 312, 313, 410, 411, 412, 413) ), @@ -135,13 +138,25 @@ private fun LectureBoxPreview() { } } +@Preview +@Composable +private fun LectureBoxPreview_Added() { + KoinTheme { + LectureBox( + position = 2, + lecture = dummyLecture, + timetableEvents = dummyLecture.toTimetableEvents(), + selectedLecture = dummyLecture, + ) + } +} + @Preview @Composable private fun LectureBoxPreview_Selected() { KoinTheme { LectureBox( position = 2, - colors = listOf(Color.Blue), lecture = dummyLecture, selectedLecture = dummyLecture, ) From 4c9529285af56a747225fde059254ffde1f603af Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:16:37 +0900 Subject: [PATCH 025/138] =?UTF-8?q?[add]=20TimetableActivity=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/ui/timetablev2/TimetableActivity.kt | 68 ++++++++++++++++--- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt index 239558d96..eaca77a98 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt @@ -1,21 +1,22 @@ package `in`.koreatech.koin.ui.timetablev2 import android.os.Bundle +import androidx.activity.viewModels import androidx.compose.material.BottomSheetValue import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.MaterialTheme import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material.rememberBottomSheetState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.koin.core.appbar.AppBarBase import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.core.util.KeyboardUtils import `in`.koreatech.koin.databinding.ActivityTimetableBinding import `in`.koreatech.koin.feature.timetable.view.TimetableScreen +import `in`.koreatech.koin.feature.timetable.view.dialog.LectureDuplicationDialog +import `in`.koreatech.koin.feature.timetable.view.dialog.SelectDepartmentDialog +import `in`.koreatech.koin.feature.timetable.viewmodel.TimetableViewModel import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerActivity import `in`.koreatech.koin.ui.navigation.state.MenuState import kotlinx.coroutines.launch @@ -27,7 +28,7 @@ class TimetableActivity : KoinNavigationDrawerActivity() { get() = MenuState.Timetable private lateinit var binding: ActivityTimetableBinding - + private val viewModel: TimetableViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -38,13 +39,20 @@ class TimetableActivity : KoinNavigationDrawerActivity() { } private fun initView() { + getUserExtra { isAnonymous -> + viewModel.getUser(isAnonymous) + } + viewModel.getInitData() initComposeView() } @OptIn(ExperimentalMaterialApi::class) private fun initComposeView() { binding.composeView.setContent { - var searchText by remember { mutableStateOf("") } + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val lectures by viewModel.lectures.collectAsStateWithLifecycle() + val searchText by viewModel.searchText.collectAsStateWithLifecycle() + val department by viewModel.department.collectAsStateWithLifecycle() val sheetState = rememberBottomSheetState( initialValue = BottomSheetValue.Collapsed @@ -55,6 +63,7 @@ class TimetableActivity : KoinNavigationDrawerActivity() { val scope = rememberCoroutineScope() hideKeyboard(sheetState.isCollapsed) + setAppbarEvent { scope.launch { if (sheetState.isExpanded) { @@ -66,13 +75,52 @@ class TimetableActivity : KoinNavigationDrawerActivity() { } KoinTheme { + if (uiState.isLectureDuplicationDialogVisible) { + LectureDuplicationDialog( + onConfirm = viewModel::updateDuplicationTimetableLecture, + onDismiss = viewModel::updateIsLectureDuplicationDialogVisible + ) + } + + if (uiState.isSelectDepartmentDialogVisible) { + SelectDepartmentDialog( + department = department, + departments = listOf( + "건축공학부", + "고용서비스정책학과", + "기계공학부", + "디자인공학부", + "메카트로닉스공학부", + "산업경영학부", + "전기전자통신공학부", + "컴퓨터공학부", + "화학생명공학부", + ), + onConfirm = viewModel::updateDepartment, + onDismiss = viewModel::updateIsSelectDepartmentDialogVisible + ) + } + TimetableScreen( + loading = uiState.loading, + range = uiState.range, + lectures = lectures, + semesters = uiState.semesters, + selectedLecture = uiState.selectedLecture, + timetableEvents = uiState.timetableEvents, + clickedTimetableEvents = uiState.clickedTimetableEvents, searchText = searchText, sheetState = sheetState, scaffoldState = scaffoldState, - onSearchTextChange = { searchText = it }, + onSearchTextChange = viewModel::updateSearchText, onClickTimetableSchedule = {}, // TODO : 학기 시간표 선택 - onClickDownloadTimetable = {} // TODO : 시간표 다운로드 + onClickDownloadTimetable = {}, // TODO : 시간표 다운로드 + onClickAddLecture = viewModel::updateTimetableLectures, + onClickRemoveLecture = viewModel::removeTimetableLectures, + onClickLecture = viewModel::updateClickedTimetableEvents, + onSelectedLecture = viewModel::updateSelectedLecture, + onClickSettingIcon = viewModel::updateIsSelectDepartmentDialogVisible, + onClickSearchIcon = {}, // TODO : 검색 아이콘 클릭 (필요할까? 그냥 보여주기용이 좋아보임) ) } } @@ -82,6 +130,10 @@ class TimetableActivity : KoinNavigationDrawerActivity() { setAppbarEvent() } + private fun getUserExtra(callback: (isAnonymous: Boolean) -> Unit) { + callback(intent.getBooleanExtra("isAnonymous", true)) + } + private fun setAppbarEvent(rightButtonClickable: () -> Unit = {}) { binding.koinBaseAppbar.setOnClickListener { when (it.id) { From 1427a0fee929d348fb8a13de9a7914c7b8b83630 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:24:56 +0900 Subject: [PATCH 026/138] =?UTF-8?q?[fix]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/feature/timetable/TimetableViewModelTest.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt index 8eba7ef65..ce5525093 100644 --- a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt @@ -93,9 +93,8 @@ class TimetableViewModelTest { val semester = semesters.firstOrNull()?.semester.orEmpty() val lecture = getLectureUseCase(semester).firstOrNull().orEmpty() - advanceUntilIdle() assertEquals(currentTime, 1000) - assertEquals(lecture, SampleTimetable.lecture) + assertEquals(lecture, listOf(SampleTimetable.lecture)) // 샘플 코드를 싱글톤을 사용해서 다른 곳에 있는데 이게 실질적으로 맞는가? // 위와 같은 질문을 한 이유는? 여기에다가 직접적으로 넣어서 테스트 해보는 것이 더 직관적일 것 같다는 생각이 든다. } From 0abe047b0ff94d58c364bd99a0356cd217caf882 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 00:35:46 +0900 Subject: [PATCH 027/138] =?UTF-8?q?[fix]=20derivedStateOf=20=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/component/LectureBox.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt index aa6587e22..4d23cc652 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt @@ -14,6 +14,9 @@ import androidx.compose.foundation.selection.selectable import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -40,12 +43,15 @@ fun LectureBox( onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onClickLecture: (timetableEvents: List) -> Unit = {}, ) { - val isSelected = selectedLecture == lecture - val isAdded = timetableEvents.any { lecture.id == it.id } +// val isSelected = selectedLecture == lecture +// val isAdded = timetableEvents.any { lecture.id == it.id } val events = lecture.toTimetableEvents() -// val isSelected by remember(lecture, selectedLecture) { -// derivedStateOf { selectedLecture == lecture } -// } + val isSelected by remember(lecture, selectedLecture) { + derivedStateOf { selectedLecture == lecture } + } + val isAdded by remember(lecture, timetableEvents) { + derivedStateOf { timetableEvents.any {lecture.id == it.id} } + } Row( modifier = modifier From b7c42e00b36af479f9a36ba37479a2494708ab64 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 23:30:42 +0900 Subject: [PATCH 028/138] =?UTF-8?q?[add]=20=EC=B6=94=EA=B0=80=EB=90=9C=20?= =?UTF-8?q?=EA=B0=95=EC=9D=98=20=EC=B6=94=EA=B0=80=20=ED=81=B4=EB=A6=AD=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=EB=84=88=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/feature/timetable/view/TimetableScreen.kt | 6 ++++-- .../in/koreatech/koin/ui/timetablev2/TimetableActivity.kt | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt index 8334c7499..080c4f16f 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt @@ -63,7 +63,8 @@ fun TimetableScreen( onClickLecture: (timetableEvents: List) -> Unit = {}, onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onClickSettingIcon: () -> Unit = {}, - onClickSearchIcon: () -> Unit = {} + onClickSearchIcon: () -> Unit = {}, + onClickTimetableEvent: (event: TimetableEvent) -> Unit = {} ) { var bottomSheetHeight by remember { mutableStateOf(0f) } val scope = rememberCoroutineScope() @@ -113,7 +114,8 @@ fun TimetableScreen( range = range, modifier = Modifier, events = timetableEvents, - clickEvent = clickedTimetableEvents + clickEvent = clickedTimetableEvents, + onEventClick = onClickTimetableEvent ) } CircleLoadingBar(loading = loading) diff --git a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt index eaca77a98..99bd04da3 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt @@ -121,6 +121,7 @@ class TimetableActivity : KoinNavigationDrawerActivity() { onSelectedLecture = viewModel::updateSelectedLecture, onClickSettingIcon = viewModel::updateIsSelectDepartmentDialogVisible, onClickSearchIcon = {}, // TODO : 검색 아이콘 클릭 (필요할까? 그냥 보여주기용이 좋아보임) + onClickTimetableEvent = {}, // TODO : 추가된 시간표 클릭 후 이벤트 (id 파싱해서 삭제하면 됨) ) } } From 142b9b97a7f81085cefa9122ae6ddf5b83da7e09 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 23:30:53 +0900 Subject: [PATCH 029/138] =?UTF-8?q?[add]=20lectureId=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/feature/timetable/model/TimetableConstants.kt | 1 + .../in/koreatech/koin/feature/timetable/model/TimetableEvent.kt | 1 + .../in/koreatech/koin/feature/timetable/utils/Extensions.kt | 2 ++ 3 files changed, 4 insertions(+) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt index de206eaab..ac52d909c 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt @@ -14,6 +14,7 @@ object TimetableConstants { val dummyEvent = TimetableEvent( id = 1, + lectureId = 1, name = "강의 제목", color = TimetableColor(Color(0xFF890000),Color(0x33890000)), dayOfWeek = DayOfWeek.FRIDAY, diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt index 07809556d..e52ee272c 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableEvent.kt @@ -24,6 +24,7 @@ data class TimetableColor( data class TimetableEvent( val id: Int, + val lectureId: Int, val name: String, val color: TimetableColor, val dayOfWeek: DayOfWeek? = null, diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt index 741fedcb6..ef1495a6c 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/utils/Extensions.kt @@ -19,6 +19,7 @@ fun TimetableLecture.toTimetableEvents(index: Int): List { findDayOfWeekAndTime().forEach { (key, value) -> val timetableEvent = TimetableEvent( id = id, + lectureId = lectureId, name = classTitle, color = defaultColors[index % defaultColors.size], dayOfWeek = key, @@ -46,6 +47,7 @@ fun Lecture.toTimetableEvents(): List { findDayOfWeekAndTime().forEach { (key, value) -> val timetableEvent = TimetableEvent( id = id, + lectureId = 1, // 상관 없음 name = name, color = TimetableColor(Color(0xFFFFFF), Color(0xFFFFFF)), dayOfWeek = key, From 93bb138f39f0100253b3a603e8c3a4cd66ec3789 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 23:47:48 +0900 Subject: [PATCH 030/138] =?UTF-8?q?[add]=20GET=20Frame=20API=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/api/auth/TimetableAuthApi.kt | 2 +- .../timetable/viewmodel/TimetableViewModel.kt | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt index 5fd2dabd9..048244dff 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt @@ -43,7 +43,7 @@ interface TimetableAuthApi { @DELETE("/v2/timetables/frame") suspend fun deleteTimetableFrame() - @GET("/v2/timetables/frame") + @GET("/v2/timetables/frames") suspend fun getTimetableFrames( @Query("semester") semester: String ): List diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt index 56b255993..97f7d2ae9 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt @@ -104,8 +104,17 @@ class TimetableViewModel @Inject constructor( false -> { // TODO : 로그인 시 시간표 수업 불러오기 - val timetableFrames = getTimetableFrames(semester) - timetableRepository.getTimetableLectures(timetableFrames.firstOrNull()?.id ?: 0) + val timetableFrames = getTimetableFrames(semester).ifEmpty { + _uiState.value = _uiState.value.copy(loading = false) + return@launch + } + val frameId = timetableFrames.find { it.isMain }?.id + if (frameId == null) { + _uiState.value = _uiState.value.copy(loading = false) + return@launch + } + + timetableRepository.getTimetableLectures(frameId) .onSuccess { timetableLectures -> _uiState.value = _uiState.value.copy( range = timetableLectures.formatTimeRange(), From 014aa0c748e5d2b03e4228bd210cc3e4e41b6b28 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Sun, 3 Nov 2024 23:50:13 +0900 Subject: [PATCH 031/138] =?UTF-8?q?[add]=20=EB=B9=88=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=9B=EB=8D=94=EB=9D=BC=EB=8F=84=20=ED=95=99?= =?UTF-8?q?=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/viewmodel/TimetableViewModel.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt index 97f7d2ae9..47d8116c5 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt @@ -105,12 +105,19 @@ class TimetableViewModel @Inject constructor( false -> { // TODO : 로그인 시 시간표 수업 불러오기 val timetableFrames = getTimetableFrames(semester).ifEmpty { - _uiState.value = _uiState.value.copy(loading = false) + _uiState.value = _uiState.value.copy( + semesters = semesters, + currentSemester = semester, + loading = false + ) return@launch } val frameId = timetableFrames.find { it.isMain }?.id if (frameId == null) { - _uiState.value = _uiState.value.copy(loading = false) + _uiState.value = _uiState.value.copy( + semesters = semesters, + currentSemester = semester, loading = false + ) return@launch } @@ -204,6 +211,7 @@ class TimetableViewModel @Inject constructor( true -> { addTimetableLectures(lecture) } + false -> { // TODO : 로그인 시 강의 추가 (중복 X) } @@ -231,10 +239,11 @@ class TimetableViewModel @Inject constructor( timetable = updatedTimetableLectures ) - when(_uiState.value.isAnonymous) { + when (_uiState.value.isAnonymous) { true -> { postTimetableLectures(timetables) } + false -> { // TODO : 로그인 시 중복에 대한 강의 업데이트 } From 95c72c3ef2979e6fde32e569cc197a3e07314e5c Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 01:01:08 +0900 Subject: [PATCH 032/138] =?UTF-8?q?[fix]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A3=BC=EC=84=9D=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/FakeTimetableRepository.kt | 119 +++++++++-------- .../timetable/TimetableViewModelTest.kt | 126 +++++++++--------- 2 files changed, 123 insertions(+), 122 deletions(-) diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt index 744c31b4d..f7149ad33 100644 --- a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/FakeTimetableRepository.kt @@ -1,5 +1,6 @@ package `in`.koreatech.koin.feature.timetable +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery @@ -14,62 +15,62 @@ import kotlinx.coroutines.flow.flow -class FakeTimetableRepository() : TimetableRepository { - override fun getSemesters(): Flow> = flow { - delay(400) - emit(listOf(SampleTimetable.semester)) - } - - override fun getLectures(semesterDate: String): Flow> = flow { - delay(600) - emit(listOf(SampleTimetable.lecture)) - } - - override fun getTimetableFrames(semester: String): Flow> { - TODO("Not yet implemented") - } - - override suspend fun getTimetableLectures(timetableFrameId: Int): Result { - TODO("Not yet implemented") - } - - override suspend fun getTimetableLectures(semester: String): Result { - TODO("Not yet implemented") - } - - override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { - TODO("Not yet implemented") - } - - override suspend fun putTimetableLectures( - key: String, - value: TimetableLectures - ): Result { - TODO("Not yet implemented") - } - - override suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame { - TODO("Not yet implemented") - } - - override suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { - TODO("Not yet implemented") - } - - override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame { - TODO("Not yet implemented") - } - - override suspend fun deleteTimetableFrame() { - TODO("Not yet implemented") - } - - override suspend fun deleteTimetableLecture(id: Int) { - TODO("Not yet implemented") - } - - override suspend fun deleteAllTimetableFrame() { - TODO("Not yet implemented") - } - -} \ No newline at end of file +//class FakeTimetableRepository() : TimetableRepository { +// override fun getSemesters(): Flow> = flow { +// delay(400) +// emit(listOf(SampleTimetable.semester)) +// } +// +// override fun getLectures(semesterDate: String): Flow> = flow { +// delay(600) +// emit(listOf(SampleTimetable.lecture)) +// } +// +// override fun getTimetableFrames(semester: String): Flow> { +// TODO("Not yet implemented") +// } +// +// override suspend fun getTimetableLectures(timetableFrameId: Int): Result { +// TODO("Not yet implemented") +// } +// +// override suspend fun getTimetableLectures(semester: String): Result { +// TODO("Not yet implemented") +// } +// +// override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { +// TODO("Not yet implemented") +// } +// +// override suspend fun putTimetableLectures( +// key: String, +// value: TimetableLectures +// ): Result { +// TODO("Not yet implemented") +// } +// +// override suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame { +// TODO("Not yet implemented") +// } +// +// override suspend fun postTimetableLectures(lectures: LecturesQuery): Result { +// TODO("Not yet implemented") +// } +// +// override suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame { +// TODO("Not yet implemented") +// } +// +// override suspend fun deleteTimetableFrame() { +// TODO("Not yet implemented") +// } +// +// override suspend fun deleteTimetableLecture(id: Int) { +// TODO("Not yet implemented") +// } +// +// override suspend fun deleteAllTimetableFrame() { +// TODO("Not yet implemented") +// } +// +//} \ No newline at end of file diff --git a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt index ce5525093..e1ab1f485 100644 --- a/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt +++ b/feature/timetable/src/test/java/in/koreatech/koin/feature/timetable/TimetableViewModelTest.kt @@ -41,66 +41,66 @@ import retrofit2.http.GET * 추가로 플로우 테스트도 진행해보기 */ -class TimetableViewModelTest { - @get: Rule - var mainCoroutineRule = MainCoroutineRule() - - private lateinit var viewModel: TimetableViewModel - private lateinit var timetableRepository: TimetableRepository - private lateinit var getLectureUseCase: GetLecturesUseCase - private lateinit var getSemesterUseCase: GetSemesterUseCase - private lateinit var getTimetableFrameUseCase: GetTimetableFramesUseCase - - @Before - fun setUp() { - timetableRepository = FakeTimetableRepository() - getLectureUseCase = GetLecturesUseCase(timetableRepository) - getSemesterUseCase = GetSemesterUseCase(timetableRepository) - getTimetableFrameUseCase = GetTimetableFramesUseCase(timetableRepository) - - viewModel = TimetableViewModel( - getLecturesUseCase = getLectureUseCase, - getSemesterUseCase = getSemesterUseCase, - getTimetableFramesUseCase = getTimetableFrameUseCase, - timetableRepository = timetableRepository - ) - } - - @Test - fun `학기(semester) 받아오는 플로우`() = runTest { - getSemesterUseCase().test { - advanceTimeBy(400) - assertEquals(currentTime, 400) - assertEquals(awaitItem(), listOf(SampleTimetable.semester)) - awaitComplete() - } - } - - @Test - fun `수업(lecture) 받아오는 플로우`() = runTest { - getLectureUseCase("20242").test { - advanceTimeBy(600) - assertEquals(currentTime, 600) - assertEquals(awaitItem(), listOf(SampleTimetable.lecture)) - awaitComplete() - } - } - - - @Test - fun `학기(semester), 수업(lecture)을 순서대로 받아오는 플로우`() = runTest { - val semesters = getSemesterUseCase().firstOrNull().orEmpty() - val semester = semesters.firstOrNull()?.semester.orEmpty() - val lecture = getLectureUseCase(semester).firstOrNull().orEmpty() - - assertEquals(currentTime, 1000) - assertEquals(lecture, listOf(SampleTimetable.lecture)) - // 샘플 코드를 싱글톤을 사용해서 다른 곳에 있는데 이게 실질적으로 맞는가? - // 위와 같은 질문을 한 이유는? 여기에다가 직접적으로 넣어서 테스트 해보는 것이 더 직관적일 것 같다는 생각이 든다. - } - - @Test - fun `뷰모델 테스트하기`() = runTest { - // 뷰모델은 어떻게 테스트 하는가? - } -} \ No newline at end of file +//class TimetableViewModelTest { +// @get: Rule +// var mainCoroutineRule = MainCoroutineRule() +// +// private lateinit var viewModel: TimetableViewModel +// private lateinit var timetableRepository: TimetableRepository +// private lateinit var getLectureUseCase: GetLecturesUseCase +// private lateinit var getSemesterUseCase: GetSemesterUseCase +// private lateinit var getTimetableFrameUseCase: GetTimetableFramesUseCase +// +// @Before +// fun setUp() { +// timetableRepository = FakeTimetableRepository() +// getLectureUseCase = GetLecturesUseCase(timetableRepository) +// getSemesterUseCase = GetSemesterUseCase(timetableRepository) +// getTimetableFrameUseCase = GetTimetableFramesUseCase(timetableRepository) +// +// viewModel = TimetableViewModel( +// getLecturesUseCase = getLectureUseCase, +// getSemesterUseCase = getSemesterUseCase, +// getTimetableFramesUseCase = getTimetableFrameUseCase, +// timetableRepository = timetableRepository +// ) +// } +// +// @Test +// fun `학기(semester) 받아오는 플로우`() = runTest { +// getSemesterUseCase().test { +// advanceTimeBy(400) +// assertEquals(currentTime, 400) +// assertEquals(awaitItem(), listOf(SampleTimetable.semester)) +// awaitComplete() +// } +// } +// +// @Test +// fun `수업(lecture) 받아오는 플로우`() = runTest { +// getLectureUseCase("20242").test { +// advanceTimeBy(600) +// assertEquals(currentTime, 600) +// assertEquals(awaitItem(), listOf(SampleTimetable.lecture)) +// awaitComplete() +// } +// } +// +// +// @Test +// fun `학기(semester), 수업(lecture)을 순서대로 받아오는 플로우`() = runTest { +// val semesters = getSemesterUseCase().firstOrNull().orEmpty() +// val semester = semesters.firstOrNull()?.semester.orEmpty() +// val lecture = getLectureUseCase(semester).firstOrNull().orEmpty() +// +// assertEquals(currentTime, 1000) +// assertEquals(lecture, listOf(SampleTimetable.lecture)) +// // 샘플 코드를 싱글톤을 사용해서 다른 곳에 있는데 이게 실질적으로 맞는가? +// // 위와 같은 질문을 한 이유는? 여기에다가 직접적으로 넣어서 테스트 해보는 것이 더 직관적일 것 같다는 생각이 든다. +// } +// +// @Test +// fun `뷰모델 테스트하기`() = runTest { +// // 뷰모델은 어떻게 테스트 하는가? +// } +//} \ No newline at end of file From d59c827f5de34efe703f7f5f97d42a8ede339e9b Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Mon, 4 Nov 2024 23:14:13 +0900 Subject: [PATCH 033/138] =?UTF-8?q?fix:=20=EA=B0=95=EC=97=85=20api=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/source/remote/VersionRemoteDataSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/VersionRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/VersionRemoteDataSource.kt index 625e3b605..4ae3a28bf 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/VersionRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/VersionRemoteDataSource.kt @@ -14,6 +14,6 @@ class VersionRemoteDataSource @Inject constructor( } suspend fun getOwnerAppVersion(): VersionResponse { - return versionApi.getVersion("android") + return versionApi.getVersion("android_owner") } } \ No newline at end of file From 5e5b37b82c7db618c39116f339a81fb45b4f4f31 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Mon, 4 Nov 2024 23:15:18 +0900 Subject: [PATCH 034/138] =?UTF-8?q?fix:=20=EC=88=AB=EC=9E=90=EB=A7=8C=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=8A=94=20=EC=88=AB=EC=9E=90=EB=A7=8C=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PasswordAuthenticationScreen.kt | 4 +++ .../InsertDetailInfoScreen.kt | 25 ++++++++++++++++--- .../business/feature/signin/SignInScreen.kt | 3 +++ .../signup/accountsetup/AccountSetupScreen.kt | 4 +++ .../feature/store/OwnerStoreAppBar.kt | 10 +++----- .../store/modifyinfo/ModifyInfoScreen.kt | 17 ++++++++++--- .../modifymenu/modifymenu/ModifyMenuScreen.kt | 6 ++++- .../registermenu/RegisterMenuScreen.kt | 6 ++++- .../feature/textfield/BorderTextField.kt | 3 +++ .../feature/textfield/LinedTextField.kt | 4 +++ 10 files changed, 65 insertions(+), 17 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt b/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt index f0c4a5185..03990e86b 100644 --- a/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.ButtonDefaults.buttonColors @@ -30,6 +31,7 @@ import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -194,6 +196,7 @@ fun PasswordAuthenticationScreen( }, isSuccess = accountState == ChangePasswordContinuationState.SendAuthCode, successText = stringResource(R.string.success_send_sms_code), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) Text( @@ -214,6 +217,7 @@ fun PasswordAuthenticationScreen( label = stringResource(R.string.input_auth_code), errorText = stringResource(R.string.auth_code_not_equal), isError = authState is ChangePasswordContinuationState.Failed, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) Spacer(modifier = Modifier.width(8.dp)) Button( diff --git a/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/InsertDetailInfoScreen.kt b/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/InsertDetailInfoScreen.kt index f48d03b96..3a40d38bf 100644 --- a/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/InsertDetailInfoScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/insertstore/insertdetailinfo/InsertDetailInfoScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Text @@ -33,6 +34,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -169,11 +171,23 @@ fun InsertDetailInfoScreenImpl( } item { - NameTextField(stringResource(id = R.string.calling_number), storePhoneNumber, onStorePhoneNumberChange, 32.dp) + NameTextField( + stringResource(id = R.string.calling_number), + storePhoneNumber, + onStorePhoneNumberChange, + 32.dp, + KeyboardOptions(keyboardType = KeyboardType.Number) + ) } item { - NameTextField(stringResource(id = R.string.delivery_fee), storeDeliveryFee, onStoreDeliveryFeeChange, 24.dp) + NameTextField( + stringResource(id = R.string.delivery_fee), + storeDeliveryFee, + onStoreDeliveryFeeChange, + 24.dp, + KeyboardOptions(keyboardType = KeyboardType.Number) + ) } item { @@ -287,7 +301,8 @@ fun NameTextField( textString: String = "", inputString: String = "", onStringChange: (String) -> Unit = {}, - paddingTopValue: Dp = 10.dp + paddingTopValue: Dp = 10.dp, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default ){ Row( modifier = Modifier @@ -303,7 +318,7 @@ fun NameTextField( fontWeight = FontWeight.Bold ) - BorderTextField(inputString, onStringChange) + BorderTextField(inputString, onStringChange, keyboardOptions) } } @@ -331,6 +346,7 @@ private fun HandleSideEffects(viewModel: InsertDetailInfoScreenViewModel, naviga fun BorderTextField( inputString: String = "", onStringChange: (String) -> Unit = {}, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default ){ Box( modifier = Modifier @@ -342,6 +358,7 @@ fun BorderTextField( BasicTextField( value = inputString, onValueChange = onStringChange, + keyboardOptions = keyboardOptions, textStyle = TextStyle( color = Color.Black, fontSize = 14.sp diff --git a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt index 4341dcb5a..179b885ee 100644 --- a/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signin/SignInScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Divider @@ -28,6 +29,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -108,6 +110,7 @@ fun SignInScreenImpl( onValueChange = onIdChange, maxLines = 1, textStyle = TextStyle(fontSize = 15.sp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), decorationBox = { innerTextField -> Column( modifier = Modifier diff --git a/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt b/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt index f6ce1f4ea..9d6c4e398 100644 --- a/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults @@ -30,6 +31,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight.Companion.Bold +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -173,6 +175,7 @@ fun AccountSetupScreen( successText = stringResource(R.string.success_send_sms_code), isError = state.sendCodeError != null, isSuccess = state.phoneNumberState == SignupContinuationState.RequestedSmsValidation, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) Button(modifier = Modifier @@ -222,6 +225,7 @@ fun AccountSetupScreen( successText = stringResource(id = R.string.auth_code_equal), isError = state.verifyState is SignupContinuationState.Failed, isSuccess = state.verifyState == SignupContinuationState.CheckComplete, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) Button( diff --git a/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt b/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt index 3b5d22408..b64ea0966 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -14,6 +15,7 @@ import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import `in`.koreatech.business.R import `in`.koreatech.business.ui.theme.ColorPrimary @@ -23,15 +25,9 @@ fun OwnerStoreAppBar(title: String) { Box( modifier = Modifier .fillMaxWidth() + .height(62.dp) .background(ColorPrimary), ) { - IconButton(onClick = { /*TODO*/ }) { - Image( - painter = painterResource(id = R.drawable.ic_back), - contentDescription = stringResource(R.string.back), - colorFilter = ColorFilter.tint(Color.White), - ) - } Text( text = title, modifier = Modifier.align(Alignment.Center), diff --git a/business/src/main/java/in/koreatech/business/feature/store/modifyinfo/ModifyInfoScreen.kt b/business/src/main/java/in/koreatech/business/feature/store/modifyinfo/ModifyInfoScreen.kt index 623b2022d..501d3245a 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/modifyinfo/ModifyInfoScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/modifyinfo/ModifyInfoScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.IconButton @@ -39,6 +40,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -92,6 +94,7 @@ fun ModifyInfoScreen( Box( modifier = Modifier .fillMaxWidth() + .height(62.dp) .background(ColorPrimary), ) { IconButton(onClick = viewModel::onBackButtonClicked) { @@ -181,8 +184,9 @@ fun ModifyInfoScreen( item { InputStoreInfo( info = stringResource(R.string.telephone_number), - data = state.storeInfo?.phone ?: "", - onValueChange = { viewModel.onPhoneNumberChanged(it) } + data = state.storeInfo?.phone?.replace("-", "") ?: "", + onValueChange = { viewModel.onPhoneNumberChanged(it) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) } item { @@ -253,7 +257,8 @@ fun ModifyInfoScreen( InputStoreInfo( info = stringResource(R.string.delivery_fee), data = state.storeInfo?.deliveryPrice?.toString() ?: "", - onValueChange = { viewModel.onDeliveryPriceChanged(it.toInt()) } + onValueChange = { viewModel.onDeliveryPriceChanged(it.toInt()) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) } @@ -340,7 +345,10 @@ fun ModifyInfoScreen( @Composable fun InputStoreInfo( - info: String, data: String, onValueChange: (String) -> Unit, + info: String, + data: String, + onValueChange: (String) -> Unit, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default ) { Row( modifier = Modifier @@ -371,6 +379,7 @@ fun InputStoreInfo( .fillMaxWidth(), value = data, onValueChange = onValueChange, + keyboardOptions = keyboardOptions, textStyle = TextStyle(color = Color.Black, fontSize = 15.sp) ) } diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/modifymenu/modifymenu/ModifyMenuScreen.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/modifymenu/modifymenu/ModifyMenuScreen.kt index 45ad2532f..6ffcf97a1 100644 --- a/business/src/main/java/in/koreatech/business/feature/storemenu/modifymenu/modifymenu/ModifyMenuScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/modifymenu/modifymenu/ModifyMenuScreen.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Divider @@ -50,6 +51,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -349,7 +351,8 @@ fun ModifyMenuScreenImpl( ), modifier = Modifier .padding(horizontal = 8.dp) - .fillMaxWidth() + .fillMaxWidth(), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) } } @@ -822,6 +825,7 @@ fun DetailMenuTextField( index = index, getStringResource = R.string.won, onStringChange = onChangeMenuPrice, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) Spacer(modifier = Modifier.weight(1f)) diff --git a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuScreen.kt b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuScreen.kt index 9c39f125f..9f7087b4b 100644 --- a/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/storemenu/registermenu/registermenu/RegisterMenuScreen.kt @@ -30,6 +30,7 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Divider @@ -52,6 +53,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -353,7 +355,8 @@ fun RegisterMenuScreenImpl( ), modifier = Modifier .padding(horizontal = 8.dp) - .fillMaxWidth() + .fillMaxWidth(), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) } } @@ -824,6 +827,7 @@ fun DetailMenuTextField( index = index, getStringResource = R.string.won, onStringChange = onChangeMenuPrice, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) ) Spacer(modifier = Modifier.weight(1f)) diff --git a/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt b/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt index f6e453d30..07b15a4a4 100644 --- a/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt +++ b/business/src/main/java/in/koreatech/business/feature/textfield/BorderTextField.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -29,6 +30,7 @@ fun MenuBorderTextField( index: Int = 0, getStringResource: Int = 0, onStringChange: (Pair) -> Unit = {}, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default ){ Box( modifier = modifier @@ -48,6 +50,7 @@ fun MenuBorderTextField( color = Color.Black, fontSize = 14.sp ), + keyboardOptions = keyboardOptions, decorationBox = { innerTextField -> if ( inputString == stringResource(id = R.string.temp_price)) { Text( diff --git a/business/src/main/java/in/koreatech/business/feature/textfield/LinedTextField.kt b/business/src/main/java/in/koreatech/business/feature/textfield/LinedTextField.kt index 7ca871163..45fc33a95 100644 --- a/business/src/main/java/in/koreatech/business/feature/textfield/LinedTextField.kt +++ b/business/src/main/java/in/koreatech/business/feature/textfield/LinedTextField.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -19,6 +20,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp @@ -42,6 +44,7 @@ fun LinedTextField( successText: String = "", isError: Boolean = false, isSuccess: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default ) { var focused by remember { mutableStateOf(false) } BasicTextField( @@ -50,6 +53,7 @@ fun LinedTextField( textStyle = textStyle, modifier = modifier.onFocusChanged { focused = it.isFocused }, maxLines = 1, + keyboardOptions = keyboardOptions, visualTransformation = if (isPassword) PasswordVisualTransformation() else VisualTransformation.None, decorationBox = { innerTextField -> Column(modifier = Modifier.fillMaxWidth()) { From 5327f3f5dff6dae48bf18e6fe5ab98bd0ee42b93 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 23:46:02 +0900 Subject: [PATCH 035/138] =?UTF-8?q?[add]=20api=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/api/auth/TimetableAuthApi.kt | 15 +++++- .../repository/TimetableRepositoryImpl.kt | 27 +++++++---- .../request/timetable/LecturesQueryRequest.kt | 46 +++++++++++++++++++ .../timetable/SemesterCheckResponse.kt | 16 +++++++ .../remote/TimetableRemoteDataSource.kt | 12 ++++- .../model/timetable/request/LecturesQuery.kt | 16 +++++++ .../model/timetable/response/Lecture.kt | 14 +++++- .../model/timetable/response/SemesterCheck.kt | 6 +++ .../domain/repository/TimetableRepository.kt | 11 +++-- 9 files changed, 147 insertions(+), 16 deletions(-) create mode 100644 data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt create mode 100644 data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterCheckResponse.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/SemesterCheck.kt diff --git a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt index 048244dff..3cb4171de 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt @@ -1,10 +1,14 @@ package `in`.koreatech.koin.data.api.auth +import `in`.koreatech.koin.data.request.timetable.LecturesQueryRequest import `in`.koreatech.koin.data.request.timetable.TimetableFrameCreateQueryRequest import `in`.koreatech.koin.data.request.timetable.TimetableFrameQueryRequest import `in`.koreatech.koin.data.request.timetable.TimetableLecturesQueryRequest +import `in`.koreatech.koin.data.response.timetable.SemesterCheckResponse import `in`.koreatech.koin.data.response.timetable.TimetableFrameResponse import `in`.koreatech.koin.data.response.timetable.TimetableLecturesResponse +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery +import retrofit2.Response import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.GET @@ -14,6 +18,9 @@ import retrofit2.http.Path import retrofit2.http.Query interface TimetableAuthApi { + @GET("/semesters/check") + suspend fun getSemestersCheck(): SemesterCheckResponse + @GET("/v2/timetables/lecture") suspend fun getTimetableLectures( @Query("timetable_frame_id") timetableFrameId: Int @@ -26,7 +33,7 @@ interface TimetableAuthApi { @POST("/v2/timetables/lecture") suspend fun postTimetableLectures( - @Body lectures: TimetableLecturesQueryRequest + @Body lectures: LecturesQueryRequest ): TimetableLecturesResponse @PUT("/v2/timetables/frame/{id}") @@ -53,6 +60,12 @@ interface TimetableAuthApi { @Path("id") id: Int ) + @DELETE("/v2/timetables/frame/{frameId}/lecture/{lectureId}") + suspend fun deleteTimetableFrameLecture( + @Path("frameId") frameId: Int, + @Path("lectureId") lectureId: Int + ): Response + @DELETE("/v2/all/timetables/frame") suspend fun deleteAllTimetableFrame() } \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt index 5299ce298..ceaea303c 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt @@ -2,21 +2,21 @@ package `in`.koreatech.koin.data.repository import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import `in`.koreatech.koin.data.request.timetable.toLecturesQueryRequest import `in`.koreatech.koin.data.request.timetable.toTimetableLecturesQueryRequest import `in`.koreatech.koin.data.source.datastore.TimetableDataStore import `in`.koreatech.koin.data.source.remote.TimetableRemoteDataSource +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery import `in`.koreatech.koin.domain.model.timetable.response.Lecture -import `in`.koreatech.koin.domain.model.timetable.response.Semester import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures import `in`.koreatech.koin.domain.repository.TimetableRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flow -import java.lang.NullPointerException import javax.inject.Inject class TimetableRepositoryImpl @Inject constructor( @@ -25,8 +25,12 @@ class TimetableRepositoryImpl @Inject constructor( ) : TimetableRepository { private val gson = Gson() - override fun getSemesters(): Flow> = flow { - emit(timetableRemoteDataSource.getSemesters().map { it.toSemester() }) + override fun getSemesters(): Flow> = flow { + emit(timetableRemoteDataSource.getSemesters().map { it.toSemester().semester }) + } + + override fun getSemesterCheck(): Flow> = flow { + emit(timetableRemoteDataSource.getSemesterCheck().toSemesterCheck().semesters) } override fun getLectures(semesterDate: String): Flow> = flow { @@ -52,8 +56,7 @@ class TimetableRepositoryImpl @Inject constructor( } override suspend fun putTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures = - timetableRemoteDataSource.postTimetableLectures(lectures.toTimetableLecturesQueryRequest()) - .toTimetableLectures() + timetableRemoteDataSource.putTimetableLectures(lectures.toTimetableLecturesQueryRequest()).toTimetableLectures() override suspend fun putTimetableLectures(key: String, value: TimetableLectures): Result = runCatching { timetableDataStore.putString(key, gson.toJson(value)) @@ -68,8 +71,8 @@ class TimetableRepositoryImpl @Inject constructor( TODO("Not yet implemented") } - override suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures { - TODO("Not yet implemented") + override suspend fun postTimetableLectures(lectures: LecturesQuery): Result = runCatching { + timetableRemoteDataSource.postTimetableLectures(lectures.toLecturesQueryRequest()).toTimetableLectures() } @@ -81,8 +84,12 @@ class TimetableRepositoryImpl @Inject constructor( TODO("Not yet implemented") } - override suspend fun deleteTimetableLecture(id: Int) { - TODO("Not yet implemented") + override suspend fun deleteTimetableLecture(id: Int): Result = runCatching { + timetableRemoteDataSource.deleteTimetableLecture(id) + } + + override suspend fun deleteTimetableFrameLecture(frameId: Int, lectureId: Int): Result = runCatching { + timetableRemoteDataSource.deleteTimetableFrameLecture(frameId, lectureId) } override suspend fun deleteAllTimetableFrame() { diff --git a/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt b/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt new file mode 100644 index 000000000..e069dea18 --- /dev/null +++ b/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt @@ -0,0 +1,46 @@ +package `in`.koreatech.koin.data.request.timetable + +import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.request.LectureQuery +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLectureQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery + +data class LecturesQueryRequest( + @SerializedName("timetable_frame_id") + val timetableFrameId: Int, + @SerializedName("timetable_lecture") + val timetableLecture: List, +) + +data class LectureQueryRequest( + @SerializedName("lecture_id") + val lectureId: Int?, + @SerializedName("class_title") + val classTitle: String, + @SerializedName("class_time") + val classTime: List, + @SerializedName("class_place") + val classPlace: String, + @SerializedName("professor") + val professor: String, + @SerializedName("grades") + val grades: String, + @SerializedName("memo") + val memo: String, +) + +fun LecturesQuery.toLecturesQueryRequest() = LecturesQueryRequest( + timetableFrameId = timetableFrameId, + timetableLecture = timetableLecture.map { it.toTLectureQueryRequest() } +) + +fun LectureQuery.toTLectureQueryRequest() = LectureQueryRequest( + lectureId = lectureId, + classTitle = classTitle, + classTime = classTime, + classPlace = classPlace, + professor = professor, + grades = grades, + memo = memo +) diff --git a/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterCheckResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterCheckResponse.kt new file mode 100644 index 000000000..0a71f3fde --- /dev/null +++ b/data/src/main/java/in/koreatech/koin/data/response/timetable/SemesterCheckResponse.kt @@ -0,0 +1,16 @@ +package `in`.koreatech.koin.data.response.timetable + +import com.google.gson.annotations.SerializedName +import `in`.koreatech.koin.domain.model.timetable.response.SemesterCheck + +data class SemesterCheckResponse( + @SerializedName("user_id") + val userId: Int, + @SerializedName("semesters") + val semesters: List, +) { + fun toSemesterCheck() = SemesterCheck( + userId = userId, + semesters = semesters + ) +} diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt index e9b7be9ca..dfb79db73 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt @@ -2,13 +2,16 @@ package `in`.koreatech.koin.data.source.remote import `in`.koreatech.koin.data.api.TimetableApi import `in`.koreatech.koin.data.api.auth.TimetableAuthApi +import `in`.koreatech.koin.data.request.timetable.LecturesQueryRequest import `in`.koreatech.koin.data.request.timetable.TimetableFrameCreateQueryRequest import `in`.koreatech.koin.data.request.timetable.TimetableFrameQueryRequest import `in`.koreatech.koin.data.request.timetable.TimetableLecturesQueryRequest import `in`.koreatech.koin.data.response.timetable.LectureResponse +import `in`.koreatech.koin.data.response.timetable.SemesterCheckResponse import `in`.koreatech.koin.data.response.timetable.SemesterResponse import `in`.koreatech.koin.data.response.timetable.TimetableFrameResponse import `in`.koreatech.koin.data.response.timetable.TimetableLecturesResponse +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import javax.inject.Inject class TimetableRemoteDataSource @Inject constructor( @@ -17,6 +20,8 @@ class TimetableRemoteDataSource @Inject constructor( ) { suspend fun getSemesters(): List = timetableApi.getSemesters() + suspend fun getSemesterCheck(): SemesterCheckResponse = timetableAuthApi.getSemestersCheck() + suspend fun getLectures(semesterDate: String): List = timetableApi.getLectures(semesterDate) @@ -36,7 +41,7 @@ class TimetableRemoteDataSource @Inject constructor( ): TimetableFrameResponse = timetableAuthApi.putTimetableFrame(id, frame) suspend fun postTimetableLectures( - lectures: TimetableLecturesQueryRequest + lectures: LecturesQueryRequest ): TimetableLecturesResponse = timetableAuthApi.postTimetableLectures(lectures) @@ -51,5 +56,10 @@ class TimetableRemoteDataSource @Inject constructor( id: Int ) = timetableAuthApi.deleteTimetableLecture(id) + suspend fun deleteTimetableFrameLecture( + frameId: Int, + lectureId: Int + ) = timetableAuthApi.deleteTimetableFrameLecture(frameId, lectureId) + suspend fun deleteAllTimetableFrame() = timetableAuthApi.deleteAllTimetableFrame() } \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt new file mode 100644 index 000000000..49f75d08d --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt @@ -0,0 +1,16 @@ +package `in`.koreatech.koin.domain.model.timetable.request + +data class LecturesQuery( + val timetableFrameId: Int, + val timetableLecture: List = emptyList(), +) + +data class LectureQuery( + val lectureId: Int?, + val classTitle: String = "", + val classTime: List, + val classPlace: String = "", + val professor: String = "", + val grades: String = "", + val memo: String = "", +) \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt index 7f8654057..dabbfeefb 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt @@ -1,5 +1,7 @@ package `in`.koreatech.koin.domain.model.timetable.response +import `in`.koreatech.koin.domain.model.timetable.request.LectureQuery +import `in`.koreatech.koin.domain.model.timetable.request.TimetableLectureQuery import java.time.DayOfWeek import java.time.LocalTime @@ -18,9 +20,19 @@ data class Lecture( val isElearning: String = "", val classTime: List ) { + fun toLectureQuery() = LectureQuery( + lectureId = id, + classTitle = name, + classTime =classTime, + classPlace = "", + professor = professor, + grades = grades, + memo = "" + ) + fun toTimetableLecture() = TimetableLecture( id = id, - lectureId = 0, + lectureId = id, regularNumber = regularNumber, code = code, designScore = designScore, diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/SemesterCheck.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/SemesterCheck.kt new file mode 100644 index 000000000..ab7e9d40a --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/SemesterCheck.kt @@ -0,0 +1,6 @@ +package `in`.koreatech.koin.domain.model.timetable.response + +data class SemesterCheck( + val userId: Int, + val semesters: List +) diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt index 9fcdc2342..a5d2382d9 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt @@ -1,16 +1,19 @@ package `in`.koreatech.koin.domain.repository +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery import `in`.koreatech.koin.domain.model.timetable.response.Lecture import `in`.koreatech.koin.domain.model.timetable.response.Semester +import `in`.koreatech.koin.domain.model.timetable.response.SemesterCheck import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures import kotlinx.coroutines.flow.Flow interface TimetableRepository { - fun getSemesters(): Flow> + fun getSemesters(): Flow> + fun getSemesterCheck(): Flow> fun getLectures(semesterDate: String): Flow> fun getTimetableFrames(semester: String): Flow> @@ -21,10 +24,12 @@ interface TimetableRepository { suspend fun putTimetableLectures(key: String, value: TimetableLectures): Result suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame - suspend fun postTimetableLectures(lectures: TimetableLecturesQuery): TimetableLectures + suspend fun postTimetableLectures(lectures: LecturesQuery): Result suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame suspend fun deleteTimetableFrame() - suspend fun deleteTimetableLecture(id: Int) + suspend fun deleteTimetableLecture(id: Int): Result + suspend fun deleteTimetableFrameLecture(frameId: Int, lectureId: Int): Result + suspend fun deleteAllTimetableFrame() } \ No newline at end of file From 8e8c91de1c5d6ec0cb35dbfc24236e6f59820db6 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 23:46:23 +0900 Subject: [PATCH 036/138] =?UTF-8?q?[add]=20=EC=8B=9C=EA=B0=84=ED=91=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=9C=A0=EC=A6=88=EC=BC=80=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/AddTimetableLectureUseCase.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt new file mode 100644 index 000000000..524a0b5d6 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt @@ -0,0 +1,19 @@ +package `in`.koreatech.koin.domain.usecase.timetable + +import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures +import `in`.koreatech.koin.domain.repository.TimetableRepository +import javax.inject.Inject + +class AddTimetableLectureUseCase @Inject constructor( + private val timetableRepository: TimetableRepository +) { + suspend operator fun invoke(frameId: Int, lectures: List): Result { + val query = LecturesQuery( + timetableFrameId = frameId, + timetableLecture = lectures.map { it.toLectureQuery() } + ) + return timetableRepository.postTimetableLectures(query) + } +} \ No newline at end of file From c8374a6c18c40eb4def4a3ea32e829ed7e9d41bf Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 23:46:41 +0900 Subject: [PATCH 037/138] =?UTF-8?q?[add]=20=EC=8B=9C=EA=B0=84=ED=91=9C=20?= =?UTF-8?q?=EC=A0=95=EA=B7=9C=20=EA=B0=95=EC=9D=98=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=9C=A0=EC=A6=88=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/DeleteTimetableFrameLectureUseCase.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableFrameLectureUseCase.kt diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableFrameLectureUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableFrameLectureUseCase.kt new file mode 100644 index 000000000..f6d137ae7 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableFrameLectureUseCase.kt @@ -0,0 +1,12 @@ +package `in`.koreatech.koin.domain.usecase.timetable + +import `in`.koreatech.koin.domain.repository.TimetableRepository +import javax.inject.Inject + +class DeleteTimetableFrameLectureUseCase @Inject constructor( + private val timetableRepository: TimetableRepository +) { + suspend operator fun invoke(frameId: Int, lectureId: Int): Result { + return timetableRepository.deleteTimetableFrameLecture(frameId, lectureId) + } +} \ No newline at end of file From b2c677b59a725f635ccb2a9a18824b7fa9fca298 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 23:47:06 +0900 Subject: [PATCH 038/138] =?UTF-8?q?[add]=20=EC=8B=9C=EA=B0=84=ED=91=9C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EA=B0=95=EC=9D=98=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=9C=A0=EC=A6=88=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/DeleteTimetableLectureUseCase.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableLectureUseCase.kt diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableLectureUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableLectureUseCase.kt new file mode 100644 index 000000000..d86091d2e --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/DeleteTimetableLectureUseCase.kt @@ -0,0 +1,12 @@ +package `in`.koreatech.koin.domain.usecase.timetable + +import `in`.koreatech.koin.domain.repository.TimetableRepository +import javax.inject.Inject + +class DeleteTimetableLectureUseCase @Inject constructor( + private val timetableRepository: TimetableRepository +) { + suspend operator fun invoke(id: Int): Result { + return timetableRepository.deleteTimetableLecture(id) + } +} \ No newline at end of file From ee56326d0505c383171393cd916127741579661b Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 23:47:26 +0900 Subject: [PATCH 039/138] =?UTF-8?q?[fix]=20=ED=95=99=EA=B8=B0=20=EC=9C=A0?= =?UTF-8?q?=EC=A6=88=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/domain/usecase/timetable/GetSemesterUseCase.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt index 4ce254259..a7d183a21 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/GetSemesterUseCase.kt @@ -1,6 +1,5 @@ package `in`.koreatech.koin.domain.usecase.timetable -import `in`.koreatech.koin.domain.model.timetable.response.Semester import `in`.koreatech.koin.domain.repository.TimetableRepository import kotlinx.coroutines.flow.Flow import javax.inject.Inject @@ -8,6 +7,6 @@ import javax.inject.Inject class GetSemesterUseCase @Inject constructor( private val timetableRepository: TimetableRepository ) { - operator fun invoke(): Flow> = - timetableRepository.getSemesters() + operator fun invoke(isAnonymous: Boolean): Flow> = + if (isAnonymous) timetableRepository.getSemesters() else timetableRepository.getSemesterCheck() } \ No newline at end of file From 4069e30d7b1c45ab15aa564649d8cb93355dc5f7 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Mon, 4 Nov 2024 23:47:52 +0900 Subject: [PATCH 040/138] =?UTF-8?q?[fix]=20lectureId=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/koin/feature/timetable/component/LectureBox.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt index 4d23cc652..d5bde12da 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/LectureBox.kt @@ -50,7 +50,7 @@ fun LectureBox( derivedStateOf { selectedLecture == lecture } } val isAdded by remember(lecture, timetableEvents) { - derivedStateOf { timetableEvents.any {lecture.id == it.id} } + derivedStateOf { timetableEvents.any {lecture.id == it.lectureId} } } Row( From 92563008b6ebf36f9448c968597f77845c8e812a Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 00:46:48 +0900 Subject: [PATCH 041/138] =?UTF-8?q?[add]=20TimeEditBox=20UI=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/component/TimeEditBox.kt | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimeEditBox.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimeEditBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimeEditBox.kt new file mode 100644 index 000000000..e377f6138 --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimeEditBox.kt @@ -0,0 +1,69 @@ +package `in`.koreatech.koin.feature.timetable.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.component.icon.StableIcon +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.timetable.R + +@Composable +fun TimeEditBox( + text: String, + modifier: Modifier = Modifier, + onClick: () -> Unit = {} +) { + Row( + modifier = modifier + .background(Color.White) + .border( + width = 1.dp, + color = KoinTheme.colors.neutral300, + shape = RoundedCornerShape(4.dp) + ) + .padding((5.5).dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = text, + style = KoinTheme.typography.bold12, + color = KoinTheme.colors.neutral800, + modifier = Modifier.padding(start = (3.5).dp) + ) + + IconButton( + onClick = onClick, + modifier = Modifier.size(24.dp) + ) { + StableIcon( + drawableResId = R.drawable.ic_arrow_down + ) + } + + } +} + +@Preview +@Composable +fun TimeEditBoxPreview() { + TimeEditBox("월요일") +} + +@Preview +@Composable +fun TimeEditBoxPreview_time() { + TimeEditBox("09:00") +} From 12f2b71bbe309068bb7b9b5bc9e732d3ce015f6b Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 00:50:10 +0900 Subject: [PATCH 042/138] =?UTF-8?q?[add]=20TimetableCustomAddBox=20UI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/TimetableCustomAddBox.kt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableCustomAddBox.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableCustomAddBox.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableCustomAddBox.kt new file mode 100644 index 000000000..24e53864b --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableCustomAddBox.kt @@ -0,0 +1,65 @@ +package `in`.koreatech.koin.feature.timetable.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.IconButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.component.icon.StableIcon +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.timetable.R + +@Composable +fun TimetableCustomAddBox( + modifier: Modifier = Modifier, + onClick: () -> Unit = {} +) { + Row( + modifier = modifier + .height(35.dp) + .fillMaxWidth() + .background(Color.White) + .border( + width = 1.dp, + color = KoinTheme.colors.neutral300, + shape = RoundedCornerShape(4.dp) + ) + .padding(top = 5.dp, bottom = 5.dp, start = 13.dp, end = 5.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(id = R.string.timetable_add_time_and_place), + style = KoinTheme.typography.bold12, + color = KoinTheme.colors.primary500 + ) + IconButton( + onClick = onClick, // TODO : 시간 및 장소 추가 클릭 처리 + modifier = Modifier.size(24.dp) + ) { + StableIcon( + drawableResId = R.drawable.ic_add, + tint = KoinTheme.colors.primary500 + ) + } + } +} + +@Preview +@Composable +fun TimetableCustomAddBoxPreview() { + TimetableCustomAddBox() +} \ No newline at end of file From 8b77176886e501e98b9b40423ad916add3372121 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 00:53:39 +0900 Subject: [PATCH 043/138] =?UTF-8?q?[add]=20TimetableInputField=20UI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/TimetableInputField.kt | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt new file mode 100644 index 000000000..67c8a84fd --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt @@ -0,0 +1,122 @@ +package `in`.koreatech.koin.feature.timetable.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Text +import androidx.compose.material3.VerticalDivider +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.timetable.R + +@Composable +fun TimetableInputField( + title: String, + modifier: Modifier = Modifier, + optional: Boolean = false, + onValueChange: (text: String) -> Unit = {}, +) { + var text by remember { mutableStateOf("") } + BasicTextField( + value = text, + onValueChange = { + text = it + onValueChange(text) + }, + modifier = modifier + .fillMaxWidth() + .height(35.dp), + maxLines = 1, + cursorBrush = SolidColor(Color.Black), + textStyle = KoinTheme.typography.regular12.copy( + color = KoinTheme.colors.neutral500 + ), + decorationBox = { innerTextField -> + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color.White) + .border( + width = 1.dp, + color = KoinTheme.colors.neutral300, + shape = RoundedCornerShape(4.dp) + ) + .padding(vertical = 4.dp, horizontal = 5.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (optional) { + Text( + text = stringResource(id = R.string.timetable_input_field_option_character), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.sub500, + modifier = Modifier.padding(end = 1.dp, bottom = 1.dp) + ) + } else { + Spacer(modifier = Modifier.width(8.dp)) + } + Text( + text = title, + style = KoinTheme.typography.bold12, + color = KoinTheme.colors.neutral800 + ) + Spacer(modifier = Modifier.width(7.dp)) + VerticalDivider( + thickness = 2.dp, + modifier = Modifier.heightIn(max = 25.dp), + color = KoinTheme.colors.neutral300 + ) + Spacer(modifier = Modifier.width(20.dp)) + Box { + text.ifEmpty { + Text( + text = stringResource(id = R.string.timetable_input_field_placeholder, title), + style = KoinTheme.typography.regular12, + color = KoinTheme.colors.neutral500 + ) + } + innerTextField() + } + } + } + ) +} + +@Preview(showBackground = true) +@Composable +private fun TimetableInputFieldPreview() { + TimetableInputField( + title = "일정명", + optional = false, + modifier = Modifier.padding(2.dp) + ) +} + +@Preview(showBackground = true) +@Composable +private fun TimetableInputFieldPreview_optional() { + TimetableInputField( + title = "일정명", + optional = true, + modifier = Modifier.padding(2.dp) + ) +} \ No newline at end of file From 08266dd7e596763bd01b27c903f7eb3b16035377 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 00:56:24 +0900 Subject: [PATCH 044/138] =?UTF-8?q?[add]=20TimetableTimeContentRow=20UI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/TimetableTimeContentRow.kt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt new file mode 100644 index 000000000..47b52373d --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt @@ -0,0 +1,76 @@ +package `in`.koreatech.koin.feature.timetable.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.timetable.R + +@Composable +fun TimetableTimeContentRow( + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .fillMaxWidth() + .background(Color.White) + .padding(start = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Row( + modifier = Modifier, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(id = R.string.timetable_input_field_option_character), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.sub500, + modifier = Modifier.padding(end = 1.dp, bottom = 1.dp) + ) + Text( + text = stringResource(id = R.string.timetable_input_field_title_time), + style = KoinTheme.typography.bold12, + color = KoinTheme.colors.neutral800 + ) + } + + Row(modifier = Modifier) { + TimeEditBox( + text = "월요일" + ) + Spacer(modifier = Modifier.width(11.dp)) + TimeEditBox( + text = "09:00" + ) + Spacer(modifier = Modifier.width(11.dp)) + Text( + text = stringResource(id = R.string.timetable_input_field_wave_character), + style = KoinTheme.typography.medium18, + color = KoinTheme.colors.neutral800 + ) + Spacer(modifier = Modifier.width(11.dp)) + TimeEditBox( + text = "11:00" + ) + } + } +} + +@Preview +@Composable +private fun TimetableTimeContentRowPreview() { + TimetableTimeContentRow() +} \ No newline at end of file From 75cdf86a73824bdfb6809505a627a84c1b15a12c Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 00:56:37 +0900 Subject: [PATCH 045/138] =?UTF-8?q?[del]=20=EC=83=98=ED=94=8C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/feature/timetable/model/TimetableConstants.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt index ac52d909c..31fa98715 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/model/TimetableConstants.kt @@ -44,7 +44,6 @@ val dummyLecture = Lecture( ) ) -val dummySemester = Semester(id = 1, semester = "20242") val defaultColors = listOf( TimetableColor(Color(0xFF890000),Color(0x33890000)), From dd810971a2dceccdc9c32746481ebdcd578062d7 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:08:04 +0900 Subject: [PATCH 046/138] =?UTF-8?q?[add]=20TimetableBottomSheetBasic=20?= =?UTF-8?q?=EC=84=B9=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/TimetableBottomSheetBasic.kt | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt new file mode 100644 index 000000000..7792e27d4 --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt @@ -0,0 +1,73 @@ +package `in`.koreatech.koin.feature.timetable.section + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.HorizontalDivider +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.domain.model.timetable.response.Lecture +import `in`.koreatech.koin.feature.timetable.component.LectureBox +import `in`.koreatech.koin.feature.timetable.component.TimetableSearchBox +import `in`.koreatech.koin.feature.timetable.model.TimetableEvent +import `in`.koreatech.koin.feature.timetable.model.dummyLecture + +@Composable +fun TimetableBottomSheetBasic( + searchText: String, + lectures: List, + modifier: Modifier = Modifier, + selectedLecture: Lecture? = null, + timetableEvents: List = emptyList(), + onClickSettingIcon: () -> Unit = {}, + onClickSearchIcon: () -> Unit = {}, + onSearchTextChange: (text: String) -> Unit = {}, + onClickAddLecture: (lecture: Lecture) -> Unit = {}, + onClickRemoveLecture: (lecture: Lecture) -> Unit = {}, + onClickLecture: (events: List) -> Unit = {}, + onSelectedLecture: (lecture: Lecture?) -> Unit = {}, +) { + Column( + modifier = modifier + .background(Color.White) + ) { + TimetableSearchBox( + modifier = Modifier.padding(bottom = 8.dp), + searchText = searchText, + onSearchTextChange = onSearchTextChange, + onClickSearchIcon = onClickSearchIcon, + onClickSettingIcon = onClickSettingIcon + ) + HorizontalDivider(thickness = 2.dp, color = KoinTheme.colors.neutral300) + LazyColumn { + items(lectures.size) { + LectureBox( + position = it, + lecture = lectures[it], + selectedLecture = selectedLecture, + timetableEvents = timetableEvents, + onClickLecture = onClickLecture, + onSelectedLecture = onSelectedLecture, + onClickAddLecture = onClickAddLecture, + onClickRemoveLecture = onClickRemoveLecture + ) + HorizontalDivider(thickness = 1.dp, color = KoinTheme.colors.neutral300) + } + } + } +} + +@Preview(showBackground = true) +@Composable +fun TimetableBottomSheetBasicPreview() { + TimetableBottomSheetBasic( + searchText = "", + lectures = listOf(dummyLecture, dummyLecture.copy(id = 2, name = "컴퓨터 개발")) + ) +} + From aea9b0ef6c18a372cbfbba5d8fbf2043b157822f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:08:18 +0900 Subject: [PATCH 047/138] =?UTF-8?q?[add]=20TimetableBottomSheetCustom=20UI?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/TimetableBottomSheetCustom.kt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt new file mode 100644 index 000000000..bcdce7280 --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt @@ -0,0 +1,62 @@ +package `in`.koreatech.koin.feature.timetable.section + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.feature.timetable.component.TimetableCustomAddBox +import `in`.koreatech.koin.feature.timetable.view.CustomEventExtraData + +@Composable +fun TimetableBottomSheetCustom( + modifier: Modifier = Modifier +) { + val events: SnapshotStateList = remember { mutableStateListOf() } + + LazyColumn( + modifier = modifier + ) { + item { + BottomSheetCustomContent( + onScheduleNameChange = {}, // TODO : 일정명 추가 + onProfessorNameChange = {}, // TODO : 교수명 추가 + onPlaceNameChange = {} // TODO : 장소 추가 + ) + } + items(events.size, key = { events[it].position }) { index -> + BottomSheetCustomExtraContent( + position = events[index].position, + onClickCancel = { cancelPosition -> + events.removeIf { it.position == cancelPosition } + }, + onPlaceNameChange = { } // TODO : 장소 추가 + ) + Spacer(modifier = Modifier.height(8.dp)) + } + + item { + TimetableCustomAddBox( + onClick = { + if (events.isEmpty()) { + events.add(CustomEventExtraData()) + } else { + events.add(CustomEventExtraData(position = events.last().position + 1)) + } + } + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun TimetableBottomSheetCustomPreview() { + TimetableBottomSheetCustom() +} + From 7d40ef65fc24a78db34db4d377cc5512a383aa2a Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:08:57 +0900 Subject: [PATCH 048/138] =?UTF-8?q?[add]=20BottomSheet=20Custom=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/BottomSheetCustomContent.kt | 52 ++++++++++++ .../section/BottomSheetCustomExtraContent.kt | 80 +++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt create mode 100644 feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomExtraContent.kt diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt new file mode 100644 index 000000000..123e4619e --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt @@ -0,0 +1,52 @@ +package `in`.koreatech.koin.feature.timetable.section + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.feature.timetable.R +import `in`.koreatech.koin.feature.timetable.component.TimetableInputField +import `in`.koreatech.koin.feature.timetable.component.TimetableTimeContentRow + +@Composable +fun BottomSheetCustomContent( + modifier: Modifier = Modifier, + onScheduleNameChange: (text: String) -> Unit = {}, + onProfessorNameChange: (text: String) -> Unit = {}, + onPlaceNameChange: (text: String) -> Unit = {}, +) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + TimetableInputField( + title = stringResource(id = R.string.timetable_input_field_title_schedule), + optional = true, + onValueChange = onScheduleNameChange + ) + Spacer(modifier = Modifier.height(8.dp)) + TimetableInputField( + title = stringResource(id = R.string.timetable_input_field_title_professor), + onValueChange = onProfessorNameChange + ) + Spacer(modifier = Modifier.height(8.dp)) + TimetableTimeContentRow() + Spacer(modifier = Modifier.height(8.dp)) + TimetableInputField( + title = stringResource(id = R.string.timetable_input_field_title_place), + onValueChange = onPlaceNameChange + ) + Spacer(modifier = Modifier.height(8.dp)) + } +} + +@Preview +@Composable +private fun BottomSheetCustomContentPreview() { + BottomSheetCustomContent() +} \ No newline at end of file diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomExtraContent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomExtraContent.kt new file mode 100644 index 000000000..17b2f4ef6 --- /dev/null +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomExtraContent.kt @@ -0,0 +1,80 @@ +package `in`.koreatech.koin.feature.timetable.section + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.component.icon.StableIcon +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.timetable.R +import `in`.koreatech.koin.feature.timetable.component.TimetableInputField +import `in`.koreatech.koin.feature.timetable.component.TimetableTimeContentRow + +@Composable +fun BottomSheetCustomExtraContent( + position: Int, + modifier: Modifier = Modifier, + onClickCancel: (position: Int) -> Unit = {}, + onPlaceNameChange: (text: String) -> Unit +) { + Column( + modifier = modifier + .fillMaxWidth() + .background(Color.White) + .border( + width = 1.dp, + color = KoinTheme.colors.neutral300, + shape = RoundedCornerShape(4.dp) + ), + ) { + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) { + IconButton( + onClick = { onClickCancel(position) }, + modifier = Modifier + .padding(5.dp) + .size(24.dp) + ) { + StableIcon( + drawableResId = R.drawable.ic_close, + ) + } + } + + Column( + modifier = Modifier.padding(horizontal = 13.dp) + ) { + Spacer(modifier = Modifier.height(4.dp)) + TimetableTimeContentRow() + Spacer(modifier = Modifier.height(8.dp)) + TimetableInputField( + title = stringResource(id = R.string.timetable_input_field_title_place), + onValueChange = onPlaceNameChange + ) + Spacer(modifier = Modifier.height(8.dp)) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun BottomSheetCustomExtraContentPreview() { + BottomSheetCustomExtraContent( + position = 1, + modifier = Modifier.padding(10.dp), + onPlaceNameChange = { } + ) +} \ No newline at end of file From 0d6530160212e0b73a3f0a17d48d57af6a6640cc Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:09:17 +0900 Subject: [PATCH 049/138] =?UTF-8?q?[add]=20TimetableBottomSheetHeader=20mo?= =?UTF-8?q?de=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/TimetableBottomSheetHeader.kt | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt index a246bde93..7af7e445b 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetHeader.kt @@ -7,12 +7,16 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.timetable.R +import `in`.koreatech.koin.feature.timetable.view.TimetableBottomSheetContentMode @Composable fun TimetableBottomSheetHeader( modifier: Modifier = Modifier, + mode: TimetableBottomSheetContentMode = TimetableBottomSheetContentMode.BASIC, onComplete: () -> Unit = {}, onClickAddLectureMode: () -> Unit = {}, onClickAddCustomLectureMode: () -> Unit = {}, @@ -23,23 +27,27 @@ fun TimetableBottomSheetHeader( horizontalArrangement = Arrangement.SpaceBetween ) { Text( - text = "직접추가", - style = KoinTheme.typography.medium18, - color = KoinTheme.colors.primary500, + text = stringResource(id = R.string.timetable_bottom_sheet_extra_custom_lecture), + style = when (mode) { + TimetableBottomSheetContentMode.BASIC -> KoinTheme.typography.medium18.copy(color = KoinTheme.colors.primary500) + TimetableBottomSheetContentMode.CUSTOM -> KoinTheme.typography.bold18.copy(color = KoinTheme.colors.primary600) + }, modifier = Modifier.clickable { onClickAddCustomLectureMode() } ) Text( - text = "수업 추가", - style = KoinTheme.typography.bold18, - color = KoinTheme.colors.primary600, + text = stringResource(id = R.string.timetable_bottom_sheet_extra_lecture), + style = when (mode) { + TimetableBottomSheetContentMode.BASIC -> KoinTheme.typography.bold18.copy(color = KoinTheme.colors.primary600) + TimetableBottomSheetContentMode.CUSTOM -> KoinTheme.typography.medium18.copy(color = KoinTheme.colors.primary500) + }, modifier = Modifier.clickable { onClickAddLectureMode() } ) Text( - text = "완료", + text = stringResource(id = R.string.timetable_bottom_sheet_complete), style = KoinTheme.typography.medium18, color = KoinTheme.colors.neutral800, modifier = Modifier.clickable { @@ -53,4 +61,12 @@ fun TimetableBottomSheetHeader( @Composable private fun TimetableBottomSheetHeaderPreview() { TimetableBottomSheetHeader() +} + +@Preview(showBackground = true) +@Composable +private fun TimetableBottomSheetHeaderPreview_Custom() { + TimetableBottomSheetHeader( + mode = TimetableBottomSheetContentMode.CUSTOM + ) } \ No newline at end of file From 84759b93ef8c773d194a9d08d5d6a0f773cb04b5 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:09:35 +0900 Subject: [PATCH 050/138] =?UTF-8?q?[fix]=20TimetableBottomSheet=20UI=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/view/TimetableBottomSheet.kt | 77 ++++++++++++++----- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt index 80612b321..ef80bd054 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt @@ -2,10 +2,11 @@ package `in`.koreatech.koin.feature.timetable.view import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -15,17 +16,37 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.domain.model.timetable.response.Lecture -import `in`.koreatech.koin.feature.timetable.component.LectureBox -import `in`.koreatech.koin.feature.timetable.component.TimetableSearchBox import `in`.koreatech.koin.feature.timetable.model.TimetableEvent -import `in`.koreatech.koin.feature.timetable.model.defaultColors import `in`.koreatech.koin.feature.timetable.model.dummyLecture +import `in`.koreatech.koin.feature.timetable.section.TimetableBottomSheetBasic +import `in`.koreatech.koin.feature.timetable.section.TimetableBottomSheetCustom import `in`.koreatech.koin.feature.timetable.section.TimetableBottomSheetHeader +import java.time.DayOfWeek +import java.time.LocalTime + +enum class TimetableBottomSheetContentMode { + CUSTOM, BASIC +} + +data class CustomEventData( + val schedule: String = "", + val professor: String? = "", + val data: List = emptyList() +) + +data class CustomEventExtraData( + val position: Int = 0, + val dayOfWeek: DayOfWeek = DayOfWeek.MONDAY, + val startTime: LocalTime = LocalTime.of(9, 0), + val endTime: LocalTime = LocalTime.of(10, 0), + val place: String = "" +) @Composable fun TimetableBottomSheet( searchText: String, lectures: List, + bottomSheetContentMode: TimetableBottomSheetContentMode, modifier: Modifier = Modifier, selectedLecture: Lecture? = null, timetableEvents: List = emptyList(), @@ -57,33 +78,35 @@ fun TimetableBottomSheet( TimetableBottomSheetHeader( modifier = Modifier.padding(bottom = 4.dp), onComplete = onComplete, + mode = bottomSheetContentMode, onClickAddLectureMode = onClickAddLectureMode, onClickAddCustomLectureMode = onClickAddCustomLectureMode ) HorizontalDivider(thickness = 1.dp, color = KoinTheme.colors.neutral300) - TimetableSearchBox( - modifier = Modifier.padding(vertical = 8.dp), - searchText = searchText, - onSearchTextChange = onSearchTextChange, - onClickSearchIcon = onClickSearchIcon, - onClickSettingIcon = onClickSettingIcon - ) - HorizontalDivider(thickness = 2.dp, color = KoinTheme.colors.neutral300) - LazyColumn { - items(lectures.size) { - LectureBox( - position = it, - lecture = lectures[it], + Spacer(modifier = Modifier.height(8.dp)) + + when (bottomSheetContentMode) { + TimetableBottomSheetContentMode.BASIC -> { + TimetableBottomSheetBasic( + searchText = searchText, + lectures = lectures, selectedLecture = selectedLecture, timetableEvents = timetableEvents, + onClickSettingIcon = onClickSettingIcon, + onClickSearchIcon = onClickSearchIcon, + onSearchTextChange = onSearchTextChange, + onClickAddLecture = onClickAddLecture, + onClickRemoveLecture = onClickRemoveLecture, onClickLecture = onClickLecture, onSelectedLecture = onSelectedLecture, - onClickAddLecture = onClickAddLecture, - onClickRemoveLecture = onClickRemoveLecture ) - HorizontalDivider(thickness = 1.dp, color = KoinTheme.colors.neutral300) + } + + TimetableBottomSheetContentMode.CUSTOM -> { + TimetableBottomSheetCustom() } } + } } @@ -94,6 +117,20 @@ private fun TimetableBottomSheetPreview() { TimetableBottomSheet( searchText = "", lectures = listOf(dummyLecture, dummyLecture.copy(id = 2, name = "컴퓨터 개발")), + bottomSheetContentMode = TimetableBottomSheetContentMode.BASIC, + selectedLecture = null, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun TimetableBottomSheetPreview_Custom() { + KoinTheme { + TimetableBottomSheet( + searchText = "", + lectures = listOf(dummyLecture, dummyLecture.copy(id = 2, name = "컴퓨터 개발")), + bottomSheetContentMode = TimetableBottomSheetContentMode.CUSTOM, selectedLecture = null, ) } From 7442bbf1357109bd6742d4806447de245295ab37 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:10:01 +0900 Subject: [PATCH 051/138] =?UTF-8?q?[add]=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/timetable/src/main/res/drawable/ic_add.xml | 13 +++++++++++++ .../src/main/res/drawable/ic_arrow_down.xml | 9 +++++++++ .../timetable/src/main/res/drawable/ic_close.xml | 13 +++++++++++++ feature/timetable/src/main/res/values/strings.xml | 13 +++++++++++++ koin/src/main/res/drawable/ic_edit.xml | 13 +++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 feature/timetable/src/main/res/drawable/ic_add.xml create mode 100644 feature/timetable/src/main/res/drawable/ic_arrow_down.xml create mode 100644 feature/timetable/src/main/res/drawable/ic_close.xml create mode 100644 koin/src/main/res/drawable/ic_edit.xml diff --git a/feature/timetable/src/main/res/drawable/ic_add.xml b/feature/timetable/src/main/res/drawable/ic_add.xml new file mode 100644 index 000000000..64dd922df --- /dev/null +++ b/feature/timetable/src/main/res/drawable/ic_add.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/feature/timetable/src/main/res/drawable/ic_arrow_down.xml b/feature/timetable/src/main/res/drawable/ic_arrow_down.xml new file mode 100644 index 000000000..b1919ab96 --- /dev/null +++ b/feature/timetable/src/main/res/drawable/ic_arrow_down.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature/timetable/src/main/res/drawable/ic_close.xml b/feature/timetable/src/main/res/drawable/ic_close.xml new file mode 100644 index 000000000..235d755ff --- /dev/null +++ b/feature/timetable/src/main/res/drawable/ic_close.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/feature/timetable/src/main/res/values/strings.xml b/feature/timetable/src/main/res/values/strings.xml index dc4cf23bd..9bf2bcab2 100644 --- a/feature/timetable/src/main/res/values/strings.xml +++ b/feature/timetable/src/main/res/values/strings.xml @@ -35,4 +35,17 @@ 전공선택 + ~ + * + %s을 입력하세요. + 일정명 + 교수명 + 시간 + 장소 + 시간 및 장소 추가 + + 수업추가 + 직접추가 + 완료 + \ No newline at end of file diff --git a/koin/src/main/res/drawable/ic_edit.xml b/koin/src/main/res/drawable/ic_edit.xml new file mode 100644 index 000000000..046ff6bfd --- /dev/null +++ b/koin/src/main/res/drawable/ic_edit.xml @@ -0,0 +1,13 @@ + + + + + + From fc1b0c4c5cef6c620a11e833984ab786c0dee86e Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:10:19 +0900 Subject: [PATCH 052/138] =?UTF-8?q?[add]=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20xml=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- koin/src/main/res/layout/activity_timetable.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koin/src/main/res/layout/activity_timetable.xml b/koin/src/main/res/layout/activity_timetable.xml index b9294a2af..85f19b898 100644 --- a/koin/src/main/res/layout/activity_timetable.xml +++ b/koin/src/main/res/layout/activity_timetable.xml @@ -25,7 +25,7 @@ app:leftButtonBackground="@drawable/ic_back_arrow" app:leftButtonHeight="14dp" app:leftButtonWidth="14dp" - app:rightButtonBackground="@drawable/ic_hamburger_button" + app:rightButtonBackground="@drawable/ic_edit" app:rightButtonHeight="18dp" app:rightButtonWidth="12dp" app:titleText="@string/navigation_item_timetable" /> From 56588e185438b7ca8ef962bf158933fbefa1509f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:15:10 +0900 Subject: [PATCH 053/138] =?UTF-8?q?[add]=20=ED=81=B4=EB=A6=AD=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=EB=84=88=20=EC=97=B0=EA=B2=B0=20=EB=B0=8F=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/view/TimetableScreen.kt | 21 ++++++------ .../koin/ui/timetablev2/TimetableActivity.kt | 32 +++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt index 080c4f16f..b63ff8be3 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableScreen.kt @@ -2,7 +2,6 @@ package `in`.koreatech.koin.feature.timetable.view import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -10,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.material.BottomSheetScaffold import androidx.compose.material.BottomSheetScaffoldState import androidx.compose.material.BottomSheetState @@ -18,7 +16,6 @@ import androidx.compose.material.BottomSheetValue import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material.rememberBottomSheetState -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -32,13 +29,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.util.pxToDp import `in`.koreatech.koin.domain.model.timetable.response.Lecture -import `in`.koreatech.koin.domain.model.timetable.response.Semester import `in`.koreatech.koin.feature.timetable.component.CircleLoadingBar import `in`.koreatech.koin.feature.timetable.component.TimetableDownloadBox import `in`.koreatech.koin.feature.timetable.component.TimetableScheduleBox import `in`.koreatech.koin.feature.timetable.model.TimetableEvent import `in`.koreatech.koin.feature.timetable.model.dummyLecture -import `in`.koreatech.koin.feature.timetable.model.dummySemester import kotlinx.coroutines.launch @OptIn(ExperimentalMaterialApi::class) @@ -47,9 +42,11 @@ fun TimetableScreen( loading: Boolean, range: Int, lectures: List, - semesters: List, + semesters: List, + currentSemester: String, selectedLecture: Lecture?, searchText: String, + bottomSheetContentMode: TimetableBottomSheetContentMode, sheetState: BottomSheetState, scaffoldState: BottomSheetScaffoldState, modifier: Modifier = Modifier, @@ -64,7 +61,9 @@ fun TimetableScreen( onSelectedLecture: (lecture: Lecture?) -> Unit = {}, onClickSettingIcon: () -> Unit = {}, onClickSearchIcon: () -> Unit = {}, - onClickTimetableEvent: (event: TimetableEvent) -> Unit = {} + onClickTimetableEvent: (event: TimetableEvent) -> Unit = {}, + onClickAddLectureMode: () -> Unit = {}, + onClickAddCustomLectureMode: () -> Unit = {}, ) { var bottomSheetHeight by remember { mutableStateOf(0f) } val scope = rememberCoroutineScope() @@ -77,8 +76,10 @@ fun TimetableScreen( lectures = lectures, selectedLecture = selectedLecture, searchText = searchText, + bottomSheetContentMode = bottomSheetContentMode, timetableEvents = timetableEvents, - onClickAddLectureMode = {}, + onClickAddLectureMode = onClickAddLectureMode, + onClickAddCustomLectureMode = onClickAddCustomLectureMode, onComplete = { scope.launch { sheetState.collapse() } }, onClickSettingIcon = onClickSettingIcon, onClickSearchIcon = onClickSearchIcon, @@ -152,9 +153,11 @@ private fun TimetableScreenPreview() { loading = false, range = 9, lectures = listOf(dummyLecture), - semesters = listOf(dummySemester), + semesters = listOf("20242"), + currentSemester = "20242", selectedLecture = null, searchText = "", + bottomSheetContentMode = TimetableBottomSheetContentMode.BASIC, sheetState = rememberBottomSheetState( initialValue = BottomSheetValue.Collapsed ), diff --git a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt index 99bd04da3..2378c98cc 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt @@ -7,14 +7,19 @@ import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material.rememberBottomSheetState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.koin.core.appbar.AppBarBase import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.core.util.KeyboardUtils import `in`.koreatech.koin.databinding.ActivityTimetableBinding +import `in`.koreatech.koin.feature.timetable.view.TimetableBottomSheetContentMode import `in`.koreatech.koin.feature.timetable.view.TimetableScreen import `in`.koreatech.koin.feature.timetable.view.dialog.LectureDuplicationDialog +import `in`.koreatech.koin.feature.timetable.view.dialog.RequestLoginDialog import `in`.koreatech.koin.feature.timetable.view.dialog.SelectDepartmentDialog import `in`.koreatech.koin.feature.timetable.viewmodel.TimetableViewModel import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerActivity @@ -62,6 +67,8 @@ class TimetableActivity : KoinNavigationDrawerActivity() { ) val scope = rememberCoroutineScope() + var bottomSheetContentMode by remember { mutableStateOf(TimetableBottomSheetContentMode.BASIC) } + hideKeyboard(sheetState.isCollapsed) setAppbarEvent { @@ -101,20 +108,37 @@ class TimetableActivity : KoinNavigationDrawerActivity() { ) } + if (uiState.isLoginDialogVisible) { + RequestLoginDialog( + onConfirm = {}, // TODO : 로그인 화면으로 연결 + onDismiss = viewModel::updateIsLoginDialogVisible + ) + } + TimetableScreen( loading = uiState.loading, range = uiState.range, lectures = lectures, semesters = uiState.semesters, + currentSemester = uiState.currentSemester, selectedLecture = uiState.selectedLecture, timetableEvents = uiState.timetableEvents, clickedTimetableEvents = uiState.clickedTimetableEvents, searchText = searchText, + bottomSheetContentMode = bottomSheetContentMode, sheetState = sheetState, scaffoldState = scaffoldState, onSearchTextChange = viewModel::updateSearchText, onClickTimetableSchedule = {}, // TODO : 학기 시간표 선택 onClickDownloadTimetable = {}, // TODO : 시간표 다운로드 + onClickAddLectureMode = { + bottomSheetContentMode = TimetableBottomSheetContentMode.BASIC + }, + onClickAddCustomLectureMode = { + handleAddCustomLectureMode(uiState.isAnonymous) { + bottomSheetContentMode = TimetableBottomSheetContentMode.CUSTOM + } + }, onClickAddLecture = viewModel::updateTimetableLectures, onClickRemoveLecture = viewModel::removeTimetableLectures, onClickLecture = viewModel::updateClickedTimetableEvents, @@ -131,6 +155,14 @@ class TimetableActivity : KoinNavigationDrawerActivity() { setAppbarEvent() } + private fun handleAddCustomLectureMode(isAnonymous: Boolean, callback: () -> Unit) { + if (isAnonymous) { + viewModel.updateIsLoginDialogVisible() + } else { + callback() + } + } + private fun getUserExtra(callback: (isAnonymous: Boolean) -> Unit) { callback(intent.getBooleanExtra("isAnonymous", true)) } From 15b4f5585ed16183c4ecea7d94fb036dc685c286 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:33:52 +0900 Subject: [PATCH 054/138] =?UTF-8?q?[fix]=20Timetable=20=EB=B7=B0=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/viewmodel/TimetableViewModel.kt | 217 +++++++++++------- .../koin/ui/timetablev2/TimetableActivity.kt | 2 +- 2 files changed, 138 insertions(+), 81 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt index 47d8116c5..df3588297 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt @@ -4,10 +4,12 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import `in`.koreatech.koin.domain.model.timetable.response.Lecture -import `in`.koreatech.koin.domain.model.timetable.response.Semester import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures import `in`.koreatech.koin.domain.repository.TimetableRepository +import `in`.koreatech.koin.domain.usecase.timetable.AddTimetableLectureUseCase +import `in`.koreatech.koin.domain.usecase.timetable.DeleteTimetableFrameLectureUseCase +import `in`.koreatech.koin.domain.usecase.timetable.DeleteTimetableLectureUseCase import `in`.koreatech.koin.domain.usecase.timetable.GetLecturesUseCase import `in`.koreatech.koin.domain.usecase.timetable.GetSemesterUseCase import `in`.koreatech.koin.domain.usecase.timetable.GetTimetableFramesUseCase @@ -31,6 +33,9 @@ class TimetableViewModel @Inject constructor( private val getLecturesUseCase: GetLecturesUseCase, private val getSemesterUseCase: GetSemesterUseCase, private val getTimetableFramesUseCase: GetTimetableFramesUseCase, + private val addTimetableLectureUseCase: AddTimetableLectureUseCase, + private val deleteTimetableLectureUseCase: DeleteTimetableLectureUseCase, + private val deleteTimetableFrameLectureUseCase: DeleteTimetableFrameLectureUseCase, private val timetableRepository: TimetableRepository ) : ViewModel() { private val _uiState = MutableStateFlow(TimetableUiState()) @@ -58,9 +63,7 @@ class TimetableViewModel @Inject constructor( } } else { lectures.filter { lecture -> - lecture.doesMatchDepartmentSearchQuery(searchEngineState.department) && (searchEngineState.text.isBlank() || lecture.doesMatchSearchQuery( - searchEngineState.text - )) + lecture.doesMatchDepartmentSearchQuery(searchEngineState.department) && (searchEngineState.text.isBlank() || lecture.doesMatchSearchQuery(searchEngineState.text)) } } }.stateIn( @@ -69,20 +72,16 @@ class TimetableViewModel @Inject constructor( emptyList() ) - - fun getUser(isAnonymous: Boolean) { - _uiState.value = _uiState.value.copy(isAnonymous = isAnonymous) - } - fun getInitData() { viewModelScope.launch { - _uiState.value = _uiState.value.copy(loading = true) - val semesters = getSemester() - val semester = semesters.firstOrNull()?.semester.orEmpty() - val lectures = getLectures(semester) - _lectures.value = lectures + updateLoading(true) + val semesters = getSemester(uiState.value.isAnonymous) + val semester = semesters.firstOrNull().orEmpty() + // TODO: 로그인 시, 학기를 불러올 때 Empty 이면 학기 추가를 해야하는 경고문 추가하기 (디자인 없어서 추가해야 함) + + _lectures.value = getLectures(semester) - when (_uiState.value.isAnonymous) { + when (uiState.value.isAnonymous) { true -> { timetableRepository.getTimetableLectures(semester) .onSuccess { timetableLectures -> @@ -95,9 +94,7 @@ class TimetableViewModel @Inject constructor( loading = false ) }.onFailure { - _uiState.value = _uiState.value.copy( - loading = false - ) + updateLoading(false) Timber.e("getTimetableLectures Local Error Message : ${it.message}") } } @@ -105,19 +102,12 @@ class TimetableViewModel @Inject constructor( false -> { // TODO : 로그인 시 시간표 수업 불러오기 val timetableFrames = getTimetableFrames(semester).ifEmpty { - _uiState.value = _uiState.value.copy( - semesters = semesters, - currentSemester = semester, - loading = false - ) + updateSemesters(semesters, semester) return@launch } val frameId = timetableFrames.find { it.isMain }?.id if (frameId == null) { - _uiState.value = _uiState.value.copy( - semesters = semesters, - currentSemester = semester, loading = false - ) + updateSemesters(semesters, semester) return@launch } @@ -125,6 +115,7 @@ class TimetableViewModel @Inject constructor( .onSuccess { timetableLectures -> _uiState.value = _uiState.value.copy( range = timetableLectures.formatTimeRange(), + frameId = timetableLectures.timetableFrameId, semesters = semesters, timetableEvents = timetableLectures.getTimetableEvents(), currentSemester = semester, @@ -132,9 +123,7 @@ class TimetableViewModel @Inject constructor( loading = false ) }.onFailure { - _uiState.value = _uiState.value.copy( - loading = false - ) + updateLoading(false) Timber.e("getTimetableLectures Remote Error Message : ${it.message}") } } @@ -144,8 +133,8 @@ class TimetableViewModel @Inject constructor( } } - private suspend fun getSemester(): List { - return getSemesterUseCase().catch { + private suspend fun getSemester(isAnonymous: Boolean): List { + return getSemesterUseCase(isAnonymous).catch { Timber.e("getSemester Error Message : ${it.message}") }.firstOrNull().orEmpty() } @@ -162,15 +151,29 @@ class TimetableViewModel @Inject constructor( }.firstOrNull().orEmpty() } + private fun updateLoading(loading: Boolean) { + _uiState.value = _uiState.value.copy(loading = loading) + } + + private fun updateSemesters(semesters: List, semester: String) { + _uiState.value = _uiState.value.copy( + semesters = semesters, + currentSemester = semester, + loading = false + ) + } + + fun updateIsAnonymous(isAnonymous: Boolean) { + _uiState.value = _uiState.value.copy(isAnonymous = isAnonymous) + } + fun updateSearchText(text: String) { _searchText.value = text } fun updateDepartment(text: String) { _department.value = text - _uiState.value = _uiState.value.copy( - isSelectDepartmentDialogVisible = false - ) + updateIsSelectDepartmentDialogVisible() } fun updateClickedTimetableEvents(timetableEvents: List) { @@ -193,86 +196,138 @@ class TimetableViewModel @Inject constructor( fun updateIsLectureDuplicationDialogVisible() { _uiState.value = _uiState.value.copy( - isLectureDuplicationDialogVisible = false + isLectureDuplicationDialogVisible = !_uiState.value.isLectureDuplicationDialogVisible + ) + } + + fun updateIsLoginDialogVisible() { + _uiState.value = _uiState.value.copy( + isLoginDialogVisible = !_uiState.value.isLoginDialogVisible ) } fun updateTimetableLectures(lecture: Lecture) { when (isDuplicateClassTime(lecture)) { - true -> { + true -> { // TODO : 강의 중복일 경우 _uiState.value = _uiState.value.copy( duplicationLecture = lecture, isLectureDuplicationDialogVisible = true ) } - false -> { - when (_uiState.value.isAnonymous) { - true -> { - addTimetableLectures(lecture) - } - - false -> { - // TODO : 로그인 시 강의 추가 (중복 X) - } - } + false -> { // TODO : 강의 중복이 아니고 추가 되어야 할 경우 + addTimetableLectures(lecture) } } } fun updateDuplicationTimetableLecture() { - val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() + when (uiState.value.isAnonymous) { + true -> { + val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() - _uiState.value.duplicationLecture?.classTime?.forEach { time -> - _uiState.value.timetableLectures.timetable.filter { it.classTime.contains(time) } - .forEach { lecture -> - updatedTimetableLectures.remove(lecture) + uiState.value.duplicationLecture?.classTime?.forEach { time -> + uiState.value.timetableLectures.timetable.filter { it.classTime.contains(time) } + .forEach { lecture -> + updatedTimetableLectures.remove(lecture) + } } - } - _uiState.value.duplicationLecture?.toTimetableLecture()?.let { timetableLecture -> - updatedTimetableLectures.add(timetableLecture) - } + uiState.value.duplicationLecture?.toTimetableLecture()?.let { timetableLecture -> + updatedTimetableLectures.add(timetableLecture) + } - val timetables = _uiState.value.timetableLectures.copy( - timetable = updatedTimetableLectures - ) + val timetables = _uiState.value.timetableLectures.copy( + timetable = updatedTimetableLectures + ) - when (_uiState.value.isAnonymous) { - true -> { - postTimetableLectures(timetables) + postLocalTimetableLectures(timetables) } - false -> { - // TODO : 로그인 시 중복에 대한 강의 업데이트 + // TODO : 로그인 시 중복에 대한 강의 추가 } } } fun addTimetableLectures(lecture: Lecture) { - val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() - updatedTimetableLectures.add(lecture.toTimetableLecture()) - val timetables = _uiState.value.timetableLectures.copy( - timetable = updatedTimetableLectures - ) + when(uiState.value.isAnonymous) { + true -> { + val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() + updatedTimetableLectures.add(lecture.toTimetableLecture()) + val timetables = _uiState.value.timetableLectures.copy( + timetable = updatedTimetableLectures + ) + + postLocalTimetableLectures(timetables) + } + false -> { + viewModelScope.launch { + addTimetableLectureUseCase( + frameId = uiState.value.frameId, + lectures = listOf(lecture) // TODO : updateTimetableLectures 함수 파라미터 lecture를 리스트로 변경 필요 + ).onSuccess { timetableLectures -> + _uiState.value = _uiState.value.copy( + range = timetableLectures.formatTimeRange(), + frameId = timetableLectures.timetableFrameId, + timetableLectures = timetableLectures, + timetableEvents = timetableLectures.getTimetableEvents(), + clickedTimetableEvents = emptyList(), + selectedLecture = null, + loading = false + ) + }.onFailure { + // TODO : 강의 추가 실패 + Timber.e("addTimetableLecture Remote Error Message : ${it.message}") + updateLoading(false) + } + } + } + } - postTimetableLectures(timetables) } fun removeTimetableLectures(lecture: Lecture) { - val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() - updatedTimetableLectures.remove(lecture.toTimetableLecture()) - val timetables = _uiState.value.timetableLectures.copy( - timetable = updatedTimetableLectures - ) + when (_uiState.value.isAnonymous) { + true -> { + val updatedTimetableLectures = _uiState.value.timetableLectures.timetable.toMutableList() + updatedTimetableLectures.remove(lecture.toTimetableLecture()) + val timetables = _uiState.value.timetableLectures.copy( + timetable = updatedTimetableLectures + ) + + postLocalTimetableLectures(timetables) + } - postTimetableLectures(timetables) + false -> { + // TODO : 로그인 시, 강의 삭제 액션 + viewModelScope.launch { + deleteTimetableFrameLectureUseCase(uiState.value.frameId, lecture.id).onSuccess { + timetableRepository.getTimetableLectures(uiState.value.frameId) + .onSuccess { timetableLectures -> + _uiState.value = _uiState.value.copy( + range = timetableLectures.formatTimeRange(), + frameId = timetableLectures.timetableFrameId, + timetableEvents = timetableLectures.getTimetableEvents(), + timetableLectures = timetableLectures, + ) + }.onFailure { + // TODO : 강의 불러오기 실패 + Timber.e("getTimetableLectures Remote Error Message : ${it.message}") + } + }.onFailure { + // TODO : 강의 삭제 실패 + Timber.e("deleteTimetableLectureUseCase Remote Error Message : ${it.message}") + } + } + + } + } } - private fun postTimetableLectures(timetables: TimetableLectures) { + private fun postLocalTimetableLectures(timetables: TimetableLectures) { viewModelScope.launch { - timetableRepository.putTimetableLectures(_uiState.value.currentSemester, timetables) + timetableRepository.putTimetableLectures(uiState.value.currentSemester, timetables) .onSuccess { timetableLectures -> _uiState.value = _uiState.value.copy( range = timetableLectures.formatTimeRange(), @@ -294,7 +349,7 @@ class TimetableViewModel @Inject constructor( private fun isDuplicateClassTime(lecture: Lecture): Boolean { lecture.classTime.forEach { time -> - _uiState.value.timetableLectures.timetable.forEach { timetableLecture -> + uiState.value.timetableLectures.timetable.forEach { timetableLecture -> if (timetableLecture.classTime.any { it == time }) return true } } @@ -309,8 +364,9 @@ data class SearchEngineState( data class TimetableUiState( val range: Int = 9, + val frameId: Int = 0, val duplicationLecture: Lecture? = null, - val semesters: List = emptyList(), + val semesters: List = emptyList(), val currentSemester: String = "", val timetableEvents: List = emptyList(), val clickedTimetableEvents: List = emptyList(), @@ -319,5 +375,6 @@ data class TimetableUiState( val loading: Boolean = false, val isLectureDuplicationDialogVisible: Boolean = false, val isSelectDepartmentDialogVisible: Boolean = false, + val isLoginDialogVisible: Boolean = false, val isAnonymous: Boolean = true, ) diff --git a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt index 2378c98cc..a88647e57 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt @@ -45,7 +45,7 @@ class TimetableActivity : KoinNavigationDrawerActivity() { private fun initView() { getUserExtra { isAnonymous -> - viewModel.getUser(isAnonymous) + viewModel.updateIsAnonymous(isAnonymous) } viewModel.getInitData() initComposeView() From 7bc3990b5c20d2ea34798541cdb7258ae70f0944 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 01:38:25 +0900 Subject: [PATCH 055/138] =?UTF-8?q?[add]=20immutable=20dependency=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/timetable/build.gradle.kts | 1 + gradle/libs.versions.toml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/feature/timetable/build.gradle.kts b/feature/timetable/build.gradle.kts index 9b20400a8..7b8b8fefe 100644 --- a/feature/timetable/build.gradle.kts +++ b/feature/timetable/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { implementation(platform(libs.compose.bom)) implementation(libs.compose.material2) implementation(libs.bundles.compose.m3) + implementation(libs.kotlinx.immutable) implementation(libs.timber) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5eb8da42..34118337e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -69,6 +69,7 @@ jsoup = "1.18.1" timber = "5.0.1" kotlinxCoroutinesTestVersion = "1.9.0" turbineVersion = "1.2.0" +kotlinxCollectionsImmutableVersion = "0.3.8" [libraries] @@ -197,6 +198,8 @@ timber = { module = "com.jakewharton.timber:timber", version.ref = "timber"} coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTestVersion" } turbine = { module = "app.cash.turbine:turbine", version.ref = "turbineVersion" } +kotlinx-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutableVersion" } + [plugins] android-application = { id = "com.android.application", version.ref = "androidGradleVersion" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } From 10d8650c20a78dd4deb12c563d3ea835285f813f Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 16:32:07 +0900 Subject: [PATCH 056/138] =?UTF-8?q?[add]=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8A=B8=EB=9E=98=ED=82=B9=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/section/TimetableContent.kt | 6 +++++- .../koin/feature/timetable/view/Timetable.kt | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt index 9bfdec3d5..e5e1c7a11 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableContent.kt @@ -56,6 +56,7 @@ fun TimetableContent( ) }, onEventClick: (event: TimetableEvent) -> Unit = {}, + onEventY: (y: Int) -> Unit = {} ) { val width = measureEventWidth(horizontalPadding = horizontalPadding, dayCount = dayCount) @@ -225,7 +226,7 @@ fun TimetableContent( } // 강의 이벤트 박스 배치 - placeablesWithEvents.forEach { (placeable, event) -> + placeablesWithEvents.forEachIndexed { index, (placeable, event) -> val initStartTime = LocalTime.of(9, 0) val eventOffsetMinutes = ChronoUnit.MINUTES.between(initStartTime, event.start) @@ -243,6 +244,9 @@ fun TimetableContent( else -> -1 } val eventX = eventOffsetDays * innerWidth + timeWidth.roundToPx() + if (index == placeablesWithEvents.size - 1) { + onEventY(eventY) + } placeable.place(eventX, eventY) } } diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt index 52d148942..b6cc4d5d3 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt @@ -7,6 +7,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -38,6 +43,13 @@ fun Timetable( onEventClick: (TimetableEvent) -> Unit = {}, ) { val verticalScrollState: ScrollState = rememberScrollState() + var scrollValue by remember { mutableStateOf(0) } + + LaunchedEffect(key1 = scrollValue) { + if (clickEvent.isNotEmpty()) { + verticalScrollState.scrollTo(scrollValue) + } + } TimetableContent( modifier = modifier @@ -48,7 +60,12 @@ fun Timetable( events = events, clickEvent = clickEvent, content = content, - onEventClick = onEventClick + onEventClick = onEventClick, + onEventY = {y -> + if (scrollValue != y) { + scrollValue = y + } + } ) } From a8ca4c231f5b18d0e3c8ce8d8147c908351eb3dc Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 16:32:21 +0900 Subject: [PATCH 057/138] =?UTF-8?q?[fix]=20=EB=B0=94=ED=85=80=EC=8B=9C?= =?UTF-8?q?=ED=8A=B8=20=EB=86=92=EC=9D=B4=20=EA=B3=A0=EC=A0=95=20dp=20?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/feature/timetable/view/TimetableBottomSheet.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt index ef80bd054..fa30fa091 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt @@ -3,7 +3,6 @@ package `in`.koreatech.koin.feature.timetable.view import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -65,7 +64,7 @@ fun TimetableBottomSheet( Column( modifier = modifier .fillMaxWidth() - .fillMaxHeight(0.65f) + .height(400.dp) .background(Color.White) .onGloballyPositioned { onBottomSheetHeightChange(it.size.height.toFloat()) From 786eaad36fbc3489c0824601652fdca4b912efcf Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Tue, 5 Nov 2024 16:32:32 +0900 Subject: [PATCH 058/138] =?UTF-8?q?feature:=20=EC=82=AC=EC=9E=A5=EB=8B=98?= =?UTF-8?q?=20=EA=B3=84=EC=A0=95=20=ED=83=88=ED=87=B4=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/store/OwnerStoreAppBar.kt | 29 +++- .../feature/store/navigator/StoreNavigator.kt | 8 + .../store/storedetail/MyStoreDetailScreen.kt | 16 +- .../storedetail/MyStoreDetailSideEffect.kt | 2 + .../store/storedetail/MyStoreDetailState.kt | 1 + .../storedetail/MyStoreDetailViewModel.kt | 32 ++++ .../storedetail/dialog/DeleteUserDialog.kt | 138 ++++++++++++++++++ .../storedetail/dialog/MyStoreSelectDialog.kt | 17 --- business/src/main/res/values/strings.xml | 3 + .../repository/OwnerRegisterRepositoryImpl.kt | 5 +- 10 files changed, 223 insertions(+), 28 deletions(-) create mode 100644 business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/DeleteUserDialog.kt diff --git a/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt b/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt index 3b5d22408..390b5a54e 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt @@ -3,6 +3,7 @@ package `in`.koreatech.business.feature.store import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.IconButton import androidx.compose.material.Text @@ -19,23 +20,35 @@ import `in`.koreatech.business.R import `in`.koreatech.business.ui.theme.ColorPrimary @Composable -fun OwnerStoreAppBar(title: String) { +fun OwnerStoreAppBar( + title: String, + showDeleteUserDialog: () -> Unit = {} +) { Box( modifier = Modifier .fillMaxWidth() .background(ColorPrimary), ) { - IconButton(onClick = { /*TODO*/ }) { - Image( - painter = painterResource(id = R.drawable.ic_back), - contentDescription = stringResource(R.string.back), - colorFilter = ColorFilter.tint(Color.White), - ) - } Text( text = title, modifier = Modifier.align(Alignment.Center), style = TextStyle(color = Color.White, fontSize = 18.sp), ) + + IconButton( + modifier = Modifier + .align(Alignment.BottomEnd) + , + onClick = { + showDeleteUserDialog() + } + + ) { + Image( + painter = painterResource(id = R.drawable.ic_delete), + contentDescription = stringResource(R.string.delete_user), + colorFilter = ColorFilter.tint(Color.White), + ) + } } } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/store/navigator/StoreNavigator.kt b/business/src/main/java/in/koreatech/business/feature/store/navigator/StoreNavigator.kt index f628d7c77..892378385 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/navigator/StoreNavigator.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/navigator/StoreNavigator.kt @@ -20,6 +20,7 @@ import `in`.koreatech.business.feature.store.storedetail.MyStoreDetailScreen import `in`.koreatech.business.feature.store.storedetail.MyStoreDetailViewModel import `in`.koreatech.business.navigation.MYSTORESCREEN import `in`.koreatech.business.navigation.REGISTERSTORESCREEN +import `in`.koreatech.business.navigation.SIGNINSCREEN import `in`.koreatech.business.navigation.navigate import `in`.koreatech.business.navigation.sharedHiltViewModel import `in`.koreatech.business.navigation.toNavigateModifyMenuScreen @@ -40,6 +41,13 @@ fun NavGraphBuilder.myStoreScreen( val modifyInfoViewModel: ModifyInfoViewModel = it.sharedHiltViewModel(navController = navController) MyStoreDetailScreen( modifier = Modifier.fillMaxSize(), + navigateToLoginScreen = { + navController.navigate(SIGNINSCREEN){ + popUpTo(MYSTORESCREEN){ + inclusive = true + } + } + }, navigateToModifyScreen = {storeId -> navController.navigate(StoreRoute.MODIFY_INFO.name) }, diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailScreen.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailScreen.kt index 9d94b6f5f..3a8670f49 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailScreen.kt @@ -44,6 +44,7 @@ import androidx.compose.ui.zIndex import `in`.koreatech.business.R import `in`.koreatech.business.feature.store.OwnerStoreAppBar import `in`.koreatech.business.feature.store.modifyinfo.ModifyInfoViewModel +import `in`.koreatech.business.feature.store.storedetail.dialog.DeleteUserDialog import `in`.koreatech.business.feature.store.storedetail.dialog.MyStoreSelectDialog import `in`.koreatech.business.feature.store.storedetail.event.EventScreen import `in`.koreatech.business.feature.store.storedetail.menu.MenuScreen @@ -84,7 +85,15 @@ fun MyStoreDetailScreen( Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { - OwnerStoreAppBar(stringResource(R.string.my_shop)) + OwnerStoreAppBar( + stringResource(R.string.my_shop), + viewModel::showDeleteUserDialog + ) + DeleteUserDialog( + onClickCancel = viewModel::closeDeleteUserDialog, + deleteUser = viewModel::deleteUser, + dialogVisibility = state.deleteUserDialogVisibility, + ) MyStoreSelectDialog( dialogVisibility = state.selectDialogVisibility, storeList = state.storeList, @@ -131,6 +140,11 @@ fun MyStoreDetailScreen( context.getString(R.string.error_modify_event) ) + MyStoreDetailSideEffect.DeleteUser -> { + ToastUtil.getInstance().makeShort(context.getString(R.string.delete_user_success)) + navigateToLoginScreen() + } + } } } diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailSideEffect.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailSideEffect.kt index 520d118d4..c578967f4 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailSideEffect.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailSideEffect.kt @@ -11,4 +11,6 @@ sealed class MyStoreDetailSideEffect { data object NavigateToRegisterStoreScreen : MyStoreDetailSideEffect() data class ShowErrorMessage(val errorMessage: String) : MyStoreDetailSideEffect() data object ShowErrorModifyEventToast : MyStoreDetailSideEffect() + + data object DeleteUser : MyStoreDetailSideEffect() } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt index c9daf89a8..8e583edb0 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt @@ -14,6 +14,7 @@ data class MyStoreDetailState( val storeMenu: ImmutableList? = null, val dialogVisibility: Boolean = false, val selectDialogVisibility: Boolean = false, + val deleteUserDialogVisibility: Boolean = false, val isEventExpanded: List = List(storeEvent?.size ?: 0) { false }, val isAllEventSelected: Boolean = false, val isSelectedEvent: MutableList = mutableListOf(), diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailViewModel.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailViewModel.kt index 40d367360..2a7b494b4 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailViewModel.kt @@ -10,6 +10,7 @@ import `in`.koreatech.koin.domain.usecase.business.GetOwnerShopEventsUseCase import `in`.koreatech.koin.domain.usecase.business.GetOwnerShopInfoUseCase import `in`.koreatech.koin.domain.usecase.business.GetOwnerShopListUseCase import `in`.koreatech.koin.domain.usecase.business.GetOwnerShopMenusUseCase +import `in`.koreatech.koin.domain.usecase.user.UserRemoveUseCase import `in`.koreatech.koin.domain.util.onFailure import `in`.koreatech.koin.domain.util.onSuccess import kotlinx.collections.immutable.toImmutableList @@ -28,6 +29,7 @@ class MyStoreDetailViewModel @Inject constructor( private val getOwnerShopEventsUseCase: GetOwnerShopEventsUseCase, private val getOwnerShopMenusUseCase: GetOwnerShopMenusUseCase, private val deleteOwnerShopEventsUseCase: DeleteOwnerEventsUseCase, + private val userRemoveUseCase: UserRemoveUseCase ) : ContainerHost, ViewModel() { override val container = container(MyStoreDetailState()) @@ -224,6 +226,22 @@ class MyStoreDetailViewModel @Inject constructor( } } + fun showDeleteUserDialog() = intent{ + reduce { + state.copy( + deleteUserDialogVisibility = true + ) + } + } + + fun closeDeleteUserDialog() = intent{ + reduce { + state.copy( + deleteUserDialogVisibility = false + ) + } + } + fun navigateToModifyScreen() = intent { if (state.storeId == -1) return@intent postSideEffect(MyStoreDetailSideEffect.NavigateToModifyScreen(state.storeId)) @@ -286,4 +304,18 @@ class MyStoreDetailViewModel @Inject constructor( ) } } + + fun deleteUser() { + intent{ + viewModelScope.launch { + userRemoveUseCase() + .onSuccess { + postSideEffect(MyStoreDetailSideEffect.DeleteUser) + } + .onFailure { errorHandler -> + postSideEffect(MyStoreDetailSideEffect.ShowErrorMessage(errorHandler.message)) + } + } + } + } } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/DeleteUserDialog.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/DeleteUserDialog.kt new file mode 100644 index 000000000..b082fa65f --- /dev/null +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/DeleteUserDialog.kt @@ -0,0 +1,138 @@ +package `in`.koreatech.business.feature.store.storedetail.dialog + + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import `in`.koreatech.business.R +import `in`.koreatech.koin.domain.model.store.Store + +@Composable +fun DeleteUserDialog( + onClickCancel: () -> Unit = {}, + deleteUser: () -> Unit = {}, + dialogVisibility: Boolean = true, +) { + if(dialogVisibility){ + Dialog( + onDismissRequest = { onClickCancel() }, + properties = DialogProperties( + dismissOnBackPress = true, + dismissOnClickOutside = true, + ) + ) { + Card( + shape = RoundedCornerShape( + topStart = 20.dp, + topEnd = 20.dp, + bottomStart = 20.dp, + bottomEnd = 20.dp + ), + ) + { + Column( + modifier = Modifier + .width(300.dp) + .wrapContentHeight(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = Modifier + .padding(top = 16.dp) + .fillMaxWidth() + ) { + Image( + painter = painterResource(R.drawable.ic_x), + contentDescription = "", + modifier = Modifier + .align(Alignment.TopEnd) + .padding(end = 16.dp) + .clickable { + onClickCancel() + } + ) + } + + Text( + text = stringResource(id = R.string.delete_user), + textAlign = TextAlign.Center, + color = Color.Black, + fontSize = 18.sp, + fontWeight = FontWeight.Bold + ) + + Text( + modifier = Modifier.padding(top = 5.dp), + text = stringResource(id = R.string.delete_user_detail), + textAlign = TextAlign.Center, + color = Color.Black, + fontSize = 15.sp + ) + + Row( + modifier = Modifier + .padding(top = 35.dp) + .padding(horizontal = 40.dp) + .fillMaxWidth() + , + horizontalArrangement = Arrangement.spacedBy(10.dp) + ){ + Button( + modifier = Modifier.weight(1F), + onClick = { + onClickCancel() + } + ) { + Text(text = stringResource(id = R.string.cancel)) + } + + Button( + modifier = Modifier.weight(1F), + onClick = { + onClickCancel() + deleteUser() + } + ) { + Text(text = stringResource(id = R.string.check)) + } + } + + } + } + } + } +} + +@Preview +@Composable +private fun PreviewDeleteUserDialog() { + DeleteUserDialog() +} \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/MyStoreSelectDialog.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/MyStoreSelectDialog.kt index 2906696fa..cb9218fd6 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/MyStoreSelectDialog.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/dialog/MyStoreSelectDialog.kt @@ -1,16 +1,9 @@ package `in`.koreatech.business.feature.store.storedetail.dialog -import android.util.Log -import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn @@ -18,18 +11,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.AlertDialog -import androidx.compose.material.Button -import androidx.compose.material.ButtonDefaults import androidx.compose.material.Card import androidx.compose.material.Text -import androidx.compose.material.TextButton import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -43,9 +29,6 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import `in`.koreatech.business.R -import `in`.koreatech.business.ui.theme.ColorActiveButton -import `in`.koreatech.business.ui.theme.ColorDisabledButton -import `in`.koreatech.business.ui.theme.ColorMinor import `in`.koreatech.koin.domain.model.store.Store @Composable diff --git a/business/src/main/res/values/strings.xml b/business/src/main/res/values/strings.xml index 759c64975..0e19cd398 100644 --- a/business/src/main/res/values/strings.xml +++ b/business/src/main/res/values/strings.xml @@ -183,4 +183,7 @@ 상점 선택 상점 추가 메뉴 추가 + 회원 탈퇴 + 현재 로그인 되어 있는 계정을\n 탈퇴하시겠습니까? + 탈퇴가 완료되었습니다. diff --git a/data/src/main/java/in/koreatech/koin/data/repository/OwnerRegisterRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/OwnerRegisterRepositoryImpl.kt index aee24239c..d24e0135a 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/OwnerRegisterRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/OwnerRegisterRepositoryImpl.kt @@ -16,6 +16,7 @@ import `in`.koreatech.koin.domain.model.owner.OwnerRegisterUrl import `in`.koreatech.koin.domain.model.owner.insertstore.OperatingTime import `in`.koreatech.koin.domain.model.owner.menu.StoreMenuOptionPrice import `in`.koreatech.koin.domain.repository.OwnerRegisterRepository +import `in`.koreatech.koin.domain.util.ext.toSHA256 import kotlinx.coroutines.CancellationException import retrofit2.HttpException import java.io.EOFException @@ -40,7 +41,7 @@ class OwnerRegisterRepositoryImpl( companyNumber, email, name, - password, + password.toSHA256(), phoneNumber, shopId, shopName @@ -71,7 +72,7 @@ class OwnerRegisterRepositoryImpl( attachments.toFileUrlList(), companyNumber, name, - password, + password.toSHA256(), phoneNumber, shopId, shopName From 8e07ec0db2ce080096d3af37fe4fb5609366fdd4 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 16:32:40 +0900 Subject: [PATCH 059/138] =?UTF-8?q?[add]=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=8B=9C=20=EC=A4=91=EB=B3=B5=20=EC=B6=94=EA=B0=80=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EB=A1=9C=EC=A7=81=20=EC=A4=80=EB=B9=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/viewmodel/TimetableViewModel.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt index df3588297..95dfe1dc3 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt @@ -246,6 +246,22 @@ class TimetableViewModel @Inject constructor( } false -> { // TODO : 로그인 시 중복에 대한 강의 추가 + val ids = mutableListOf() + uiState.value.duplicationLecture?.classTime?.forEach { time -> + uiState.value.timetableLectures.timetable.filter { it.classTime.contains(time) } + .forEach { lecture -> + ids.add(lecture.id) + } + } + // TODO : ids 요청 쿼리 파라미터로 삭제 API 연결 +// deleteTimetableLecturesUseCase(ids).onSuccess { + // TODO : 삭제 후, duplicationLecture 강의 추가 API 연결 +// uiState.value.duplicationLecture?.let { lecture -> +// addTimetableLectures(lecture) +// } ?: return@onSuccess +// }.onFailure { +// } + } } } From ab661df3753de2ee400cda3e1bffe0ec858ac76f Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Tue, 5 Nov 2024 16:42:48 +0900 Subject: [PATCH 060/138] =?UTF-8?q?fix:=20=EB=9D=84=EC=96=B4=EC=93=B0?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/business/feature/store/OwnerStoreAppBar.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt b/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt index 390b5a54e..7181158fe 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/OwnerStoreAppBar.kt @@ -34,15 +34,12 @@ fun OwnerStoreAppBar( modifier = Modifier.align(Alignment.Center), style = TextStyle(color = Color.White, fontSize = 18.sp), ) - IconButton( modifier = Modifier - .align(Alignment.BottomEnd) - , + .align(Alignment.BottomEnd), onClick = { showDeleteUserDialog() } - ) { Image( painter = painterResource(id = R.drawable.ic_delete), From d2be18a3525f721e74e1084665f3444cace27ff3 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 16:44:22 +0900 Subject: [PATCH 061/138] =?UTF-8?q?[add]=20contentPadding=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/section/TimetableBottomSheetBasic.kt | 5 ++++- .../feature/timetable/section/TimetableBottomSheetCustom.kt | 4 +++- .../koin/feature/timetable/view/TimetableBottomSheet.kt | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt index 7792e27d4..2dced1ad7 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetBasic.kt @@ -2,6 +2,7 @@ package `in`.koreatech.koin.feature.timetable.section import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.HorizontalDivider @@ -44,7 +45,9 @@ fun TimetableBottomSheetBasic( onClickSettingIcon = onClickSettingIcon ) HorizontalDivider(thickness = 2.dp, color = KoinTheme.colors.neutral300) - LazyColumn { + LazyColumn( + contentPadding = PaddingValues(bottom = 16.dp) + ) { items(lectures.size) { LectureBox( position = it, diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt index bcdce7280..78765e3da 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt @@ -1,5 +1,6 @@ package `in`.koreatech.koin.feature.timetable.section +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyColumn @@ -20,7 +21,8 @@ fun TimetableBottomSheetCustom( val events: SnapshotStateList = remember { mutableStateListOf() } LazyColumn( - modifier = modifier + modifier = modifier, + contentPadding = PaddingValues(bottom = 16.dp) ) { item { BottomSheetCustomContent( diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt index fa30fa091..2ce7d5516 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt @@ -70,8 +70,9 @@ fun TimetableBottomSheet( onBottomSheetHeightChange(it.size.height.toFloat()) } .padding( - horizontal = 24.dp, - vertical = 10.dp + start = 24.dp, + end = 24.dp, + top = 10.dp ), ) { TimetableBottomSheetHeader( From 6a937062f426b0c560170f0fd862d3ec7a6f3af2 Mon Sep 17 00:00:00 2001 From: nazero Date: Tue, 5 Nov 2024 17:09:44 +0900 Subject: [PATCH 062/138] =?UTF-8?q?fix:=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../changepassword/ChangePasswordViewModel.kt | 2 +- .../PasswordAuthenticationScreen.kt | 4 +- .../signup/accountsetup/AccountSetupScreen.kt | 5 +- .../signup/businessauth/BusinessAuthScreen.kt | 515 ++++++++---------- .../businessauth/BusinessAuthViewModel.kt | 42 +- .../signup/checkterm/CheckTermScreen.kt | 2 + .../completesignup/CompleteSignupScreen.kt | 2 + .../store/storedetail/MyStoreDetailState.kt | 2 + .../store/storedetail/event/EventItem.kt | 16 +- .../store/storedetail/menu/MenuScreen.kt | 4 +- business/src/main/res/values/strings.xml | 3 +- .../koreatech/koin/data/mapper/UserMapper.kt | 7 + .../usecase/owner/OwnerRegisterUseCase.kt | 3 +- 13 files changed, 295 insertions(+), 312 deletions(-) diff --git a/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordViewModel.kt b/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordViewModel.kt index 60a919a70..ac056b984 100644 --- a/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordViewModel.kt @@ -52,7 +52,7 @@ class ChangePasswordViewModel @Inject constructor( fillAllPasswords() } - fun insertPasswordChecked(passwordChecked: String) = intent{ + fun insertPasswordChecked(passwordChecked: String) = blockingIntent{ reduce { state.copy(passwordChecked = passwordChecked) } coincidePasswordReset() fillAllPasswords() diff --git a/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt b/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt index f0c4a5185..ad23e3fd6 100644 --- a/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt @@ -208,7 +208,7 @@ fun PasswordAuthenticationScreen( horizontalArrangement = Arrangement.SpaceBetween, ) { LinedTextField( - modifier = Modifier.widthIn(max = 230.dp), + modifier = Modifier.widthIn(max = 220.dp), value = authCode, onValueChange = insertAuthCode, label = stringResource(R.string.input_auth_code), @@ -222,7 +222,7 @@ fun PasswordAuthenticationScreen( ColorAccent ) else buttonColors(ColorPrimary), modifier = modifier - .width(124.dp) + .width(135.dp) .height(41.dp) .clickableOnce { } ) { diff --git a/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt b/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt index f6ce1f4ea..5eaf685a4 100644 --- a/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signup/accountsetup/AccountSetupScreen.kt @@ -179,7 +179,7 @@ fun AccountSetupScreen( .width(115.dp) .height(41.dp), shape = RoundedCornerShape(4.dp), - enabled = state.phoneNumber.isNotEmpty() && state.phoneNumberState !is SignupContinuationState.RequestedSmsValidation, + enabled = state.phoneNumber.isNotEmpty(), colors = ButtonDefaults.buttonColors( backgroundColor = if(state.sendCodeError == null) ColorPrimary else ColorSecondary, contentColor = Color.White, @@ -189,7 +189,7 @@ fun AccountSetupScreen( onClick = viewModel::checkExistsAccount ) { Text( - text = stringResource(id = R.string.send_authentication_code), + text = if(state.phoneNumberState is SignupContinuationState.RequestedSmsValidation) stringResource(id = R.string.resend_authentication_code) else stringResource(id = R.string.send_authentication_code), fontWeight = Bold, fontSize = 13.sp, ) @@ -302,6 +302,7 @@ fun AccountSetupScreen( fontWeight = Bold, ) } + Spacer(modifier = Modifier.height(20.dp)) } } diff --git a/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthScreen.kt b/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthScreen.kt index 104170ef0..d8c528ef5 100644 --- a/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthScreen.kt @@ -1,6 +1,5 @@ package `in`.koreatech.business.feature.signup.businessauth -import android.provider.OpenableColumns import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts @@ -30,6 +29,7 @@ import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -48,7 +48,6 @@ import `in`.koreatech.business.R import `in`.koreatech.business.feature.signup.accountsetup.AccountSetupViewModel import `in`.koreatech.business.feature.signup.dialog.BusinessAlertDialog import `in`.koreatech.business.feature.textfield.LinedTextField -import `in`.koreatech.business.ui.theme.ColorDescription import `in`.koreatech.business.ui.theme.ColorDisabledButton import `in`.koreatech.business.ui.theme.ColorMinor import `in`.koreatech.business.ui.theme.ColorPrimary @@ -58,6 +57,7 @@ import `in`.koreatech.business.ui.theme.Gray1 import `in`.koreatech.business.ui.theme.Gray3 import `in`.koreatech.koin.domain.model.store.AttachStore import `in`.koreatech.koin.domain.state.signup.SignupContinuationState +import kotlinx.coroutines.CoroutineScope import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @@ -67,6 +67,7 @@ fun BusinessAuthScreen( accountSetupViewModel: AccountSetupViewModel = hiltViewModel(), businessAuthViewModel: BusinessAuthViewModel = hiltViewModel(), scrollState: ScrollState = rememberScrollState(), + coroutineScope: CoroutineScope = rememberCoroutineScope(), onBackClicked: () -> Unit = {}, onSearchClicked: () -> Unit = {}, onNextClicked: () -> Unit = {}, @@ -77,317 +78,284 @@ fun BusinessAuthScreen( val multiplePhotoPickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickMultipleVisualMedia(5), onResult = { - businessAuthViewModel.changeImageUri(it) - /* var fileName = "" - var fileSize = 0L - businessAuthState.fileInfo.clear() - businessAuthViewModel.initStoreImageUrls() - uriList.forEach { - val inputStream = context.contentResolver.openInputStream(it) - businessAuthViewModel.onImageUrlsChanged(mutableListOf()) - if (it.scheme.equals("content")) { - val cursor = context.contentResolver.query(it, null, null, null, null) - cursor.use { - if (cursor != null && cursor.moveToFirst()) { - val fileNameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) - val fileSizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE) - - if (fileNameIndex != -1 && fileSizeIndex != -1) { - fileName = cursor.getString(fileNameIndex) - fileSize = cursor.getLong(fileSizeIndex) - } - } - } - } - if (inputStream != null) { - businessAuthViewModel.getPreSignedUrl( - fileName = fileName, - fileSize = fileSize, - fileType = "image/" + fileName.split(".")[1], - imageUri = it.toString() - ) - - } - inputStream?.close() - }*/ + businessAuthViewModel.changeImageUri( + context, + accountSetupState.phoneNumber, + accountSetupState.password, + it + ) } ) Column( - modifier = modifier.fillMaxSize(), + modifier = modifier + .fillMaxSize() + .padding(top = 12.dp), ) { - Column { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 12.dp) + + Box( + modifier = Modifier + .fillMaxWidth() + ) { + IconButton( + onClick = businessAuthViewModel::onNavigateToBackScreen, + modifier = Modifier.align(Alignment.CenterStart) ) { - IconButton( - onClick = { businessAuthViewModel.onNavigateToBackScreen() }, - modifier = Modifier.align(Alignment.CenterStart) - ) { - Icon( - painter = painterResource(id = R.drawable.ic_back), - contentDescription = stringResource(id = R.string.back_icon), - ) - } + Icon( + painter = painterResource(id = R.drawable.ic_back), + contentDescription = stringResource(id = R.string.back_icon), + ) + } + Text( + text = stringResource(id = R.string.sign_up), + fontSize = 18.sp, + fontWeight = Bold, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.height(20.dp)) + + Column( + modifier = Modifier + .padding(horizontal = 24.dp), + verticalArrangement = Arrangement.Center, + ) { + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + modifier = Modifier, + color = ColorPrimary, + fontWeight = Bold, + text = stringResource(id = R.string.business_auth) + ) Text( - text = stringResource(id = R.string.sign_up), - fontSize = 18.sp, + text = stringResource(id = R.string.three_third), + color = ColorPrimary, fontWeight = Bold, - modifier = Modifier.align(Alignment.Center) ) } - Spacer(modifier = Modifier.height(20.dp)) - - Column( + Canvas( modifier = Modifier - .padding(horizontal = 24.dp), - verticalArrangement = Arrangement.Center, + .fillMaxWidth() + .padding(16.dp) ) { - Row( - modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Text( - modifier = Modifier, - color = ColorPrimary, - fontWeight = Bold, - text = stringResource(id = R.string.business_auth) - ) - Text( - text = stringResource(id = R.string.three_third), - color = ColorPrimary, - fontWeight = Bold, - ) - } - - Canvas( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - ) { - drawLine( - color = ColorUnarchived, - start = Offset(-40f, 0f), - end = Offset(size.width + 35, size.height), - strokeWidth = 4.dp.toPx(), - cap = StrokeCap.Round - ) - drawLine( - color = ColorPrimary, - start = Offset(-40f, 0f), - end = Offset(size.width + 40, size.height), - strokeWidth = 4.dp.toPx(), - cap = StrokeCap.Round - ) - } + drawLine( + color = ColorUnarchived, + start = Offset(-40f, 0f), + end = Offset(size.width + 35, size.height), + strokeWidth = 4.dp.toPx(), + cap = StrokeCap.Round + ) + drawLine( + color = ColorPrimary, + start = Offset(-40f, 0f), + end = Offset(size.width + 40, size.height), + strokeWidth = 4.dp.toPx(), + cap = StrokeCap.Round + ) } } - Spacer(modifier = Modifier.height(20.dp)) Column( modifier = Modifier - .padding(horizontal = 24.dp) + .fillMaxSize() + .padding(start = 24.dp, end = 24.dp, top = 32.dp, bottom = 24.dp) .verticalScroll(scrollState), verticalArrangement = Arrangement.Center, ) { - Spacer(modifier = Modifier.height(10.dp)) - - Column { - + Text( + text = stringResource(id = R.string.master_name), + fontSize = 14.sp, + fontWeight = Bold + ) + LinedTextField( + value = businessAuthState.name, + onValueChange = { businessAuthViewModel.onNameChanged(it) }, + label = stringResource(id = R.string.enter_name) + ) + Text( + text = stringResource(id = R.string.shop_name), + fontSize = 14.sp, + fontWeight = Bold + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Top, + ) { - Text( - text = stringResource(id = R.string.master_name), - fontSize = 14.sp, - fontWeight = Bold - ) LinedTextField( - value = businessAuthState.name, - onValueChange = { businessAuthViewModel.onNameChanged(it) }, - label = stringResource(id = R.string.enter_name) + modifier = Modifier.width(197.dp), + value = businessAuthState.shopName, + onValueChange = { + businessAuthViewModel.onShopNameChanged(it) + businessAuthViewModel.onShopIdChanged(null) + }, + label = stringResource(id = R.string.enter_store_name) ) - Text( - text = stringResource(id = R.string.shop_name), - fontSize = 14.sp, - fontWeight = Bold - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Top, - ) { + Button(modifier = Modifier + .height(41.dp), + shape = RoundedCornerShape(4.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = ColorPrimary, + contentColor = Color.White, + ), + onClick = { + businessAuthViewModel.onNavigateToSearchStore() + }) { + Text(text = stringResource(id = R.string.search_store)) + } + } + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = stringResource(id = R.string.business_registration_number), + fontSize = 14.sp, + fontWeight = Bold + ) + LinedTextField( + value = businessAuthState.shopNumber, + onValueChange = { + businessAuthViewModel.onStoreNumberChanged(it) + businessAuthViewModel.storeNumberCheck() + }, + label = stringResource(id = R.string.enter_business_registration_number), + isError = businessAuthState.signupContinuationState == SignupContinuationState.BusinessNumberIsNotValidate || + businessAuthState.signupContinuationState is SignupContinuationState.Failed, + errorText = if (businessAuthState.signupContinuationState is SignupContinuationState.Failed) + businessAuthState.signupContinuationState.message + else stringResource(id = R.string.business_number_not_validate) + ) + Spacer(modifier = Modifier.height(10.dp)) - LinedTextField( - modifier = Modifier.width(197.dp), - value = businessAuthState.shopName, - onValueChange = { - businessAuthViewModel.onShopNameChanged(it) - businessAuthViewModel.onShopIdChanged(null) - }, - label = stringResource(id = R.string.enter_store_name) - ) + Text( + text = stringResource(id = R.string.instruction_file), + fontSize = 14.sp, + fontWeight = Bold + ) - Button(modifier = Modifier - .height(41.dp), - shape = RoundedCornerShape(4.dp), - colors = ButtonDefaults.buttonColors( - backgroundColor = ColorPrimary, - contentColor = Color.White, - ), - onClick = { - businessAuthViewModel.onNavigateToSearchStore() - }) { - Text(text = stringResource(id = R.string.search_store)) + if (businessAuthState.selectedImages.isNotEmpty()) { + UploadFileList( + modifier, + businessAuthState.selectedImages, + ) { + val list = mutableListOf() + businessAuthState.selectedImages.forEach { + list.add(it.title) } + list.removeAt(it) + businessAuthViewModel.onImageUrlsChanged( + list.map { + AttachStore( + it, + it + ) + }.toMutableList() + ) } - Spacer(modifier = Modifier.height(20.dp)) - Text( - text = stringResource(id = R.string.business_registration_number), - fontSize = 14.sp, - fontWeight = Bold - ) - LinedTextField( - value = businessAuthState.shopNumber, - onValueChange = { businessAuthViewModel.onStoreNumberChanged(it) }, - label = stringResource(id = R.string.enter_business_registration_number), - isError = businessAuthState.signupContinuationState == SignupContinuationState.BusinessNumberIsNotValidate || - businessAuthState.signupContinuationState is SignupContinuationState.Failed, - errorText = if (businessAuthState.signupContinuationState is SignupContinuationState.Failed) - businessAuthState.signupContinuationState.message - else stringResource(id = R.string.business_number_not_validate) - ) - Spacer(modifier = Modifier.height(10.dp)) + } - Text( - text = stringResource(id = R.string.instruction_file), - fontSize = 14.sp, - fontWeight = Bold + Button( + modifier = Modifier + .fillMaxWidth() + .height(44.dp), + shape = RectangleShape, + enabled = businessAuthState.selectedImages.isEmpty(), + colors = ButtonDefaults.buttonColors( + backgroundColor = ColorTextField, + contentColor = Gray1, + disabledBackgroundColor = ColorTextField, + disabledContentColor = Gray3, + ), + onClick = { businessAuthViewModel.onDialogVisibilityChanged(true) }) { + Icon( + painter = painterResource(id = R.drawable.attach_file_add), + contentDescription = stringResource(id = R.string.attach_file) ) Text( - text = stringResource(id = R.string.file_upload_instruction), - fontSize = 12.sp, - color = ColorDescription + modifier = Modifier.padding(start = 8.dp), + text = stringResource(id = R.string.file_upload), + color = if (businessAuthState.selectedImages.isEmpty()) Gray1 else Gray3, + fontSize = 13.sp, + fontWeight = Bold, ) - Column( - modifier = Modifier - .fillMaxWidth(), - ) { - - if (businessAuthState.selectedImages.isNotEmpty()) { - UploadFileList( - modifier, - businessAuthState.selectedImages, - ) { - val list = mutableListOf() - businessAuthState.selectedImages.forEach { - list.add(it.title) - } - list.removeAt(it) - businessAuthViewModel.onImageUrlsChanged( - list.map { - AttachStore( - it, - it - ) - }.toMutableList() - ) - } - Spacer(modifier = Modifier.height(10.dp)) - } - - Button( - modifier = Modifier - .fillMaxWidth() - .height(44.dp), - shape = RectangleShape, - enabled = businessAuthState.selectedImages.isEmpty(), - colors = ButtonDefaults.buttonColors( - backgroundColor = ColorTextField, - contentColor = Gray1, - disabledBackgroundColor = ColorTextField, - disabledContentColor = Gray3, - ), - onClick = { businessAuthViewModel.onDialogVisibilityChanged(true) }) { - Icon( - painter = painterResource(id = R.drawable.attach_file_add), - contentDescription = stringResource(id = R.string.attach_file) - ) - Text( - modifier = Modifier.padding(start = 8.dp), - text = stringResource(id = R.string.file_upload), - fontSize = 13.sp, - fontWeight = Bold, - color = Gray1, - ) - } - } + } - Spacer(modifier = Modifier.height(60.dp)) - Button(modifier = Modifier - .fillMaxWidth() - .height(44.dp), - shape = RoundedCornerShape(4.dp), - enabled = businessAuthState.isButtonEnabled, - colors = ButtonDefaults.buttonColors( - backgroundColor = ColorPrimary, - disabledBackgroundColor = ColorDisabledButton, - contentColor = Color.White, - disabledContentColor = Color.White, - ), + Spacer(modifier = Modifier.weight(1f)) + Button(modifier = Modifier + .fillMaxWidth() + .height(44.dp), + shape = RoundedCornerShape(4.dp), + enabled = businessAuthState.isButtonEnabled, + colors = ButtonDefaults.buttonColors( + backgroundColor = ColorPrimary, + disabledBackgroundColor = ColorDisabledButton, + contentColor = Color.White, + disabledContentColor = Color.White, + ), - onClick = { - businessAuthViewModel.onPositiveButtonClicked(context, - phoneNumber = accountSetupState.phoneNumber, - password = accountSetupState.password - ) - }) { - Text( - text = stringResource(id = R.string.next), - fontSize = 15.sp, - color = Color.White, + onClick = { + businessAuthViewModel.sendRegisterRequest( + fileUrls = businessAuthState.fileInfo.map { it.resultUrl }, + companyNumber = businessAuthState.shopNumber, + phoneNumber = accountSetupState.phoneNumber, + name = businessAuthState.name, + password = accountSetupState.password, + shopId = businessAuthState.shopId, + shopName = businessAuthState.shopName, ) + }) { + Text( + text = stringResource(id = R.string.next), + fontSize = 15.sp, + color = Color.White, + ) - BusinessAlertDialog( - onDismissRequest = { businessAuthViewModel.onDialogVisibilityChanged(false) }, - onConfirmation = { - multiplePhotoPickerLauncher.launch( - PickVisualMediaRequest( - ActivityResultContracts.PickVisualMedia.ImageOnly - ) + BusinessAlertDialog( + onDismissRequest = { businessAuthViewModel.onDialogVisibilityChanged(false) }, + onConfirmation = { + multiplePhotoPickerLauncher.launch( + PickVisualMediaRequest( + ActivityResultContracts.PickVisualMedia.ImageOnly ) - businessAuthViewModel.onDialogVisibilityChanged(false) - }, - dialogTitle = stringResource(id = R.string.file_upload), - dialogText = stringResource(id = R.string.file_upload_requirements), - positiveButtonText = stringResource(id = R.string.select_file), - visibility = businessAuthState.dialogVisibility - ) - } + ) + businessAuthViewModel.onDialogVisibilityChanged(false) + }, + dialogTitle = stringResource(id = R.string.file_upload), + dialogText = stringResource(id = R.string.file_upload_requirements), + positiveButtonText = stringResource(id = R.string.select_file), + visibility = businessAuthState.dialogVisibility + ) } + Spacer(modifier = Modifier.height(20.dp)) + } - businessAuthViewModel.collectSideEffect { - when (it) { - BusinessAuthSideEffect.NavigateToSearchStore -> { - onSearchClicked() - } - BusinessAuthSideEffect.NavigateToBackScreen -> { - onBackClicked() - } + } + businessAuthViewModel.collectSideEffect { + when (it) { + BusinessAuthSideEffect.NavigateToSearchStore -> { + onSearchClicked() + } - BusinessAuthSideEffect.NavigateToNextScreen -> { - onNextClicked() - } + BusinessAuthSideEffect.NavigateToBackScreen -> { + onBackClicked() } + BusinessAuthSideEffect.NavigateToNextScreen -> { + onNextClicked() + } } + } + } @Composable @@ -397,12 +365,10 @@ fun UploadFileList( onDelete: (Int) -> Unit = {} ) { Column(modifier = Modifier.height(fileList.size * 40.dp)) { - LazyColumn( - modifier = modifier - .fillMaxSize(), + modifier = Modifier.fillMaxWidth(), ) { - items(fileList.size) { + items(fileList.size) { index -> Row( modifier = Modifier .fillMaxWidth() @@ -410,19 +376,20 @@ fun UploadFileList( .padding(6.dp), verticalAlignment = Alignment.CenterVertically, ) { - Image( modifier = Modifier .size(24.dp) - .clickable { - onDelete(it) - } + .clickable { onDelete(index) } .padding(end = 8.dp), painter = painterResource(id = R.drawable.ic_delete_button), contentDescription = stringResource(id = R.string.file_icon), ) - Text(text = fileList[it].title, fontSize = 15.sp, color = ColorMinor) + Text( + text = fileList[index].title, + fontSize = 15.sp, + color = ColorMinor + ) } Spacer(modifier = Modifier.width(12.dp)) } diff --git a/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthViewModel.kt b/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthViewModel.kt index 1e3cb8e25..9eedb8942 100644 --- a/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthViewModel.kt +++ b/business/src/main/java/in/koreatech/business/feature/signup/businessauth/BusinessAuthViewModel.kt @@ -12,7 +12,6 @@ import `in`.koreatech.business.feature.storemenu.modifymenu.modifymenu.toStringL import `in`.koreatech.business.util.getImageInfo import `in`.koreatech.koin.data.mapper.strToOwnerRegisterUrl import `in`.koreatech.koin.domain.constant.SIGN_UP_IMAGE_MAX -import `in`.koreatech.koin.domain.constant.STORE_MENU_IMAGE_MAX import `in`.koreatech.koin.domain.model.store.AttachStore import `in`.koreatech.koin.domain.model.store.StoreUrl import `in`.koreatech.koin.domain.state.signup.SignupContinuationState @@ -61,8 +60,15 @@ class BusinessAuthViewModel @Inject constructor( fun onStoreNumberChanged(storeNumber: String) = blockingIntent { reduce { state.copy( - shopNumber = storeNumber, - signupContinuationState = if (storeNumber.length != 10) SignupContinuationState.BusinessNumberIsNotValidate + shopNumber = if (storeNumber.length <=10) storeNumber else state.shopNumber, + ) + } + } + + fun storeNumberCheck() = intent { + reduce { + state.copy( + signupContinuationState = if (state.shopNumber.length != 10) SignupContinuationState.BusinessNumberIsNotValidate else SignupContinuationState.RequestedSmsValidation ) } @@ -92,32 +98,35 @@ class BusinessAuthViewModel @Inject constructor( postSideEffect(BusinessAuthSideEffect.NavigateToNextScreen) } - fun changeImageUri(uriList: List){ + fun changeImageUri(context: Context, phoneNumber: String, password: String, uriList: List) { intent { reduce { - if(uriList.size < SIGN_UP_IMAGE_MAX){ + if (uriList.size <= SIGN_UP_IMAGE_MAX) { val newMenuUriList = state.imageUriList.toMutableList() - for(imageUri in uriList) { + for (imageUri in uriList) { newMenuUriList.add(imageUri.toString()) - insertStoreFileUrl(imageUri.toString().substringAfterLast("/"), imageUri.toString()) + insertStoreFileUrl( + imageUri.toString().substringAfterLast("/"), + imageUri.toString() + ) } - if(newMenuUriList.size != SIGN_UP_IMAGE_MAX)newMenuUriList.add(ImageHolder.TempUri.toString()) + if (newMenuUriList.size <= SIGN_UP_IMAGE_MAX) newMenuUriList.add(ImageHolder.TempUri.toString()) state.copy( imageUriList = newMenuUriList ) - } - else{ + } else { state.copy( imageUriList = uriList.toStringList() ) } } + uploadImageList(context) } } - fun onPositiveButtonClicked(context: Context, phoneNumber: String, password: String) { + private fun uploadImageList(context: Context) { intent { viewModelScope.launch { state.imageUriList.forEach { uriString -> @@ -134,15 +143,6 @@ class BusinessAuthViewModel @Inject constructor( } } } - sendRegisterRequest( - fileUrls = state.fileInfo.map { it.resultUrl }, - companyNumber = state.shopNumber, - phoneNumber = phoneNumber, - name = state.name, - password = password, - shopId = state.shopId, - shopName = state.shopName, - ) } } } @@ -216,7 +216,7 @@ class BusinessAuthViewModel @Inject constructor( } } - private fun sendRegisterRequest( + fun sendRegisterRequest( fileUrls: List, companyNumber: String, phoneNumber: String, diff --git a/business/src/main/java/in/koreatech/business/feature/signup/checkterm/CheckTermScreen.kt b/business/src/main/java/in/koreatech/business/feature/signup/checkterm/CheckTermScreen.kt index 9d4f69bfa..5190b66cd 100644 --- a/business/src/main/java/in/koreatech/business/feature/signup/checkterm/CheckTermScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signup/checkterm/CheckTermScreen.kt @@ -277,6 +277,8 @@ fun CheckTermScreen( ) { Text(text = stringResource(R.string.next)) } + Spacer(modifier = Modifier.height(20.dp)) + } } diff --git a/business/src/main/java/in/koreatech/business/feature/signup/completesignup/CompleteSignupScreen.kt b/business/src/main/java/in/koreatech/business/feature/signup/completesignup/CompleteSignupScreen.kt index 03cc47689..19038c584 100644 --- a/business/src/main/java/in/koreatech/business/feature/signup/completesignup/CompleteSignupScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/signup/completesignup/CompleteSignupScreen.kt @@ -170,6 +170,8 @@ fun CompleteSignupScreen( ) } + Spacer(modifier = Modifier.height(20.dp)) + } viewModel.collectSideEffect { diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt index c9daf89a8..491a23bc3 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/MyStoreDetailState.kt @@ -1,11 +1,13 @@ package `in`.koreatech.business.feature.store.storedetail +import androidx.compose.runtime.Immutable import `in`.koreatech.koin.domain.model.owner.StoreDetailInfo import `in`.koreatech.koin.domain.model.store.ShopEvent import `in`.koreatech.koin.domain.model.store.Store import `in`.koreatech.koin.domain.model.store.StoreMenuCategories import kotlinx.collections.immutable.ImmutableList +@Immutable data class MyStoreDetailState( val storeList: List = mutableListOf(), val storeInfo: StoreDetailInfo? = null, diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventItem.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventItem.kt index 715291a06..bad4986bf 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventItem.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventItem.kt @@ -67,7 +67,7 @@ fun EventItem( StoreUtil.generateOpenCloseTimeString(item.startDate, item.endDate) } val pagerState = - rememberPagerState { state.storeEvent[index].thumbnailImages?.size ?: 1 } + rememberPagerState { (state.storeEvent[index].thumbnailImages?.size ?: 0).takeIf { it > 0 } ?: 1 } if (state.isEventExpanded[index]) { EventExpandedItem(state.storeEvent[index], eventOpenCloseTime = eventOpenCloseTime, @@ -113,7 +113,6 @@ fun EventFoldedItem( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - item.thumbnailImages?.getOrNull(0)?.let { Box( modifier = Modifier .fillMaxHeight() @@ -128,7 +127,7 @@ fun EventFoldedItem( .height(80.dp) .clip(RoundedCornerShape(5.dp)), contentScale = ContentScale.FillBounds, - painter = if (item.thumbnailImages?.size == 0) painterResource(id = R.drawable.no_image) else rememberAsyncImagePainter( + painter = if (item.thumbnailImages.isNullOrEmpty()) painterResource(id = R.drawable.no_image) else rememberAsyncImagePainter( model = item.thumbnailImages?.getOrNull(0) ), contentDescription = stringResource(R.string.event_default_image), @@ -154,7 +153,7 @@ fun EventFoldedItem( contentDescription = stringResource(R.string.check), ) } - } + } Column( modifier = Modifier.fillMaxWidth() @@ -171,7 +170,9 @@ fun EventFoldedItem( maxLines = 1, overflow = TextOverflow.Ellipsis ) - Row(modifier = Modifier.weight(1f)) { + Row(modifier = Modifier.weight(1f), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center) { Text( text = stringResource(R.string.view_all), fontWeight = FontWeight(500), @@ -223,14 +224,13 @@ fun EventExpandedItem( ) { Image( modifier = Modifier.fillMaxSize(), - painter = if (item.thumbnailImages?.size == 0) painterResource(id = R.drawable.no_event_image) else rememberAsyncImagePainter( + painter = if (item.thumbnailImages.isNullOrEmpty()) painterResource(id = R.drawable.no_event_image) else rememberAsyncImagePainter( model = item.thumbnailImages?.getOrNull(it) ), contentDescription = stringResource(R.string.event_default_image), - contentScale = ContentScale.Inside + contentScale = ContentScale.FillBounds, ) } - } Column( modifier = Modifier.padding(vertical = 5.dp) diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt index 7ec1d2ca0..e8153c150 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt @@ -72,10 +72,10 @@ fun MenuScreen( ) { Text( - modifier = Modifier.padding(13.dp), + modifier = Modifier.padding(8.dp), text = categories[it], fontSize = 12.sp, - style = TextStyle(color = Gray6, fontSize = 15.sp), + style = TextStyle(color = Gray6, fontSize = 13.sp), fontWeight = FontWeight(500), ) } diff --git a/business/src/main/res/values/strings.xml b/business/src/main/res/values/strings.xml index 759c64975..e43f3ad8e 100644 --- a/business/src/main/res/values/strings.xml +++ b/business/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ 비밀번호가 변경되었습니다.\n새로운 비밀번호로 로그인 부탁드립니다. 재발송 인증번호 발송 + 인증번호 재발송 비밀번호 확인 새 비밀번호 새 비밀번호를 입력해주세요. @@ -117,7 +118,7 @@ 중복된 아이디입니다. 가게이름 이름을 입력해주세요. - 사업자 등록번호를 입력해주세요. + 사업자 등록번호를 입력해주세요.(10자리수) -없이 번호를 입력해주세요. 사업자 인증 파일 인증번호가 일치하지 않습니다. diff --git a/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt b/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt index 890460313..c9bf630e7 100644 --- a/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt +++ b/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt @@ -76,6 +76,13 @@ fun String.toPhoneNumber() : String{ else -> phoneNumberDigitsOnly } } +fun String.toBusinessNumber() : String{ + val businessNumberDigitsOnly = this.filter { it.isDigit() } + return when (businessNumberDigitsOnly.length) { + 11->"${businessNumberDigitsOnly.substring(0, 3)}-${businessNumberDigitsOnly.substring(3, 5)}-${businessNumberDigitsOnly.substring(5)}" + else -> businessNumberDigitsOnly + } +} fun String.toSchoolEamil() = "$this@koreatech.ac.kr" diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt index dc8be84d6..d269a8502 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt @@ -4,6 +4,7 @@ import `in`.koreatech.koin.domain.error.owner.OwnerErrorHandler import `in`.koreatech.koin.domain.model.error.ErrorHandler import `in`.koreatech.koin.domain.model.owner.OwnerRegisterUrl import `in`.koreatech.koin.domain.repository.OwnerRegisterRepository +import `in`.koreatech.koin.domain.util.ext.toSHA256 import javax.inject.Inject class OwnerRegisterUseCase @Inject constructor( @@ -24,7 +25,7 @@ class OwnerRegisterUseCase @Inject constructor( attachments, companyNumber, name, - password, + password.toSHA256(), phoneNumber, shopId, shopName From de45b894931724ca27b10b9d6219092e725b4e10 Mon Sep 17 00:00:00 2001 From: nazero Date: Tue, 5 Nov 2024 17:23:22 +0900 Subject: [PATCH 063/138] =?UTF-8?q?Add:=20=EB=B2=84=ED=8A=BC=20=EA=B0=84?= =?UTF-8?q?=EA=B2=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/findpassword/changepassword/ChangePasswordScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordScreen.kt b/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordScreen.kt index bda72233a..cbe1c69fe 100644 --- a/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/findpassword/changepassword/ChangePasswordScreen.kt @@ -210,9 +210,9 @@ fun ChangePasswordScreen( color = if (fillAllPasswords && buttonEnabled) Color.White else Gray1 ) } + Spacer(modifier = Modifier.height(20.dp)) } } - } @Composable From c701ea5c7f0e52ff0ce5ffbfbf61b8cb7c2f450a Mon Sep 17 00:00:00 2001 From: nazero Date: Tue, 5 Nov 2024 17:24:18 +0900 Subject: [PATCH 064/138] =?UTF-8?q?Add:=20=EB=B2=84=ED=8A=BC=20=EA=B0=84?= =?UTF-8?q?=EA=B2=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../finishchangepassword/FinishChangePasswordScreen.kt | 1 + .../passwordauthentication/PasswordAuthenticationScreen.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/business/src/main/java/in/koreatech/business/feature/findpassword/finishchangepassword/FinishChangePasswordScreen.kt b/business/src/main/java/in/koreatech/business/feature/findpassword/finishchangepassword/FinishChangePasswordScreen.kt index 3a721e252..7d0008b9d 100644 --- a/business/src/main/java/in/koreatech/business/feature/findpassword/finishchangepassword/FinishChangePasswordScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/findpassword/finishchangepassword/FinishChangePasswordScreen.kt @@ -150,6 +150,7 @@ fun FinishChangePasswordScreen( color = Color.White, ) } + Spacer(modifier = Modifier.height(20.dp)) } } } diff --git a/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt b/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt index ad23e3fd6..8cb131ce5 100644 --- a/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/findpassword/passwordauthentication/PasswordAuthenticationScreen.kt @@ -256,6 +256,7 @@ fun PasswordAuthenticationScreen( fontWeight = FontWeight.Bold ) } + Spacer(modifier = Modifier.height(20.dp)) } } } From 50eda47d12f140604b802e78bc322999194b1dc9 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Tue, 5 Nov 2024 19:55:38 +0900 Subject: [PATCH 065/138] =?UTF-8?q?[add]=20adjustResize=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- koin/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/koin/src/main/AndroidManifest.xml b/koin/src/main/AndroidManifest.xml index dda8f6ab1..7adec1c8f 100644 --- a/koin/src/main/AndroidManifest.xml +++ b/koin/src/main/AndroidManifest.xml @@ -38,6 +38,7 @@ Date: Tue, 5 Nov 2024 20:26:45 +0900 Subject: [PATCH 066/138] del: sha256 --- .../koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt index d269a8502..b15d30292 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt @@ -25,7 +25,7 @@ class OwnerRegisterUseCase @Inject constructor( attachments, companyNumber, name, - password.toSHA256(), + password, phoneNumber, shopId, shopName From 3983c05d17777a7bd0475386df216a5d52d3f116 Mon Sep 17 00:00:00 2001 From: nazero Date: Tue, 5 Nov 2024 20:57:52 +0900 Subject: [PATCH 067/138] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/data/mapper/UserMapper.kt | 33 +++++++++++++++---- .../usecase/owner/OwnerRegisterUseCase.kt | 1 - 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt b/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt index c9bf630e7..784a4f3d2 100644 --- a/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt +++ b/data/src/main/java/in/koreatech/koin/data/mapper/UserMapper.kt @@ -55,31 +55,50 @@ fun User.Student.toUserRequestWithPassword(hashedPassword: String) = UserRequest hashedPassword = hashedPassword ) -fun Graduated.toBoolean(): Boolean{ +fun Graduated.toBoolean(): Boolean { return this == Graduated.Graduate } fun Gender.toInt(): Int? { - return when (this){ + return when (this) { Gender.Man -> 0 Gender.Woman -> 1 else -> null } } -fun String.toPhoneNumber() : String{ +fun String.toPhoneNumber(): String { val phoneNumberDigitsOnly = this.filter { it.isDigit() } return when (phoneNumberDigitsOnly.length) { - 11 -> "${phoneNumberDigitsOnly.substring(0, 3)}-${phoneNumberDigitsOnly.substring(3, 7)}-${phoneNumberDigitsOnly.substring(7)}" - 10 -> "${phoneNumberDigitsOnly.substring(0, 3)}-${phoneNumberDigitsOnly.substring(3, 6)}-${phoneNumberDigitsOnly.substring(6)}" + 11 -> "${phoneNumberDigitsOnly.substring(0, 3)}-${ + phoneNumberDigitsOnly.substring( + 3, + 7 + ) + }-${phoneNumberDigitsOnly.substring(7)}" + + 10 -> "${phoneNumberDigitsOnly.substring(0, 3)}-${ + phoneNumberDigitsOnly.substring( + 3, + 6 + ) + }-${phoneNumberDigitsOnly.substring(6)}" + else -> phoneNumberDigitsOnly } } -fun String.toBusinessNumber() : String{ + +fun String.toBusinessNumber(): String { val businessNumberDigitsOnly = this.filter { it.isDigit() } return when (businessNumberDigitsOnly.length) { - 11->"${businessNumberDigitsOnly.substring(0, 3)}-${businessNumberDigitsOnly.substring(3, 5)}-${businessNumberDigitsOnly.substring(5)}" + 11 -> "${businessNumberDigitsOnly.substring(0, 3)}-${ + businessNumberDigitsOnly.substring( + 3, + 5 + ) + }-${businessNumberDigitsOnly.substring(5)}" + else -> businessNumberDigitsOnly } } diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt index b15d30292..dc8be84d6 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/owner/OwnerRegisterUseCase.kt @@ -4,7 +4,6 @@ import `in`.koreatech.koin.domain.error.owner.OwnerErrorHandler import `in`.koreatech.koin.domain.model.error.ErrorHandler import `in`.koreatech.koin.domain.model.owner.OwnerRegisterUrl import `in`.koreatech.koin.domain.repository.OwnerRegisterRepository -import `in`.koreatech.koin.domain.util.ext.toSHA256 import javax.inject.Inject class OwnerRegisterUseCase @Inject constructor( From 33c5b981f4bf18305ec6f1ea00ee70ab3126624c Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 31 Oct 2024 01:46:01 +0900 Subject: [PATCH 068/138] =?UTF-8?q?add:=202.8.3=20compose=20=EB=84=A4?= =?UTF-8?q?=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20ktx=20Serialization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/bus/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/feature/bus/build.gradle.kts b/feature/bus/build.gradle.kts index 0c8d53ab4..110e7d11b 100644 --- a/feature/bus/build.gradle.kts +++ b/feature/bus/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.koin.library) alias(libs.plugins.koin.hilt) alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlinx.serialization) } android { @@ -30,4 +31,7 @@ dependencies { debugImplementation(libs.bundles.compose.debug.test) androidTestImplementation(libs.compose.ui.test.manifest) + + implementation("androidx.navigation:navigation-compose:2.8.3") + implementation(libs.kotlinx.serialization.json) } \ No newline at end of file From dfa1a46d1117d9bc061b71b06293441d7128730e Mon Sep 17 00:00:00 2001 From: Thirfir Date: Fri, 1 Nov 2024 03:17:13 +0900 Subject: [PATCH 069/138] =?UTF-8?q?add:=20=EB=B2=84=EC=8A=A4=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=B0=20=EC=83=81=EB=8B=A8=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_caution.xml | 13 ++++ .../java/in/koreatech/bus/Bus2Activity.kt | 10 ++- .../koreatech/bus/navigation/BusNavigation.kt | 36 +++++++++ .../in/koreatech/bus/navigation/Routes.kt | 8 ++ .../composable/BusTimetableScreen.kt | 77 +++++++++++++++++++ .../bus/screen/timetable/type/BusType.kt | 12 +++ .../timetable/viewmodel/BusViewModel.kt | 11 +++ feature/bus/src/main/res/values/strings.xml | 13 +++- 8 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 core/designsystem/src/main/res/drawable/ic_caution.xml create mode 100644 feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt diff --git a/core/designsystem/src/main/res/drawable/ic_caution.xml b/core/designsystem/src/main/res/drawable/ic_caution.xml new file mode 100644 index 000000000..6431e1275 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_caution.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt index 6e2946fea..e2eba259f 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt @@ -3,10 +3,15 @@ package `in`.koreatech.bus import android.os.Bundle import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.navigation.compose.rememberNavController +import `in`.koreatech.bus.navigation.BusNavigation import `in`.koreatech.koin.feature.bus.R class Bus2Activity : AppCompatActivity() { @@ -16,7 +21,10 @@ class Bus2Activity : AppCompatActivity() { setContentView(R.layout.activity_bus2) findViewById(R.id.compose_view_bus).setContent { MaterialTheme { - + BusNavigation( + modifier = Modifier.fillMaxSize(), + navController = rememberNavController(), + ) } } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt new file mode 100644 index 000000000..00341c717 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt @@ -0,0 +1,36 @@ +package `in`.koreatech.bus.navigation + +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import `in`.koreatech.bus.screen.timetable.viewmodel.BusViewModel + +@Composable +fun BusNavigation( + modifier: Modifier = Modifier, + navController: NavHostController = rememberNavController(), + viewModel: BusViewModel = hiltViewModel() +) { + + NavHost( + modifier = modifier, + navController = navController, + startDestination = Routes.BusTimetable, + enterTransition = { + EnterTransition.None + }, exitTransition = { + ExitTransition.None + } + ) { + + composable { + + } + } +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt new file mode 100644 index 000000000..9b4fc63f5 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt @@ -0,0 +1,8 @@ +package `in`.koreatech.bus.navigation + +import kotlinx.serialization.Serializable + +internal object Routes { + + @Serializable data object BusTimetable +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt new file mode 100644 index 000000000..deea62e39 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -0,0 +1,77 @@ +package `in`.koreatech.bus.screen.timetable.composable + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.screen.timetable.type.BusType +import `in`.koreatech.koin.core.designsystem.component.tab.KoinTabRow +import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText +import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) +@Composable +internal fun BusTimetableScreen( + modifier: Modifier = Modifier, + onNavigationIconClick: () -> Unit = {} +) { + var selectedBusTypeTabIndex by remember { mutableIntStateOf(0) } + + Column( + modifier = modifier + ) { + KoinTopAppBar( + title = "버스 시간표", + onNavigationIconClick = onNavigationIconClick + ) + + LazyColumn { + item { + Column( + modifier = Modifier.padding(start = 24.dp) + ) { + Text( + text = stringResource(R.string.shuttle_timetable), + style = KoinTheme.typography.bold20 + ) + Spacer(modifier = Modifier.height(8.dp)) + LeadingIconText( + text = stringResource(R.string.request_for_incorrect_information), + iconRes = R.drawable.ic_caution + ) + } + } + + stickyHeader { + KoinTabRow( + titles = BusType.entries.map { stringResource(it.titleRes) }, + selectedTabIndex = 0, + onTabSelected = { /* TODO */ } + ) + } + } + } +} + + +@Preview(showBackground = true) +@Composable +private fun BusTimetableScreenPreview() { + BusTimetableScreen( + modifier = Modifier.fillMaxSize() + ) +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt new file mode 100644 index 000000000..3f7cdc463 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt @@ -0,0 +1,12 @@ +package `in`.koreatech.bus.screen.timetable.type + +import androidx.annotation.StringRes +import `in`.koreatech.koin.feature.bus.R + +internal enum class BusType( + @StringRes val titleRes: Int +) { + SHUTTLE(R.string.tab_shuttle), + EXPRESS(R.string.tab_express), + CITY(R.string.tab_city), +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt new file mode 100644 index 000000000..aa0234d35 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt @@ -0,0 +1,11 @@ +package `in`.koreatech.bus.screen.timetable.viewmodel + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class BusViewModel @Inject constructor( + +) : ViewModel() { +} \ No newline at end of file diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 73862c416..9c6a76f96 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -1 +1,12 @@ - \ No newline at end of file + + + 버스 시간표 + 교내 셔틀 시간표 + 정보가 정확하지 않나요? + 셔틀 + 대성 + 시내 + + + + \ No newline at end of file From 7b01d1e11f63e95a3d153e3af860aba8e539ac7a Mon Sep 17 00:00:00 2001 From: Thirfir Date: Mon, 4 Nov 2024 00:32:24 +0900 Subject: [PATCH 070/138] =?UTF-8?q?fix:=20ChipGroup=20=EB=A7=A4=EA=B0=9C?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=88=9C=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/core/designsystem/component/chip/TextChipGroup.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChipGroup.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChipGroup.kt index 63291454d..39f645982 100644 --- a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChipGroup.kt +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChipGroup.kt @@ -31,12 +31,12 @@ import `in`.koreatech.koin.core.designsystem.component.chip.ChipOverflowStrategy */ @Composable fun TextChipGroup( - modifier: Modifier = Modifier, - chipOverflowStrategy: ChipOverflowStrategy = Flow(), titles: List, - shape: Shape = RoundedCornerShape(50), vararg selectedChipIndexes: Int, onChipSelected: (title: String) -> Unit, + modifier: Modifier = Modifier, + chipOverflowStrategy: ChipOverflowStrategy = Flow(), + shape: Shape = RoundedCornerShape(50), showClickRipple: Boolean = true, contentPadding: PaddingValues = PaddingValues(vertical = 6.dp, horizontal = 12.dp), horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(6.dp), From 6129d050181dda3f5d5ea4174da8f5dbb7285b7a Mon Sep 17 00:00:00 2001 From: Thirfir Date: Mon, 4 Nov 2024 00:48:15 +0900 Subject: [PATCH 071/138] =?UTF-8?q?add:=20=EC=85=94=ED=8B=80=20=EB=85=B8?= =?UTF-8?q?=EC=84=A0=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/bus/src/main/res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 9c6a76f96..04eaf8346 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -6,6 +6,9 @@ 셔틀 대성 시내 + 주중노선 + 주말노선 + 순환노선 From c51ecbedc576bd87c424280f89656ac1471f426a Mon Sep 17 00:00:00 2001 From: Thirfir Date: Mon, 4 Nov 2024 00:48:27 +0900 Subject: [PATCH 072/138] =?UTF-8?q?add:=20=EC=85=94=ED=8B=80=20=EB=85=B8?= =?UTF-8?q?=EC=84=A0=20Route=20Type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/screen/timetable/type/ShuttleBusRouteType.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt new file mode 100644 index 000000000..3c34d8edc --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt @@ -0,0 +1,12 @@ +package `in`.koreatech.bus.screen.timetable.type + +import androidx.annotation.StringRes +import `in`.koreatech.koin.feature.bus.R + +enum class ShuttleBusRouteType( + @StringRes val titleRes: Int +) { + WEEKDAY(R.string.weekday_routes), + WEEKEND(R.string.weekend_routes), + CIRCULATION(R.string.circulation_routes) +} \ No newline at end of file From a08cbaf23c0e5aabd45d6195cc790f29d9df45f6 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Mon, 4 Nov 2024 00:48:52 +0900 Subject: [PATCH 073/138] =?UTF-8?q?add:=20=EC=85=94=ED=8B=80=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=ED=91=9C=20=EC=8A=A4=ED=81=AC=EB=A6=B0=20=EC=83=81?= =?UTF-8?q?=EB=8B=A8=20=EC=B9=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/composable/BusTimetableScreen.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index deea62e39..6b3341a97 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -10,13 +10,18 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.bus.screen.timetable.type.BusType +import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType +import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup import `in`.koreatech.koin.core.designsystem.component.tab.KoinTabRow import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar @@ -29,7 +34,8 @@ internal fun BusTimetableScreen( modifier: Modifier = Modifier, onNavigationIconClick: () -> Unit = {} ) { - var selectedBusTypeTabIndex by remember { mutableIntStateOf(0) } + + var selectedTimetableTypeTabIndex by rememberSaveable { mutableIntStateOf(0) } Column( modifier = modifier @@ -59,10 +65,14 @@ internal fun BusTimetableScreen( stickyHeader { KoinTabRow( titles = BusType.entries.map { stringResource(it.titleRes) }, - selectedTabIndex = 0, - onTabSelected = { /* TODO */ } + selectedTabIndex = selectedTimetableTypeTabIndex, + onTabSelected = { selectedTimetableTypeTabIndex = it } ) } + + item { + + } } } } From b00b48c138b68fe50b6f4b251f8faff4f67becee Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 21:14:57 +0900 Subject: [PATCH 074/138] =?UTF-8?q?add:=20=EC=85=94=ED=8B=80=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=ED=91=9C=20=ED=99=94=EB=A9=B4=20base?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screen/timetable/composable/BusTimetableScreen.kt | 8 +++++++- .../timetable/composable/ShuttleTimetableScreen.kt | 11 +++++++++++ .../bus/screen/timetable/type/ShuttleBusRouteType.kt | 1 + feature/bus/src/main/res/values/strings.xml | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index 6b3341a97..4358d406d 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -71,7 +71,13 @@ internal fun BusTimetableScreen( } item { - + when(selectedTimetableTypeTabIndex) { + BusType.SHUTTLE.ordinal -> { + ShuttleTimetableScreen( + modifier = Modifier.fillMaxSize() + ) + } + } } } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt new file mode 100644 index 000000000..fd00f208a --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt @@ -0,0 +1,11 @@ +package `in`.koreatech.bus.screen.timetable.composable + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +internal fun ShuttleTimetableScreen( + modifier: Modifier = Modifier, +) { + +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt index 3c34d8edc..851dd2304 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt @@ -6,6 +6,7 @@ import `in`.koreatech.koin.feature.bus.R enum class ShuttleBusRouteType( @StringRes val titleRes: Int ) { + ALL(R.string.all_routes), WEEKDAY(R.string.weekday_routes), WEEKEND(R.string.weekend_routes), CIRCULATION(R.string.circulation_routes) diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 04eaf8346..52f6a59aa 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ 셔틀 대성 시내 + 전체 주중노선 주말노선 순환노선 From 9ab1b358b8c270ab5f7216a5bd5ec57d93120076 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 21:17:50 +0900 Subject: [PATCH 075/138] =?UTF-8?q?add:=20=ED=95=98=EC=96=80=20=EB=B0=94?= =?UTF-8?q?=ED=83=95=20Surface=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designsystem/component/tab/KoinSurface.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/tab/KoinSurface.kt diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/tab/KoinSurface.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/tab/KoinSurface.kt new file mode 100644 index 000000000..4e801b363 --- /dev/null +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/tab/KoinSurface.kt @@ -0,0 +1,35 @@ +package `in`.koreatech.koin.core.designsystem.component.tab + +import androidx.compose.foundation.BorderStroke +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Composable +fun KoinSurface( + modifier: Modifier = Modifier, + shape: Shape = RectangleShape, + color: Color = Color.White, + contentColor: Color = Color.Black, + tonalElevation: Dp = 0.dp, + shadowElevation: Dp = 0.dp, + border: BorderStroke? = null, + content: @Composable () -> Unit +) { + + Surface( + modifier = modifier, + shape = shape, + color = color, + contentColor = contentColor, + tonalElevation = tonalElevation, + shadowElevation = shadowElevation, + border = border, + content = content + ) +} \ No newline at end of file From e8b8dbfc34f4e3a401e0bca7401438a9bc940f4a Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 21:49:32 +0900 Subject: [PATCH 076/138] =?UTF-8?q?add:=20=EC=9D=BD=EA=B8=B0=20=EC=A0=84?= =?UTF-8?q?=EC=9A=A9=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=B9=A9=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/chip/ReadOnlyTextChip.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/ReadOnlyTextChip.kt diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/ReadOnlyTextChip.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/ReadOnlyTextChip.kt new file mode 100644 index 000000000..683aaa0e1 --- /dev/null +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/ReadOnlyTextChip.kt @@ -0,0 +1,60 @@ +package `in`.koreatech.koin.core.designsystem.component.chip + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme + +/** + * 선택 불가한 텍스트 칩 + * @param title 텍스트 + * @param modifier Modifier + * @param containerColor 칩 배경색 + * @param textStyle 텍스트 스타일 + * @param shape 칩 모양 + * @param contentPadding 칩 내부 padding + */ +@Composable +fun ReadOnlyTextChip( + title: String, + modifier: Modifier = Modifier, + containerColor: Color = KoinTheme.colors.primary500, + textStyle: TextStyle = KoinTheme.typography.regular12, + shape: Shape = RoundedCornerShape(4.dp), + contentPadding: PaddingValues = PaddingValues(horizontal = 4.dp) +) { + Box( + modifier = modifier + .clip(shape) + .background(containerColor) + .padding(contentPadding), + contentAlignment = Alignment.Center + ) { + Text( + text = title, + style = textStyle, + ) + } +} + +@Preview +@Composable +private fun ReadOnlyTextChipPreview() { + ReadOnlyTextChip( + title = "순환", + containerColor = Color(0xFF4ED92C), + textStyle = KoinTheme.typography.regular12.copy(color = Color.White) + ) +} From 4a1dbb0e081c599aabfa744892dd26d96898320e Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 22:32:38 +0900 Subject: [PATCH 077/138] =?UTF-8?q?fix:=20TopAppBar=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20TextStyle=20parameter=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/designsystem/component/topbar/KoinTopAppBar.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/topbar/KoinTopAppBar.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/topbar/KoinTopAppBar.kt index e42b59901..c9f1526ba 100644 --- a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/topbar/KoinTopAppBar.kt +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/topbar/KoinTopAppBar.kt @@ -14,16 +14,19 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.R import `in`.koreatech.koin.core.designsystem.noRippleClickable +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme @OptIn(ExperimentalMaterial3Api::class) @Composable fun KoinTopAppBar( title: String, modifier: Modifier = Modifier, + textStyle: TextStyle = KoinTheme.typography.medium18, onNavigationIconClick: () -> Unit = {}, actions: @Composable() (RowScope.() -> Unit) = {}, colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors( @@ -35,7 +38,10 @@ fun KoinTopAppBar( ) { CenterAlignedTopAppBar( title = { - Text(title) + Text( + text = title, + style = textStyle, + ) }, modifier = modifier, navigationIcon = { From d8282864f6e81f1531caedead53ed801d354cac0 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 22:32:50 +0900 Subject: [PATCH 078/138] add: Bus feature ImmutableList dependency --- feature/bus/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/feature/bus/build.gradle.kts b/feature/bus/build.gradle.kts index 110e7d11b..bac9fe443 100644 --- a/feature/bus/build.gradle.kts +++ b/feature/bus/build.gradle.kts @@ -25,6 +25,7 @@ dependencies { implementation(libs.core.ktx) implementation(libs.appcompat) implementation(libs.material) + implementation(libs.kotlinxCollectionsImmutable) implementation(platform(libs.compose.bom)) implementation(libs.bundles.compose.m3) From 0d98019d90c4b2dc01189f4c3aaba9bbc0724e4f Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 22:33:23 +0900 Subject: [PATCH 079/138] =?UTF-8?q?add:=20=EC=85=94=ED=8B=80=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20=EC=8B=9C=EA=B0=84=ED=91=9C=20=EC=B2=AB=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EC=B6=94=EA=B0=80=20(with.=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=ED=8F=AC=EB=A7=B7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/BusTimetableScreen.kt | 67 ++++++- .../composable/ShuttleTimetableScreen.kt | 188 ++++++++++++++++++ .../timetable/type/ShuttleBusRouteType.kt | 11 +- .../ShuttleTimetableOverviewViewState.kt | 19 ++ feature/bus/src/main/res/values/strings.xml | 3 + 5 files changed, 280 insertions(+), 8 deletions(-) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/viewstate/ShuttleTimetableOverviewViewState.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index 4358d406d..4ebdc2560 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -1,9 +1,11 @@ package `in`.koreatech.bus.screen.timetable.composable import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -16,17 +18,21 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.bus.screen.timetable.type.BusType import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType +import `in`.koreatech.bus.viewstate.ShuttleRegionViewState +import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup import `in`.koreatech.koin.core.designsystem.component.tab.KoinTabRow import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R +import kotlinx.collections.immutable.persistentListOf @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable @@ -41,14 +47,14 @@ internal fun BusTimetableScreen( modifier = modifier ) { KoinTopAppBar( - title = "버스 시간표", + title = stringResource(R.string.title_bus_timetable), onNavigationIconClick = onNavigationIconClick ) LazyColumn { item { Column( - modifier = Modifier.padding(start = 24.dp) + modifier = Modifier.fillMaxWidth().background(Color.White).padding(start = 24.dp) ) { Text( text = stringResource(R.string.shuttle_timetable), @@ -74,7 +80,62 @@ internal fun BusTimetableScreen( when(selectedTimetableTypeTabIndex) { BusType.SHUTTLE.ordinal -> { ShuttleTimetableScreen( - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), + regions = persistentListOf( + ShuttleRegionViewState( + name = "서울", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "서울-대전", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "서울-대전", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.CIRCULATION, + name = "서울-대전", + ) + ) + ), + ShuttleRegionViewState( + name = "대전", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대전-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "대전-서울", + description = "대전에서 서울로 이동하는 노선입니다." + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.CIRCULATION, + name = "대전-서울", + description = "대전에서 서울로 이동하는 노선입니다." + ) + ) + ), + ShuttleRegionViewState( + name = "대구", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대구-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대구-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "대구-서울", + ) + ) + ) + ) ) } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt index fd00f208a..b084e5e70 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt @@ -1,11 +1,199 @@ package `in`.koreatech.bus.screen.timetable.composable +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight +import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType +import `in`.koreatech.bus.viewstate.ShuttleRegionViewState +import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState +import `in`.koreatech.koin.core.designsystem.component.chip.ReadOnlyTextChip +import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup +import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf @Composable internal fun ShuttleTimetableScreen( modifier: Modifier = Modifier, + regions: ImmutableList ) { + var selectedRouteTypeIndex by rememberSaveable { mutableIntStateOf(ShuttleBusRouteType.ALL.ordinal) } + val context = LocalContext.current + + Column( + modifier = modifier + ) { + TextChipGroup( + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp, horizontal = 24.dp), + titles = ShuttleBusRouteType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedRouteTypeIndex = ShuttleBusRouteType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedRouteTypeIndex) + ) + regions.forEach { + ShuttleRegionView( + modifier = Modifier, + region = it + ) + if (it != regions.last()) { + Spacer(modifier = Modifier.height(10.dp)) + } + } + } +} + +@Composable +private fun ShuttleRegionView( + modifier: Modifier = Modifier, + region: ShuttleRegionViewState +) { + KoinSurface( + modifier = modifier + ) { + Column( + modifier = Modifier.padding(horizontal = 24.dp).padding(top = 16.dp, bottom = 4.dp) + ) { + Text( + text = region.name, + style = KoinTheme.typography.bold18, + ) + region.timetableOverviews.forEach { + ShuttleRouteItem( + modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 10.dp), + timetableOverview = it + ) + } + } + } +} + +@Composable +private fun ShuttleRouteItem( + modifier: Modifier = Modifier, + timetableOverview: ShuttleTimetableOverviewViewState +) { + Column( + modifier = modifier + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + ReadOnlyTextChip( + title = stringResource(timetableOverview.routeType.simpleTitleRes), + containerColor = when (timetableOverview.routeType) { // TODO : 색상 정리 + ShuttleBusRouteType.WEEKDAY -> Color(0xFF34ADFF) + ShuttleBusRouteType.WEEKEND -> Color(0xFFFFB443) + ShuttleBusRouteType.CIRCULATION -> Color(0xFF4ED92C) + else -> Color.Transparent + }, + textStyle = KoinTheme.typography.regular12.copy(color = Color.White) + ) + + Text( + text = timetableOverview.name, + style = KoinTheme.typography.medium16, + modifier = Modifier.padding(start = 8.dp) + ) + Spacer(modifier = Modifier.weight(1f)) + Icon( + imageVector = Icons.AutoMirrored.Rounded.KeyboardArrowRight, + contentDescription = timetableOverview.name, + tint = KoinTheme.colors.neutral400 + ) + } + if (timetableOverview.description.isNotEmpty()) + Text( + text = timetableOverview.description, + style = KoinTheme.typography.regular12, + color = KoinTheme.colors.neutral500, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun ShuttleTimetableScreenPreview() { + ShuttleTimetableScreen( + modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), + regions = persistentListOf( + ShuttleRegionViewState( + name = "서울", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "서울-대전", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "서울-대전", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.CIRCULATION, + name = "서울-대전", + ) + ) + ), + ShuttleRegionViewState( + name = "대전", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대전-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "대전-서울", + description = "대전에서 서울로 이동하는 노선입니다." + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.CIRCULATION, + name = "대전-서울", + description = "대전에서 서울로 이동하는 노선입니다." + ) + ) + ), + ShuttleRegionViewState( + name = "대구", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대구-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대구-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "대구-서울", + ) + ) + ) + ) + ) } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt index 851dd2304..b84afe6d4 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt @@ -4,10 +4,11 @@ import androidx.annotation.StringRes import `in`.koreatech.koin.feature.bus.R enum class ShuttleBusRouteType( - @StringRes val titleRes: Int + @StringRes val titleRes: Int, + @StringRes val simpleTitleRes: Int ) { - ALL(R.string.all_routes), - WEEKDAY(R.string.weekday_routes), - WEEKEND(R.string.weekend_routes), - CIRCULATION(R.string.circulation_routes) + ALL(R.string.all_routes, 0), + WEEKDAY(R.string.weekday_routes, R.string.weekday_routes_simple), + WEEKEND(R.string.weekend_routes, R.string.weekend_routes_simple), + CIRCULATION(R.string.circulation_routes, R.string.circulation_routes_simple), } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/viewstate/ShuttleTimetableOverviewViewState.kt b/feature/bus/src/main/java/in/koreatech/bus/viewstate/ShuttleTimetableOverviewViewState.kt new file mode 100644 index 000000000..e36b39fe0 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/viewstate/ShuttleTimetableOverviewViewState.kt @@ -0,0 +1,19 @@ +package `in`.koreatech.bus.viewstate + +import androidx.compose.runtime.Immutable +import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType + +@Immutable +data class ShuttleTimetableOverviewViewState( + val routeType: ShuttleBusRouteType, + val name: String, + val description: String = "", +) + +@Immutable +data class ShuttleRegionViewState( + val name: String, + val timetableOverviews: List +) + +// TODO : 임시 데이터, API 아직 없음 \ No newline at end of file diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 52f6a59aa..caaed9e72 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -10,6 +10,9 @@ 주중노선 주말노선 순환노선 + 주중 + 주말 + 순환 From ffe957d34401f29499faec8597625bb5e3652493 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Tue, 5 Nov 2024 23:04:59 +0900 Subject: [PATCH 080/138] add: BusTimetableViewModel base --- .../timetable/composable/BusTimetableScreen.kt | 5 ++++- .../timetable/viewmodel/BusTimetableViewModel.kt | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index 4ebdc2560..44d87e7bc 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -22,8 +22,10 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import `in`.koreatech.bus.screen.timetable.type.BusType import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType +import `in`.koreatech.bus.screen.timetable.viewmodel.BusTimetableViewModel import `in`.koreatech.bus.viewstate.ShuttleRegionViewState import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup @@ -38,7 +40,8 @@ import kotlinx.collections.immutable.persistentListOf @Composable internal fun BusTimetableScreen( modifier: Modifier = Modifier, - onNavigationIconClick: () -> Unit = {} + onNavigationIconClick: () -> Unit = {}, + viewModel: BusTimetableViewModel = hiltViewModel() ) { var selectedTimetableTypeTabIndex by rememberSaveable { mutableIntStateOf(0) } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt new file mode 100644 index 000000000..ffd834b4a --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt @@ -0,0 +1,12 @@ +package `in`.koreatech.bus.screen.timetable.viewmodel + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class BusTimetableViewModel @Inject constructor( + +) : ViewModel() { + +} \ No newline at end of file From 7dd9b789d4f48c987dd054aa41639dec188f923a Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 09:12:10 +0900 Subject: [PATCH 081/138] =?UTF-8?q?[fix]=20=ED=95=A8=EC=88=98=20=EC=98=A4?= =?UTF-8?q?=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/request/timetable/LecturesQueryRequest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt b/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt index e069dea18..c48303720 100644 --- a/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt +++ b/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt @@ -32,10 +32,10 @@ data class LectureQueryRequest( fun LecturesQuery.toLecturesQueryRequest() = LecturesQueryRequest( timetableFrameId = timetableFrameId, - timetableLecture = timetableLecture.map { it.toTLectureQueryRequest() } + timetableLecture = timetableLecture.map { it.toLectureQueryRequest() } ) -fun LectureQuery.toTLectureQueryRequest() = LectureQueryRequest( +fun LectureQuery.toLectureQueryRequest() = LectureQueryRequest( lectureId = lectureId, classTitle = classTitle, classTime = classTime, From 264916f95cc5c839e1266bcefd4bf2b0830beb09 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 09:44:31 +0900 Subject: [PATCH 082/138] =?UTF-8?q?[del]=20LectureQuery=20=EB=AA=A8?= =?UTF-8?q?=EB=8D=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/TimetableRepositoryImpl.kt | 11 ++++++---- .../request/timetable/LecturesQueryRequest.kt | 20 ++++++------------- .../remote/TimetableRemoteDataSource.kt | 1 - .../model/timetable/request/LecturesQuery.kt | 16 --------------- .../model/timetable/response/Lecture.kt | 12 ----------- .../domain/repository/TimetableRepository.kt | 5 +---- .../timetable/AddTimetableLectureUseCase.kt | 7 +------ 7 files changed, 15 insertions(+), 57 deletions(-) delete mode 100644 domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt diff --git a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt index ceaea303c..a9a839f91 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt @@ -2,11 +2,11 @@ package `in`.koreatech.koin.data.repository import com.google.gson.Gson import com.google.gson.reflect.TypeToken -import `in`.koreatech.koin.data.request.timetable.toLecturesQueryRequest +import `in`.koreatech.koin.data.request.timetable.LecturesQueryRequest +import `in`.koreatech.koin.data.request.timetable.toLectureQueryRequest import `in`.koreatech.koin.data.request.timetable.toTimetableLecturesQueryRequest import `in`.koreatech.koin.data.source.datastore.TimetableDataStore import `in`.koreatech.koin.data.source.remote.TimetableRemoteDataSource -import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery @@ -71,8 +71,11 @@ class TimetableRepositoryImpl @Inject constructor( TODO("Not yet implemented") } - override suspend fun postTimetableLectures(lectures: LecturesQuery): Result = runCatching { - timetableRemoteDataSource.postTimetableLectures(lectures.toLecturesQueryRequest()).toTimetableLectures() + override suspend fun postTimetableLectures(frameId: Int, lectures: List): Result = runCatching { + timetableRemoteDataSource.postTimetableLectures(LecturesQueryRequest( + timetableFrameId = frameId, + timetableLecture = lectures.map { it.toLectureQueryRequest() } + )).toTimetableLectures() } diff --git a/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt b/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt index c48303720..86618703d 100644 --- a/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt +++ b/data/src/main/java/in/koreatech/koin/data/request/timetable/LecturesQueryRequest.kt @@ -1,10 +1,7 @@ package `in`.koreatech.koin.data.request.timetable import com.google.gson.annotations.SerializedName -import `in`.koreatech.koin.domain.model.timetable.request.LectureQuery -import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery -import `in`.koreatech.koin.domain.model.timetable.request.TimetableLectureQuery -import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery +import `in`.koreatech.koin.domain.model.timetable.response.Lecture data class LecturesQueryRequest( @SerializedName("timetable_frame_id") @@ -30,17 +27,12 @@ data class LectureQueryRequest( val memo: String, ) -fun LecturesQuery.toLecturesQueryRequest() = LecturesQueryRequest( - timetableFrameId = timetableFrameId, - timetableLecture = timetableLecture.map { it.toLectureQueryRequest() } -) - -fun LectureQuery.toLectureQueryRequest() = LectureQueryRequest( - lectureId = lectureId, - classTitle = classTitle, +fun Lecture.toLectureQueryRequest() = LectureQueryRequest( + lectureId = id, + classTitle = name, classTime = classTime, - classPlace = classPlace, + classPlace = "", professor = professor, grades = grades, - memo = memo + memo = "" ) diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt index dfb79db73..ff30974cf 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt @@ -11,7 +11,6 @@ import `in`.koreatech.koin.data.response.timetable.SemesterCheckResponse import `in`.koreatech.koin.data.response.timetable.SemesterResponse import `in`.koreatech.koin.data.response.timetable.TimetableFrameResponse import `in`.koreatech.koin.data.response.timetable.TimetableLecturesResponse -import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import javax.inject.Inject class TimetableRemoteDataSource @Inject constructor( diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt deleted file mode 100644 index 49f75d08d..000000000 --- a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/request/LecturesQuery.kt +++ /dev/null @@ -1,16 +0,0 @@ -package `in`.koreatech.koin.domain.model.timetable.request - -data class LecturesQuery( - val timetableFrameId: Int, - val timetableLecture: List = emptyList(), -) - -data class LectureQuery( - val lectureId: Int?, - val classTitle: String = "", - val classTime: List, - val classPlace: String = "", - val professor: String = "", - val grades: String = "", - val memo: String = "", -) \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt index dabbfeefb..9bd9848f2 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/timetable/response/Lecture.kt @@ -1,7 +1,5 @@ package `in`.koreatech.koin.domain.model.timetable.response -import `in`.koreatech.koin.domain.model.timetable.request.LectureQuery -import `in`.koreatech.koin.domain.model.timetable.request.TimetableLectureQuery import java.time.DayOfWeek import java.time.LocalTime @@ -20,16 +18,6 @@ data class Lecture( val isElearning: String = "", val classTime: List ) { - fun toLectureQuery() = LectureQuery( - lectureId = id, - classTitle = name, - classTime =classTime, - classPlace = "", - professor = professor, - grades = grades, - memo = "" - ) - fun toTimetableLecture() = TimetableLecture( id = id, lectureId = id, diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt index a5d2382d9..dfdfa9cfd 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt @@ -1,12 +1,9 @@ package `in`.koreatech.koin.domain.repository -import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameCreateQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableFrameQuery import `in`.koreatech.koin.domain.model.timetable.request.TimetableLecturesQuery import `in`.koreatech.koin.domain.model.timetable.response.Lecture -import `in`.koreatech.koin.domain.model.timetable.response.Semester -import `in`.koreatech.koin.domain.model.timetable.response.SemesterCheck import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures import kotlinx.coroutines.flow.Flow @@ -24,7 +21,7 @@ interface TimetableRepository { suspend fun putTimetableLectures(key: String, value: TimetableLectures): Result suspend fun putTimetableFrame(id: Int, frame: TimetableFrameQuery): TimetableFrame - suspend fun postTimetableLectures(lectures: LecturesQuery): Result + suspend fun postTimetableLectures(frameId: Int, lectures: List): Result suspend fun postTimetableFrame(frame: TimetableFrameCreateQuery): TimetableFrame suspend fun deleteTimetableFrame() diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt index 524a0b5d6..0dd71f207 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/timetable/AddTimetableLectureUseCase.kt @@ -1,6 +1,5 @@ package `in`.koreatech.koin.domain.usecase.timetable -import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import `in`.koreatech.koin.domain.model.timetable.response.Lecture import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures import `in`.koreatech.koin.domain.repository.TimetableRepository @@ -10,10 +9,6 @@ class AddTimetableLectureUseCase @Inject constructor( private val timetableRepository: TimetableRepository ) { suspend operator fun invoke(frameId: Int, lectures: List): Result { - val query = LecturesQuery( - timetableFrameId = frameId, - timetableLecture = lectures.map { it.toLectureQuery() } - ) - return timetableRepository.postTimetableLectures(query) + return timetableRepository.postTimetableLectures(frameId, lectures) } } \ No newline at end of file From 665de6babeb9df8e1225fbf9590519fc3bb1f1c9 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 09:44:46 +0900 Subject: [PATCH 083/138] =?UTF-8?q?[add]=20textMeasurer=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/api/auth/TimetableAuthApi.kt | 1 - .../component/TimetableInputField.kt | 19 +++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt index 3cb4171de..ccaa9d6ec 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt @@ -7,7 +7,6 @@ import `in`.koreatech.koin.data.request.timetable.TimetableLecturesQueryRequest import `in`.koreatech.koin.data.response.timetable.SemesterCheckResponse import `in`.koreatech.koin.data.response.timetable.TimetableFrameResponse import `in`.koreatech.koin.data.response.timetable.TimetableLecturesResponse -import `in`.koreatech.koin.domain.model.timetable.request.LecturesQuery import retrofit2.Response import retrofit2.http.Body import retrofit2.http.DELETE diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt index 67c8a84fd..f932c09a5 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt @@ -23,7 +23,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.koin.core.designsystem.theme.KoinTheme @@ -37,6 +39,12 @@ fun TimetableInputField( onValueChange: (text: String) -> Unit = {}, ) { var text by remember { mutableStateOf("") } + val textMeasurer = rememberTextMeasurer() + val textLayoutResult = textMeasurer.measure( + text = stringResource(id = R.string.timetable_input_field_option_character), + style = KoinTheme.typography.regular16, + ) + val optionalCharacterWidth = textLayoutResult.size.width BasicTextField( value = text, onValueChange = { @@ -65,14 +73,14 @@ fun TimetableInputField( verticalAlignment = Alignment.CenterVertically ) { if (optional) { + Spacer(modifier = Modifier.width(LocalDensity.current.run { optionalCharacterWidth.toDp() })) + } else { Text( text = stringResource(id = R.string.timetable_input_field_option_character), style = KoinTheme.typography.regular16, color = KoinTheme.colors.sub500, - modifier = Modifier.padding(end = 1.dp, bottom = 1.dp) + modifier = Modifier.padding(end = 1.dp, bottom = 1.dp), ) - } else { - Spacer(modifier = Modifier.width(8.dp)) } Text( text = title, @@ -89,7 +97,10 @@ fun TimetableInputField( Box { text.ifEmpty { Text( - text = stringResource(id = R.string.timetable_input_field_placeholder, title), + text = stringResource( + id = R.string.timetable_input_field_placeholder, + title + ), style = KoinTheme.typography.regular12, color = KoinTheme.colors.neutral500 ) From 321e1b5efba593da16f8f194e5a2dc8815b698bb Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 09:58:00 +0900 Subject: [PATCH 084/138] =?UTF-8?q?[add]=20IntrinsicSize=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/timetable/component/TimetableInputField.kt | 7 +++++-- .../feature/timetable/section/BottomSheetCustomContent.kt | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt index f932c09a5..0d90d5ff2 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableInputField.kt @@ -3,8 +3,10 @@ package `in`.koreatech.koin.feature.timetable.component import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn @@ -35,7 +37,7 @@ import `in`.koreatech.koin.feature.timetable.R fun TimetableInputField( title: String, modifier: Modifier = Modifier, - optional: Boolean = false, + optional: Boolean = true, onValueChange: (text: String) -> Unit = {}, ) { var text by remember { mutableStateOf("") } @@ -62,6 +64,7 @@ fun TimetableInputField( decorationBox = { innerTextField -> Row( modifier = Modifier + .height(IntrinsicSize.Min) .fillMaxWidth() .background(Color.White) .border( @@ -90,7 +93,7 @@ fun TimetableInputField( Spacer(modifier = Modifier.width(7.dp)) VerticalDivider( thickness = 2.dp, - modifier = Modifier.heightIn(max = 25.dp), + modifier = Modifier.fillMaxHeight(), color = KoinTheme.colors.neutral300 ) Spacer(modifier = Modifier.width(20.dp)) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt index 123e4619e..b2f482f78 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt @@ -26,7 +26,7 @@ fun BottomSheetCustomContent( ) { TimetableInputField( title = stringResource(id = R.string.timetable_input_field_title_schedule), - optional = true, + optional = false, onValueChange = onScheduleNameChange ) Spacer(modifier = Modifier.height(8.dp)) From 0f54d667644ab85a2a5376e0bd71d0af256b52ee Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 10:03:55 +0900 Subject: [PATCH 085/138] =?UTF-8?q?[add]=20spaceBy=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timetable/component/TimetableTimeContentRow.kt | 8 ++++---- .../feature/timetable/section/BottomSheetCustomContent.kt | 8 +++----- .../timetable/section/TimetableBottomSheetCustom.kt | 1 + 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt index 47b52373d..d7ed4d49f 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt @@ -47,21 +47,21 @@ fun TimetableTimeContentRow( ) } - Row(modifier = Modifier) { + Row( + modifier = Modifier, + horizontalArrangement = Arrangement.spacedBy(11.dp) + ) { TimeEditBox( text = "월요일" ) - Spacer(modifier = Modifier.width(11.dp)) TimeEditBox( text = "09:00" ) - Spacer(modifier = Modifier.width(11.dp)) Text( text = stringResource(id = R.string.timetable_input_field_wave_character), style = KoinTheme.typography.medium18, color = KoinTheme.colors.neutral800 ) - Spacer(modifier = Modifier.width(11.dp)) TimeEditBox( text = "11:00" ) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt index b2f482f78..82e88dcbf 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/BottomSheetCustomContent.kt @@ -1,5 +1,6 @@ package `in`.koreatech.koin.feature.timetable.section +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -22,26 +23,23 @@ fun BottomSheetCustomContent( ) { Column( modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) ) { TimetableInputField( title = stringResource(id = R.string.timetable_input_field_title_schedule), optional = false, onValueChange = onScheduleNameChange ) - Spacer(modifier = Modifier.height(8.dp)) TimetableInputField( title = stringResource(id = R.string.timetable_input_field_title_professor), onValueChange = onProfessorNameChange ) - Spacer(modifier = Modifier.height(8.dp)) TimetableTimeContentRow() - Spacer(modifier = Modifier.height(8.dp)) TimetableInputField( title = stringResource(id = R.string.timetable_input_field_title_place), onValueChange = onPlaceNameChange ) - Spacer(modifier = Modifier.height(8.dp)) } } diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt index 78765e3da..4e09816be 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/section/TimetableBottomSheetCustom.kt @@ -30,6 +30,7 @@ fun TimetableBottomSheetCustom( onProfessorNameChange = {}, // TODO : 교수명 추가 onPlaceNameChange = {} // TODO : 장소 추가 ) + Spacer(modifier = Modifier.height(8.dp)) } items(events.size, key = { events[it].position }) { index -> BottomSheetCustomExtraContent( From bd6cb2b426c9be3686a45c9fff1ce69986b410b4 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 10:22:33 +0900 Subject: [PATCH 086/138] =?UTF-8?q?[del]=20=EC=A1=B0=EA=B1=B4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/koin/feature/timetable/view/Timetable.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt index b6cc4d5d3..574f66725 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/Timetable.kt @@ -61,10 +61,8 @@ fun Timetable( clickEvent = clickEvent, content = content, onEventClick = onEventClick, - onEventY = {y -> - if (scrollValue != y) { - scrollValue = y - } + onEventY = { y -> + scrollValue = y } ) } From cc3b9e79a1eeaff09367cb1cc126b0737724bb8d Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 10:24:04 +0900 Subject: [PATCH 087/138] =?UTF-8?q?[del]=20=EC=A4=91=EB=B3=B5=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=A2=85=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle/libs.versions.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 34118337e..ae2aa3c38 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -139,7 +139,7 @@ lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", v map-sdk = { module = "com.naver.maps:map-sdk", version.ref = "mapSdkVersion" } photoview = { module = "com.github.chrisbanes:PhotoView", version.ref = "photoviewVersion" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlinVersion" } -kotlinxCollectionsImmutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version = "0.3.6" } +kotlinxCollectionsImmutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutableVersion" } core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtxVersion" } junit = { group = "junit", name = "junit", version.ref = "junitVersion" } ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" } @@ -198,8 +198,6 @@ timber = { module = "com.jakewharton.timber:timber", version.ref = "timber"} coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTestVersion" } turbine = { module = "app.cash.turbine:turbine", version.ref = "turbineVersion" } -kotlinx-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutableVersion" } - [plugins] android-application = { id = "com.android.application", version.ref = "androidGradleVersion" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } From dfac5214ea52cee72048665e5dd64836ab16a5ad Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 10:24:49 +0900 Subject: [PATCH 088/138] =?UTF-8?q?[add]=20immutable=20=EC=A2=85=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/timetable/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/timetable/build.gradle.kts b/feature/timetable/build.gradle.kts index 7b8b8fefe..65a921d49 100644 --- a/feature/timetable/build.gradle.kts +++ b/feature/timetable/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { implementation(platform(libs.compose.bom)) implementation(libs.compose.material2) implementation(libs.bundles.compose.m3) - implementation(libs.kotlinx.immutable) + implementation(libs.kotlinxCollectionsImmutable) implementation(libs.timber) From 015aa0dc2fd2b8a3a67f0f80b5ef217247d2be33 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 10:26:04 +0900 Subject: [PATCH 089/138] =?UTF-8?q?[fix]=20immutableList=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/feature/timetable/view/TimetableBottomSheet.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt index 2ce7d5516..d7cc7b4c4 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/view/TimetableBottomSheet.kt @@ -20,6 +20,8 @@ import `in`.koreatech.koin.feature.timetable.model.dummyLecture import `in`.koreatech.koin.feature.timetable.section.TimetableBottomSheetBasic import `in`.koreatech.koin.feature.timetable.section.TimetableBottomSheetCustom import `in`.koreatech.koin.feature.timetable.section.TimetableBottomSheetHeader +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import java.time.DayOfWeek import java.time.LocalTime @@ -30,7 +32,7 @@ enum class TimetableBottomSheetContentMode { data class CustomEventData( val schedule: String = "", val professor: String? = "", - val data: List = emptyList() + val data: ImmutableList = persistentListOf() ) data class CustomEventExtraData( From 58e3f4655d08126a3c9cba1c75c6f5cc27310d27 Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Wed, 6 Nov 2024 14:56:41 +0900 Subject: [PATCH 090/138] =?UTF-8?q?[del]=20Row=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=ED=9B=84=20Spacer=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/TimetableTimeContentRow.kt | 63 ++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt index d7ed4d49f..0041ac640 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/component/TimetableTimeContentRow.kt @@ -28,44 +28,35 @@ fun TimetableTimeContentRow( .background(Color.White) .padding(start = 4.dp), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween ) { - Row( - modifier = Modifier, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(id = R.string.timetable_input_field_option_character), - style = KoinTheme.typography.regular16, - color = KoinTheme.colors.sub500, - modifier = Modifier.padding(end = 1.dp, bottom = 1.dp) - ) - Text( - text = stringResource(id = R.string.timetable_input_field_title_time), - style = KoinTheme.typography.bold12, - color = KoinTheme.colors.neutral800 - ) - } + Text( + text = stringResource(id = R.string.timetable_input_field_option_character), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.sub500, + modifier = Modifier.padding(end = 1.dp, bottom = 1.dp) + ) + Text( + text = stringResource(id = R.string.timetable_input_field_title_time), + style = KoinTheme.typography.bold12, + color = KoinTheme.colors.neutral800 + ) - Row( - modifier = Modifier, - horizontalArrangement = Arrangement.spacedBy(11.dp) - ) { - TimeEditBox( - text = "월요일" - ) - TimeEditBox( - text = "09:00" - ) - Text( - text = stringResource(id = R.string.timetable_input_field_wave_character), - style = KoinTheme.typography.medium18, - color = KoinTheme.colors.neutral800 - ) - TimeEditBox( - text = "11:00" - ) - } + Spacer(modifier = Modifier.weight(1f)) + + TimeEditBox( + text = "월요일" + ) + TimeEditBox( + text = "09:00" + ) + Text( + text = stringResource(id = R.string.timetable_input_field_wave_character), + style = KoinTheme.typography.medium18, + color = KoinTheme.colors.neutral800 + ) + TimeEditBox( + text = "11:00" + ) } } From 3b480f2bf7a968bb4377e29227a179e692572ae8 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 00:02:13 +0900 Subject: [PATCH 091/138] =?UTF-8?q?AGP=20=EC=97=85=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=207.2.1=20->=208.7.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build-logic/convention/build.gradle.kts | 4 ++-- .../java/in/koreatech/convention/AndroidCompose.kt | 2 +- .../java/in/koreatech/convention/AndroidLibrary.kt | 8 ++++---- .../main/java/in/koreatech/convention/AndroidOrbit.kt | 2 +- .../java/in/koreatech/convention/AndroidProject.kt | 10 +++++----- .../main/java/in/koreatech/convention/KotlinAndroid.kt | 4 ++-- gradle.properties | 3 +++ gradle/libs.versions.toml | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- koin/build.gradle.kts | 2 +- 10 files changed, 22 insertions(+), 19 deletions(-) diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 4e0215153..b8a5bc42b 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -3,8 +3,8 @@ plugins { } java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } dependencies { diff --git a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidCompose.kt b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidCompose.kt index 34aa90bfb..736d020c7 100644 --- a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidCompose.kt +++ b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidCompose.kt @@ -6,7 +6,7 @@ import org.gradle.kotlin.dsl.dependencies internal fun Project.configureAndroidCompose( - commonExtension: CommonExtension<*, *, *, *>, + commonExtension: CommonExtension<*, *, *, *, *, *>, ) { commonExtension.apply { buildFeatures.compose = true diff --git a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidLibrary.kt b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidLibrary.kt index da5036884..b69f786c8 100644 --- a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidLibrary.kt +++ b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidLibrary.kt @@ -6,7 +6,7 @@ import org.gradle.api.JavaVersion import org.gradle.api.Project internal fun Project.configureAndroidLibrary( - commonExtension: CommonExtension<*, *, *, *>, + commonExtension: CommonExtension<*, *, *, *, *, *>, ) { (commonExtension as? LibraryExtension)?.let { it.defaultConfig.targetSdk = 34 @@ -26,12 +26,12 @@ internal fun Project.configureAndroidLibrary( } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + jvmTarget = JavaVersion.VERSION_17.toString() } packagingOptions { diff --git a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidOrbit.kt b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidOrbit.kt index 71f67d20a..f00b48ee1 100644 --- a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidOrbit.kt +++ b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidOrbit.kt @@ -5,7 +5,7 @@ import org.gradle.api.Project import org.gradle.kotlin.dsl.dependencies internal fun Project.configureAndroidOrbit( - commonExtension: CommonExtension<*, *, *, *> + commonExtension: CommonExtension<*, *, *, *, *, *> ){ dependencies { implementation(libs.findBundle("orbit").get()) diff --git a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidProject.kt b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidProject.kt index a2ac0e038..2354f4152 100644 --- a/build-logic/convention/src/main/java/in/koreatech/convention/AndroidProject.kt +++ b/build-logic/convention/src/main/java/in/koreatech/convention/AndroidProject.kt @@ -8,7 +8,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions internal fun configureAndroidProject( - commonExtension: CommonExtension<*, *, *, *>, + commonExtension: CommonExtension<*, *, *, *, *, *>, ) { (commonExtension as? ApplicationExtension)?.let { it.defaultConfig.targetSdk = 34 @@ -26,17 +26,17 @@ internal fun configureAndroidProject( } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + jvmTarget = JavaVersion.VERSION_17.toString() } } } -fun CommonExtension<*, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) { +fun CommonExtension<*, *, *, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) { (this as ExtensionAware).extensions.configure("kotlinOptions", block) } diff --git a/build-logic/convention/src/main/java/in/koreatech/convention/KotlinAndroid.kt b/build-logic/convention/src/main/java/in/koreatech/convention/KotlinAndroid.kt index 5a29c1e7c..31df021db 100644 --- a/build-logic/convention/src/main/java/in/koreatech/convention/KotlinAndroid.kt +++ b/build-logic/convention/src/main/java/in/koreatech/convention/KotlinAndroid.kt @@ -8,7 +8,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension internal fun Project.configureKotlinJvm() { extensions.configure { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 4b6f36405..6d8dbb94c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,6 +23,9 @@ org.gradle.daemon=true org.gradle.parallel=true # Enable configure on demand. org.gradle.configureondemand=true +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false # When configured, Gradle will run in incubating parallel mode. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5eb8da42..9b8c8f192 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,8 +15,8 @@ firebaseAppdistributionGradleVersion = "4.2.0" javaxInjectVersion = "1" jsr250ApiVersion = "1.0" kotlinVersion = "1.9.22" -androidGradleVersion = "7.2.1" -firebaseGradleVersion = "2.4.1" +androidGradleVersion = "8.7.2" +firebaseGradleVersion = "2.5.2" hiltVersion = "2.50" kotlinxCoroutinesAndroidVersion = "1.6.3" kotlinxCoroutinesCoreVersion = "1.6.3" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3c8225c29..6b97c975f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sat Mar 02 04:09:08 KST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/koin/build.gradle.kts b/koin/build.gradle.kts index 1c28bd992..26f6bbb46 100644 --- a/koin/build.gradle.kts +++ b/koin/build.gradle.kts @@ -79,7 +79,7 @@ android { fun getPropertyKey(propertyKey: String): String { val nullableProperty: String? = - gradleLocalProperties(rootDir).getProperty(propertyKey) + gradleLocalProperties(rootDir, providers).getProperty(propertyKey) return nullableProperty ?: "null" } From 018378bb36d0fb2939a0588997fe7d1b6e6d659c Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 20:25:21 +0900 Subject: [PATCH 092/138] add: Singleton annotation --- .../in/koreatech/koin/core/di/CoroutineDispatchersModule.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt b/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt index f7813eb18..fc8b3f94c 100644 --- a/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt +++ b/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt @@ -10,23 +10,29 @@ import `in`.koreatech.koin.core.qualifier.MainDispatcher import `in`.koreatech.koin.core.qualifier.UnconfinedDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module object CoroutineDispatchersModule { + @IoDispatcher + @Singleton @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO @UnconfinedDispatcher + @Singleton @Provides fun providesUnconfinedDispatcher(): CoroutineDispatcher = Dispatchers.Unconfined @DefaultDispatcher + @Singleton @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default @MainDispatcher + @Singleton @Provides fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main } \ No newline at end of file From 1e87075b9cca21da999236db9c0c5ad3ac6ffa05 Mon Sep 17 00:00:00 2001 From: Thirfir <86772949+ThirFir@users.noreply.github.com> Date: Wed, 6 Nov 2024 20:26:05 +0900 Subject: [PATCH 093/138] update firebase cd to java 17 --- .github/workflows/firebase_cd.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/firebase_cd.yml b/.github/workflows/firebase_cd.yml index 3f61bd0b3..f188d0e14 100644 --- a/.github/workflows/firebase_cd.yml +++ b/.github/workflows/firebase_cd.yml @@ -8,11 +8,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: set up JDK 11 + - name: set up JDK 17 uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: '11' + java-version: '17' - name: Make gradlew executable run: chmod +x ./gradlew @@ -90,4 +90,4 @@ jobs: fields: repo,message,commit,author,action,eventName,ref,workflow,job,took env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - if: always() \ No newline at end of file + if: always() From 56bd1d76ac8ce9bc0308629aa3a10e77ea10d57a Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 20:59:13 +0900 Subject: [PATCH 094/138] upgrade hilt version --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9b8c8f192..5d7be19ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ jsr250ApiVersion = "1.0" kotlinVersion = "1.9.22" androidGradleVersion = "8.7.2" firebaseGradleVersion = "2.5.2" -hiltVersion = "2.50" +hiltVersion = "2.52" kotlinxCoroutinesAndroidVersion = "1.6.3" kotlinxCoroutinesCoreVersion = "1.6.3" kotlinxSerializationVersionVersion = "1.6.3" @@ -50,7 +50,7 @@ butterknifeVersion = "10.1.0" googleServiceVersion = "4.3.14" composeNavigationVersion = "2.7.7" orbitVersion = "7.0.1" -hiltComposeVersion = "1.0.0" +hiltComposeVersion = "1.2.0" markermanVersion = "2.3.0" coilVersion = "2.6.0" napier = "2.6.1" From 1ed35ff4765dcd9689ec2b1a4ba33d4d91bc5ccf Mon Sep 17 00:00:00 2001 From: Thirfir <86772949+ThirFir@users.noreply.github.com> Date: Wed, 6 Nov 2024 21:13:53 +0900 Subject: [PATCH 095/138] Update gradle.properties --- gradle.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle.properties b/gradle.properties index 6d8dbb94c..a7d0cf7e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,6 +27,7 @@ android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=false android.nonFinalResIds=false +android.enableR8.fullMode = false # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit From d03995cf8662c330ee67cc83f04be7eab9c3b9d3 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 21:24:18 +0900 Subject: [PATCH 096/138] delete singleton annotation --- .../in/koreatech/koin/core/di/CoroutineDispatchersModule.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt b/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt index fc8b3f94c..0c6d668b2 100644 --- a/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt +++ b/core/src/main/java/in/koreatech/koin/core/di/CoroutineDispatchersModule.kt @@ -10,29 +10,24 @@ import `in`.koreatech.koin.core.qualifier.MainDispatcher import `in`.koreatech.koin.core.qualifier.UnconfinedDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers -import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module object CoroutineDispatchersModule { @IoDispatcher - @Singleton @Provides fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO @UnconfinedDispatcher - @Singleton @Provides fun providesUnconfinedDispatcher(): CoroutineDispatcher = Dispatchers.Unconfined @DefaultDispatcher - @Singleton @Provides fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default @MainDispatcher - @Singleton @Provides fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main } \ No newline at end of file From 66ea8e7fa8678b6b92f19a8d5ba36858c8e926b8 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 21:35:07 +0900 Subject: [PATCH 097/138] Revert "upgrade hilt version" This reverts commit 56bd1d76ac8ce9bc0308629aa3a10e77ea10d57a. --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5d7be19ae..9b8c8f192 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ jsr250ApiVersion = "1.0" kotlinVersion = "1.9.22" androidGradleVersion = "8.7.2" firebaseGradleVersion = "2.5.2" -hiltVersion = "2.52" +hiltVersion = "2.50" kotlinxCoroutinesAndroidVersion = "1.6.3" kotlinxCoroutinesCoreVersion = "1.6.3" kotlinxSerializationVersionVersion = "1.6.3" @@ -50,7 +50,7 @@ butterknifeVersion = "10.1.0" googleServiceVersion = "4.3.14" composeNavigationVersion = "2.7.7" orbitVersion = "7.0.1" -hiltComposeVersion = "1.2.0" +hiltComposeVersion = "1.0.0" markermanVersion = "2.3.0" coilVersion = "2.6.0" napier = "2.6.1" From c5f52a8b14677752c16a717eadad5e953f531bbd Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 21:44:15 +0900 Subject: [PATCH 098/138] add: AndroidEntryPoint --- feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt index e2eba259f..cb9330110 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt @@ -11,9 +11,11 @@ import androidx.compose.ui.platform.ComposeView import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.navigation.compose.rememberNavController +import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.bus.navigation.BusNavigation import `in`.koreatech.koin.feature.bus.R +@AndroidEntryPoint class Bus2Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) From d467ff723f4dd05ab76491db659c20290c85e796 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 21:53:37 +0900 Subject: [PATCH 099/138] add: AndroidEntryPoint --- .../java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt index eaca77a98..8dc5e7148 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/timetablev2/TimetableActivity.kt @@ -9,6 +9,7 @@ import androidx.compose.material.rememberBottomSheetState import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.lifecycle.compose.collectAsStateWithLifecycle +import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.koin.core.appbar.AppBarBase import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.core.util.KeyboardUtils @@ -21,6 +22,7 @@ import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerActivity import `in`.koreatech.koin.ui.navigation.state.MenuState import kotlinx.coroutines.launch +@AndroidEntryPoint class TimetableActivity : KoinNavigationDrawerActivity() { override val screenTitle: String get() = SCREEN_TITLE From 5b5b59ca275e619f90dca427341d71e999d73f41 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 01:45:54 +0900 Subject: [PATCH 100/138] Upgrade agp to 8.4.1 --- business/proguard-rules.pro | 102 +++++++++++++++++++---- core/build.gradle.kts | 2 - data/build.gradle.kts | 2 - gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- koin/proguard-rules.pro | 5 +- 6 files changed, 95 insertions(+), 22 deletions(-) diff --git a/business/proguard-rules.pro b/business/proguard-rules.pro index f1b424510..d34890685 100644 --- a/business/proguard-rules.pro +++ b/business/proguard-rules.pro @@ -1,21 +1,95 @@ # Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# By default, the flags in this file are appended to flags specified +# in /Users/namhoonkim/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} +# Add any project specific keep options here: + +# Begin: Common Proguard rules +-dontwarn com.google.** +# End: Common Proguard rules + +# 에러 발생시 라인 표시 +-keepattributes SourceFile,LineNumberTable + +# jdk 컴파일할 때 발생하는 오류 메시지 방지 +-keepattributes EnclosingMethod + +# 최적화 X +-dontoptimize + +# 사용하지 않는 변수 남김 +-dontshrink + +#public 클래스 난독 시 메서드 호출 문제 발생 가능 +-keep public class * + +# Begin : lib +-keep class com.jakewharton.** { *; } +-keep class com.jpardogo.materialtabstrip.** { *; } +-keep interface com.jakewharton.** { *; } +-keep interface com.jpardogo.materialtabstrip.** { *; } +-keep class com.crashlytics.** { *; } +# End + + +# Begin : material, androidx +-dontwarn com.google.android.material.** +-keep class com.google.android.material.** { *; } -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable +-dontwarn androidx.** +-keep class androidx.** { *; } +-keep interface androidx.** { *; } +#End + + +# Begin: Proguard rules for retrofit2 +-dontwarn java.lang.invoke.** +# Platform calls Class.forName on types which do not exist on Android to determine platform. +-dontnote retrofit2.Platform +# Platform used when running on RoboVM on iOS. Will not be used at runtime. +-dontnote retrofit2.Platform$IOS$MainThreadExecutor +# Platform used when running on Java 8 VMs. Will not be used at runtime. +-dontwarn retrofit2.Platform$Java8 + +# retrofit2 POJO model error +-keepclasseswithmembers class * { + @retrofit2.http.* ; +} +#-keep class com.bcsdlab.kap.community.networks.models.** { *; } +#-keepclassmembers class com.bcsdlab.kap.community.networks.models.** { *; } + +# Retain generic type information for use by reflection by converters and adapters. +-keepattributes Signature +# Retain declared checked exceptions for use by a Proxy instance. +-keepattributes Exceptions +# End: Proguard rules for retrofit2 + +# Begin: Proguard rules for okhttp3 +-keep class okhttp3.** { *; } +-keep interface okhttp3.** { *; } +-dontwarn okhttp3.** +-dontwarn okio.** +# End: Proguard rules for okhttp3 + +# Begin: Proguard rules for Firebase +# Authentication +-keepattributes *Annotation* +# Realtime database +-keepattributes Signature +# End: Proguard rules for Firebase + +# Proguard rules for BottomNavigationHelper +#-keepclassmembers class android.support.design.internal.BottomNavigationMenuView { +# boolean mShiftingMode; +#} +-keep class com.kakao.sdk.**.model.* { ; } +-keep class * extends com.google.gson.TypeAdapter +#} -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile +-dontwarn org.jspecify.annotations.NullMarked +-dontwarn top.defaults.checkerboarddrawable.CheckerboardDrawable \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 058cdb86b..eb415f559 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -8,7 +8,6 @@ android { buildTypes { getByName("debug") { - isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) @@ -16,7 +15,6 @@ android { } getByName("release") { - isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 3f4ad88bf..d9994d4ad 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -13,7 +13,6 @@ android { buildTypes { getByName("debug") { - isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) @@ -21,7 +20,6 @@ android { } getByName("release") { - isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9b8c8f192..cefd60fbf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ firebaseAppdistributionGradleVersion = "4.2.0" javaxInjectVersion = "1" jsr250ApiVersion = "1.0" kotlinVersion = "1.9.22" -androidGradleVersion = "8.7.2" +androidGradleVersion = "8.4.1" firebaseGradleVersion = "2.5.2" hiltVersion = "2.50" kotlinxCoroutinesAndroidVersion = "1.6.3" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6b97c975f..6638b49b0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Mar 02 04:09:08 KST 2024 +#Thu Nov 07 01:02:31 KST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/koin/proguard-rules.pro b/koin/proguard-rules.pro index 0657151ad..d34890685 100644 --- a/koin/proguard-rules.pro +++ b/koin/proguard-rules.pro @@ -89,4 +89,7 @@ #} -keep class com.kakao.sdk.**.model.* { ; } -keep class * extends com.google.gson.TypeAdapter -#} \ No newline at end of file +#} + +-dontwarn org.jspecify.annotations.NullMarked +-dontwarn top.defaults.checkerboarddrawable.CheckerboardDrawable \ No newline at end of file From 610e1f7d35daa62ecf84ec48cf64c7cf6171295b Mon Sep 17 00:00:00 2001 From: Thirfir <86772949+ThirFir@users.noreply.github.com> Date: Thu, 7 Nov 2024 01:46:53 +0900 Subject: [PATCH 101/138] =?UTF-8?q?Update=20playstore=5Fcd=20=EC=9E=90?= =?UTF-8?q?=EB=B0=94=2017?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/playstore_cd.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/playstore_cd.yml b/.github/workflows/playstore_cd.yml index 871c8b395..bcffa3abd 100644 --- a/.github/workflows/playstore_cd.yml +++ b/.github/workflows/playstore_cd.yml @@ -8,11 +8,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: set up JDK 11 + - name: set up JDK 17 uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: '11' + java-version: '17' - name: Make gradlew executable run: chmod +x ./gradlew @@ -88,11 +88,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: set up JDK 11 + - name: set up JDK 17 uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: '11' + java-version: '17' - name: Make gradlew executable run: chmod +x ./gradlew @@ -162,4 +162,4 @@ jobs: fields: repo,message,commit,author,action,eventName,ref,workflow,job,took env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - if: always() \ No newline at end of file + if: always() From f5074ab34f40cda5ca542651abeb18949b4f1b73 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 02:00:24 +0900 Subject: [PATCH 102/138] fix: 0 -> FLAG_IMMUTABLE --- koin/src/main/java/in/koreatech/koin/ui/bus/BusWidget.java | 4 +++- .../in/koreatech/koin/ui/dining/appwidget/DiningAppWidget.kt | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/koin/src/main/java/in/koreatech/koin/ui/bus/BusWidget.java b/koin/src/main/java/in/koreatech/koin/ui/bus/BusWidget.java index 59f1f6323..c07f0cfc7 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/bus/BusWidget.java +++ b/koin/src/main/java/in/koreatech/koin/ui/bus/BusWidget.java @@ -1,5 +1,7 @@ package in.koreatech.koin.ui.bus; +import static android.app.PendingIntent.FLAG_IMMUTABLE; + import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; @@ -354,7 +356,7 @@ public String translatePlaceEnglishToKorean(String place) { */ private static PendingIntent getPendingSelfIntent(Context context, int appWidgetId, String action) { Intent intent = new Intent(context, BusWidget.class).setAction(action); - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, intent, 0); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, intent, FLAG_IMMUTABLE); return pendingIntent; } } diff --git a/koin/src/main/java/in/koreatech/koin/ui/dining/appwidget/DiningAppWidget.kt b/koin/src/main/java/in/koreatech/koin/ui/dining/appwidget/DiningAppWidget.kt index 94dae6474..605651503 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/dining/appwidget/DiningAppWidget.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/dining/appwidget/DiningAppWidget.kt @@ -7,6 +7,7 @@ import `in`.koreatech.koin.domain.usecase.dining.GetDiningUseCase import `in`.koreatech.koin.domain.util.DiningUtil import `in`.koreatech.koin.domain.util.TimeUtil import android.app.PendingIntent +import android.app.PendingIntent.FLAG_IMMUTABLE import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider import android.content.ComponentName @@ -216,7 +217,7 @@ class DiningAppWidget : AppWidgetProvider() { viewNum: Int ) { val intent = Intent(context, DiningAppWidget::class.java).setAction(name) - val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0) + val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, FLAG_IMMUTABLE) remoteViews.setOnClickPendingIntent(viewNum, pendingIntent) } From 1ecadc45f55fc572ca148fcad5147ca54c9fcccf Mon Sep 17 00:00:00 2001 From: Jokwanhee Date: Thu, 7 Nov 2024 10:05:22 +0900 Subject: [PATCH 103/138] =?UTF-8?q?[add]=20=EA=B0=95=EC=9D=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=8B=9C=20=EC=82=AD=EC=A0=9C=20=ED=9B=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/data/api/auth/TimetableAuthApi.kt | 5 ++++ .../repository/TimetableRepositoryImpl.kt | 4 ++++ .../remote/TimetableRemoteDataSource.kt | 4 ++++ .../domain/repository/TimetableRepository.kt | 1 + .../timetable/viewmodel/TimetableViewModel.kt | 23 ++++++++++--------- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt index ccaa9d6ec..6683c7bba 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/auth/TimetableAuthApi.kt @@ -65,6 +65,11 @@ interface TimetableAuthApi { @Path("lectureId") lectureId: Int ): Response + @DELETE("/v2/timetables/lectures") + suspend fun deleteTimetableLectures( + @Query("timetable_lecture_ids") lectureIds : List + ): Response + @DELETE("/v2/all/timetables/frame") suspend fun deleteAllTimetableFrame() } \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt index a9a839f91..448afa925 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/TimetableRepositoryImpl.kt @@ -95,6 +95,10 @@ class TimetableRepositoryImpl @Inject constructor( timetableRemoteDataSource.deleteTimetableFrameLecture(frameId, lectureId) } + override suspend fun deleteTimetableLectures(lectureIds: List): Result = runCatching { + timetableRemoteDataSource.deleteTimetableLectures(lectureIds) + } + override suspend fun deleteAllTimetableFrame() { TODO("Not yet implemented") } diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt index ff30974cf..9fa87eb23 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/TimetableRemoteDataSource.kt @@ -60,5 +60,9 @@ class TimetableRemoteDataSource @Inject constructor( lectureId: Int ) = timetableAuthApi.deleteTimetableFrameLecture(frameId, lectureId) + suspend fun deleteTimetableLectures( + lectureIds: List + ) = timetableAuthApi.deleteTimetableLectures(lectureIds) + suspend fun deleteAllTimetableFrame() = timetableAuthApi.deleteAllTimetableFrame() } \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt index dfdfa9cfd..fac56fd74 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/TimetableRepository.kt @@ -26,6 +26,7 @@ interface TimetableRepository { suspend fun deleteTimetableFrame() suspend fun deleteTimetableLecture(id: Int): Result + suspend fun deleteTimetableLectures(lectureIds: List): Result suspend fun deleteTimetableFrameLecture(frameId: Int, lectureId: Int): Result suspend fun deleteAllTimetableFrame() diff --git a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt index 95dfe1dc3..358d8f505 100644 --- a/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt +++ b/feature/timetable/src/main/java/in/koreatech/koin/feature/timetable/viewmodel/TimetableViewModel.kt @@ -245,23 +245,23 @@ class TimetableViewModel @Inject constructor( postLocalTimetableLectures(timetables) } false -> { - // TODO : 로그인 시 중복에 대한 강의 추가 - val ids = mutableListOf() + val ids = mutableSetOf() uiState.value.duplicationLecture?.classTime?.forEach { time -> uiState.value.timetableLectures.timetable.filter { it.classTime.contains(time) } .forEach { lecture -> ids.add(lecture.id) } } - // TODO : ids 요청 쿼리 파라미터로 삭제 API 연결 -// deleteTimetableLecturesUseCase(ids).onSuccess { - // TODO : 삭제 후, duplicationLecture 강의 추가 API 연결 -// uiState.value.duplicationLecture?.let { lecture -> -// addTimetableLectures(lecture) -// } ?: return@onSuccess -// }.onFailure { -// } - + viewModelScope.launch { + timetableRepository.deleteTimetableLectures(ids.toList()).onSuccess { + uiState.value.duplicationLecture?.let { lecture -> + addTimetableLectures(lecture) + } ?: return@onSuccess + }.onFailure { + // TODO : 로그인 시 중복 강의 삭제 실패 + Timber.e("Delete Lectures : ${it.message}") + } + } } } } @@ -289,6 +289,7 @@ class TimetableViewModel @Inject constructor( timetableLectures = timetableLectures, timetableEvents = timetableLectures.getTimetableEvents(), clickedTimetableEvents = emptyList(), + isLectureDuplicationDialogVisible = false, selectedLecture = null, loading = false ) From 64db23128fcf0e396b3bbb1c47e56cebeac46921 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 01:55:18 +0900 Subject: [PATCH 104/138] =?UTF-8?q?add:=20=EB=8C=80=EC=84=B1,=20=EC=8B=9C?= =?UTF-8?q?=EB=82=B4=EB=B2=84=EC=8A=A4=20=EA=B3=B5=ED=86=B5=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=ED=91=9C=20=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/CommonTimetableItem.kt | 47 +++++++ .../composable/CommonTimetableView.kt | 127 ++++++++++++++++++ .../bus/screen/timetable/type/DaytimeType.kt | 5 + .../timetable/type/ExpressDirectionType.kt | 11 ++ .../viewstate/ExpressTimetableViewState.kt | 16 +++ feature/bus/src/main/res/values/strings.xml | 5 + 6 files changed, 211 insertions(+) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableItem.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/DaytimeType.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableItem.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableItem.kt new file mode 100644 index 000000000..fc5a1cbb9 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableItem.kt @@ -0,0 +1,47 @@ +package `in`.koreatech.bus.screen.timetable.composable + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.viewstate.ArrivalViewState +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme + +@Composable +internal fun CommonTimetableItem( + arrival: ArrivalViewState, + textStyle: TextStyle, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + ) { + Text( + modifier = Modifier.padding(vertical = 16.dp), + text = arrival.arrivalTime, + style = textStyle, + ) + HorizontalDivider( + color = KoinTheme.colors.neutral200, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun CommonTimetableItemPreview() { + CommonTimetableItem( + arrival = ArrivalViewState( + arrivalTime = "09:00" + ), + textStyle = KoinTheme.typography.bold18.copy( + color = KoinTheme.colors.warning500 + ), + modifier = Modifier.padding(vertical = 12.dp) + ) +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt new file mode 100644 index 000000000..a253ce8e8 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt @@ -0,0 +1,127 @@ +package `in`.koreatech.bus.screen.timetable.composable + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.screen.timetable.type.DaytimeType +import `in`.koreatech.bus.viewstate.ArrivalViewState +import `in`.koreatech.bus.viewstate.ExpressTimetableViewState +import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R + +@Composable +internal fun CommonTimetableView( + timetable: ExpressTimetableViewState, + modifier: Modifier = Modifier +) { + KoinSurface( + modifier = modifier + ) { + Column( + modifier = Modifier.padding(horizontal = 24.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth().padding(top = 16.dp) + ) { + Column( + modifier = Modifier.weight(1f).padding(end = 8.dp) + ) { + Text( + text = stringResource(R.string.am), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.neutral600 + ) + + timetable.arrivals[DaytimeType.AM]?.forEach { + CommonTimetableItem( + arrival = it, + textStyle = KoinTheme.typography.bold18.copy( + color = KoinTheme.colors.warning500 + ), + modifier = Modifier + ) + } + } + + Column( + modifier = Modifier.weight(1f).padding(start = 8.dp) + ) { + Text( + text = stringResource(R.string.pm), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.neutral600 + ) + + timetable.arrivals[DaytimeType.PM]?.forEach { + CommonTimetableItem( + arrival = it, + textStyle = KoinTheme.typography.bold18.copy( + color = KoinTheme.colors.info700 + ), + modifier = Modifier + ) + } + } + } + + Text( + modifier = Modifier.padding(vertical = 8.dp), + text = stringResource(R.string.updated_at) + " " + timetable.updatedAt, + style = KoinTheme.typography.regular14, + color = KoinTheme.colors.neutral500 + ) + } + } +} + +@Preview +@Composable +private fun CommonTimetableViewPreview() { + CommonTimetableView( + modifier = Modifier.fillMaxSize(), + timetable = ExpressTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ), + ArrivalViewState( + arrivalTime = "21:00" + ), + ArrivalViewState( + arrivalTime = "21:30" + ), + ArrivalViewState( + arrivalTime = "22:00" + ), + ArrivalViewState( + arrivalTime = "22:30" + ), + ) + ) + ) + ) +} diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/DaytimeType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/DaytimeType.kt new file mode 100644 index 000000000..a39fc6a8f --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/DaytimeType.kt @@ -0,0 +1,5 @@ +package `in`.koreatech.bus.screen.timetable.type + +enum class DaytimeType { + AM, PM +} diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt new file mode 100644 index 000000000..e75fc6cf5 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt @@ -0,0 +1,11 @@ +package `in`.koreatech.bus.screen.timetable.type + +import androidx.annotation.StringRes +import `in`.koreatech.koin.feature.bus.R + +enum class ExpressDirectionType( + @StringRes val titleRes: Int +) { + TO_BYEONGCHEON(R.string.to_byeongcheon), + TO_CHEONAN(R.string.to_cheonan), +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt b/feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt new file mode 100644 index 000000000..cfc8cef08 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt @@ -0,0 +1,16 @@ +package `in`.koreatech.bus.viewstate + +import androidx.compose.runtime.Immutable +import `in`.koreatech.bus.screen.timetable.type.DaytimeType + +@Immutable +data class ExpressTimetableViewState( + val arrivals: Map>, + val updatedAt: String +) + +data class ArrivalViewState( + val arrivalTime: String, +) + +// TODO : 임시 데이터, API 아직 없음 \ No newline at end of file diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index caaed9e72..a2d066a36 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -13,6 +13,11 @@ 주중 주말 순환 + 병천방면 + 천안방면 + 오전 + 오후 + 업데이트 날짜 : From 1b0d0ac45be90dc7a85176c2531c8de75f6f0253 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 01:55:32 +0900 Subject: [PATCH 105/138] =?UTF-8?q?add:=20=EB=8C=80=EC=84=B1=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=ED=91=9C=20=EC=A0=84=EC=B2=B4=20=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/ExpressTimetableScreen.kt | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt new file mode 100644 index 000000000..86686ba53 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt @@ -0,0 +1,108 @@ +package `in`.koreatech.bus.screen.timetable.composable + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.screen.timetable.type.DaytimeType +import `in`.koreatech.bus.screen.timetable.type.ExpressDirectionType +import `in`.koreatech.bus.viewstate.ArrivalViewState +import `in`.koreatech.bus.viewstate.ExpressTimetableViewState +import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme + +@Composable +internal fun ExpressTimetableScreen( + timetable: ExpressTimetableViewState, + modifier: Modifier = Modifier, + onDirectionChanged: (ExpressDirectionType) -> Unit = {} +) { + + var selectedDirectionTypeIndex by rememberSaveable { mutableIntStateOf(ExpressDirectionType.TO_BYEONGCHEON.ordinal) } + val context = LocalContext.current + + Column( + modifier = modifier + ) { + TextChipGroup( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp, horizontal = 24.dp), + titles = ExpressDirectionType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedDirectionTypeIndex = ExpressDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) + ) + + CommonTimetableView( + timetable = timetable, + modifier = Modifier.fillMaxSize() + ) + } + + LaunchedEffect(selectedDirectionTypeIndex) { + onDirectionChanged(ExpressDirectionType.entries[selectedDirectionTypeIndex]) + } +} + +@Preview(showBackground = true) +@Composable +private fun ExpressTimetableScreenPreview() { + ExpressTimetableScreen( + modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), + timetable = ExpressTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ), + ArrivalViewState( + arrivalTime = "21:00" + ), + ArrivalViewState( + arrivalTime = "21:30" + ), + ArrivalViewState( + arrivalTime = "22:00" + ), + ArrivalViewState( + arrivalTime = "22:30" + ), + ArrivalViewState( + arrivalTime = "23:00" + ), + ArrivalViewState( + arrivalTime = "23:30" + ) + ), + ) + ) + ) +} \ No newline at end of file From 10bbe6da76388a4cd43f41a06f29c8403d034df0 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 01:56:51 +0900 Subject: [PATCH 106/138] =?UTF-8?q?fix:=20=EB=8C=80=EC=84=B1,=20=EC=8B=9C?= =?UTF-8?q?=EB=82=B4=EB=B2=84=EC=8A=A4=20data=20=ED=98=95=ED=83=9C=20?= =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=98=EB=AF=80=EB=A1=9C=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=ED=83=80=EC=9E=85=EC=9D=84=20=EA=B7=B8?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EC=B6=B0=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/CommonTimetableView.kt | 6 +++--- .../composable/ExpressTimetableScreen.kt | 18 +++++++++--------- ...DirectionType.kt => CommonDirectionType.kt} | 2 +- ...iewState.kt => CommonTimetableViewState.kt} | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) rename feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/{ExpressDirectionType.kt => CommonDirectionType.kt} (88%) rename feature/bus/src/main/java/in/koreatech/bus/viewstate/{ExpressTimetableViewState.kt => CommonTimetableViewState.kt} (90%) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt index a253ce8e8..2c87b184a 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt @@ -13,14 +13,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.bus.screen.timetable.type.DaytimeType import `in`.koreatech.bus.viewstate.ArrivalViewState -import `in`.koreatech.bus.viewstate.ExpressTimetableViewState +import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R @Composable internal fun CommonTimetableView( - timetable: ExpressTimetableViewState, + timetable: CommonTimetableViewState, modifier: Modifier = Modifier ) { KoinSurface( @@ -88,7 +88,7 @@ internal fun CommonTimetableView( private fun CommonTimetableViewPreview() { CommonTimetableView( modifier = Modifier.fillMaxSize(), - timetable = ExpressTimetableViewState( + timetable = CommonTimetableViewState( updatedAt = "2024-09-21", arrivals = mapOf( DaytimeType.AM to listOf( diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt index 86686ba53..6dc530d41 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt @@ -17,20 +17,20 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import `in`.koreatech.bus.screen.timetable.type.DaytimeType -import `in`.koreatech.bus.screen.timetable.type.ExpressDirectionType +import `in`.koreatech.bus.screen.timetable.type.CommonDirectionType import `in`.koreatech.bus.viewstate.ArrivalViewState -import `in`.koreatech.bus.viewstate.ExpressTimetableViewState +import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup import `in`.koreatech.koin.core.designsystem.theme.KoinTheme @Composable internal fun ExpressTimetableScreen( - timetable: ExpressTimetableViewState, + timetable: CommonTimetableViewState, modifier: Modifier = Modifier, - onDirectionChanged: (ExpressDirectionType) -> Unit = {} + onDirectionChanged: (CommonDirectionType) -> Unit = {} ) { - var selectedDirectionTypeIndex by rememberSaveable { mutableIntStateOf(ExpressDirectionType.TO_BYEONGCHEON.ordinal) } + var selectedDirectionTypeIndex by rememberSaveable { mutableIntStateOf(CommonDirectionType.TO_BYEONGCHEON.ordinal) } val context = LocalContext.current Column( @@ -40,9 +40,9 @@ internal fun ExpressTimetableScreen( modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp, horizontal = 24.dp), - titles = ExpressDirectionType.entries.map { stringResource(it.titleRes) }, + titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, onChipSelected = { title -> - selectedDirectionTypeIndex = ExpressDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 + selectedDirectionTypeIndex = CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 }, selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) ) @@ -54,7 +54,7 @@ internal fun ExpressTimetableScreen( } LaunchedEffect(selectedDirectionTypeIndex) { - onDirectionChanged(ExpressDirectionType.entries[selectedDirectionTypeIndex]) + onDirectionChanged(CommonDirectionType.entries[selectedDirectionTypeIndex]) } } @@ -63,7 +63,7 @@ internal fun ExpressTimetableScreen( private fun ExpressTimetableScreenPreview() { ExpressTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), - timetable = ExpressTimetableViewState( + timetable = CommonTimetableViewState( updatedAt = "2024-09-21", arrivals = mapOf( DaytimeType.AM to listOf( diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt similarity index 88% rename from feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt rename to feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt index e75fc6cf5..108382464 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ExpressDirectionType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt @@ -3,7 +3,7 @@ package `in`.koreatech.bus.screen.timetable.type import androidx.annotation.StringRes import `in`.koreatech.koin.feature.bus.R -enum class ExpressDirectionType( +enum class CommonDirectionType( @StringRes val titleRes: Int ) { TO_BYEONGCHEON(R.string.to_byeongcheon), diff --git a/feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt b/feature/bus/src/main/java/in/koreatech/bus/viewstate/CommonTimetableViewState.kt similarity index 90% rename from feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt rename to feature/bus/src/main/java/in/koreatech/bus/viewstate/CommonTimetableViewState.kt index cfc8cef08..8051bfffc 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/viewstate/ExpressTimetableViewState.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/viewstate/CommonTimetableViewState.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.Immutable import `in`.koreatech.bus.screen.timetable.type.DaytimeType @Immutable -data class ExpressTimetableViewState( +data class CommonTimetableViewState( val arrivals: Map>, val updatedAt: String ) From 73847764a1e85657de32744918846e751ae0a1a5 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 02:06:14 +0900 Subject: [PATCH 107/138] =?UTF-8?q?add:=20=EC=8B=9C=EB=82=B4=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20=EC=8B=9C=EA=B0=84=ED=91=9C=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/CityTimetableScreen.kt | 109 ++++++++++++++++++ .../timetable/type/CityBusNumberType.kt | 10 ++ feature/bus/src/main/res/values/strings.xml | 3 + 3 files changed, 122 insertions(+) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt new file mode 100644 index 000000000..41fd8e42a --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt @@ -0,0 +1,109 @@ +package `in`.koreatech.bus.screen.timetable.composable + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.screen.timetable.type.CityBusNumberType +import `in`.koreatech.bus.screen.timetable.type.CommonDirectionType +import `in`.koreatech.bus.screen.timetable.type.DaytimeType +import `in`.koreatech.bus.viewstate.ArrivalViewState +import `in`.koreatech.bus.viewstate.CommonTimetableViewState +import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme + +@Composable +internal fun CityTimetableScreen( + timetable: CommonTimetableViewState, + modifier: Modifier = Modifier, + onBusNumberChanged: (CityBusNumberType) -> Unit = {}, + onDirectionChanged: (CommonDirectionType) -> Unit = {} +) { + + var selectedBusNumberTypeIndex by rememberSaveable { mutableIntStateOf(CityBusNumberType.N400.ordinal) } + var selectedDirectionTypeIndex by rememberSaveable { mutableIntStateOf(CommonDirectionType.TO_BYEONGCHEON.ordinal) } + val context = LocalContext.current + + Column( + modifier = modifier + ) { + TextChipGroup( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .padding(top = 8.dp, bottom = 4.dp), + titles = CityBusNumberType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedBusNumberTypeIndex = CityBusNumberType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedBusNumberTypeIndex) + ) + TextChipGroup( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .padding(top = 4.dp, bottom = 8.dp), + titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedDirectionTypeIndex = CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) + ) + + CommonTimetableView( + timetable = timetable, + modifier = Modifier.fillMaxSize() + ) + } + + LaunchedEffect(selectedBusNumberTypeIndex) { + onBusNumberChanged(CityBusNumberType.entries[selectedBusNumberTypeIndex]) + } + + LaunchedEffect(selectedDirectionTypeIndex) { + onDirectionChanged(CommonDirectionType.entries[selectedDirectionTypeIndex]) + } +} + +@Preview +@Composable +private fun CityTimetableScreenPreview() { + CityTimetableScreen( + modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), + timetable = CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ) + ) + ) + ) + ) +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt new file mode 100644 index 000000000..1e21d62ad --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt @@ -0,0 +1,10 @@ +package `in`.koreatech.bus.screen.timetable.type + +import androidx.annotation.StringRes +import `in`.koreatech.koin.feature.bus.R + +enum class CityBusNumberType( + @StringRes val titleRes: Int +) { + N400(R.string.n400), N405(R.string.n405), N495(R.string.n495) +} \ No newline at end of file diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index a2d066a36..233e11b8c 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -18,6 +18,9 @@ 오전 오후 업데이트 날짜 : + 400번 + 405번 + 495번 From 082cdc12e6b33a3a08f0a5baf644fccbbbf3eae9 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 02:21:53 +0900 Subject: [PATCH 108/138] =?UTF-8?q?add:=20=EC=8B=9C=EA=B0=84=ED=91=9C=20?= =?UTF-8?q?=EB=B7=B0=EB=93=A4=20=ED=83=AD=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/bus/navigation/BusNavigation.kt | 10 ++- .../composable/BusTimetableScreen.kt | 77 +++++++++++++++++++ .../timetable/viewmodel/BusViewModel.kt | 11 --- 3 files changed, 83 insertions(+), 15 deletions(-) delete mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt index 00341c717..15f7eeea2 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt @@ -2,20 +2,19 @@ package `in`.koreatech.bus.navigation import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import `in`.koreatech.bus.screen.timetable.viewmodel.BusViewModel +import `in`.koreatech.bus.screen.timetable.composable.BusTimetableScreen @Composable fun BusNavigation( modifier: Modifier = Modifier, navController: NavHostController = rememberNavController(), - viewModel: BusViewModel = hiltViewModel() ) { NavHost( @@ -30,7 +29,10 @@ fun BusNavigation( ) { composable { - + BusTimetableScreen( + modifier = Modifier.fillMaxSize(), + onNavigationIconClick = { navController.popBackStack() } + ) } } } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index 44d87e7bc..bfb73ee68 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -24,8 +24,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import `in`.koreatech.bus.screen.timetable.type.BusType +import `in`.koreatech.bus.screen.timetable.type.DaytimeType import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType import `in`.koreatech.bus.screen.timetable.viewmodel.BusTimetableViewModel +import `in`.koreatech.bus.viewstate.ArrivalViewState +import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.bus.viewstate.ShuttleRegionViewState import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup @@ -141,6 +144,80 @@ internal fun BusTimetableScreen( ) ) } + BusType.EXPRESS.ordinal -> { + ExpressTimetableScreen( + modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), + timetable = CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ), + ArrivalViewState( + arrivalTime = "21:00" + ), + ArrivalViewState( + arrivalTime = "21:30" + ), + ArrivalViewState( + arrivalTime = "22:00" + ), + ArrivalViewState( + arrivalTime = "22:30" + ), + ArrivalViewState( + arrivalTime = "23:00" + ), + ArrivalViewState( + arrivalTime = "23:30" + ) + ), + ) + ) + ) + } + BusType.CITY.ordinal -> { + CityTimetableScreen( + modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), + timetable = CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ) + ) + ) + ) + ) + } } } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt deleted file mode 100644 index aa0234d35..000000000 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package `in`.koreatech.bus.screen.timetable.viewmodel - -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class BusViewModel @Inject constructor( - -) : ViewModel() { -} \ No newline at end of file From 519815e72eb7627c2efb0960dcaffd3cd932e012 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 02:36:10 +0900 Subject: [PATCH 109/138] =?UTF-8?q?refactor:=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B7=B0=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99,=20=EC=8B=9C=EA=B0=84=ED=91=9C?= =?UTF-8?q?=20=ED=94=84=EB=A6=AC=EB=B7=B0=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/BusTimetableScreen.kt | 157 +++--------- .../viewmodel/BusTimetableViewModel.kt | 235 ++++++++++++++++++ 2 files changed, 270 insertions(+), 122 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index bfb73ee68..a91ff4c0c 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -19,10 +19,12 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.bus.screen.timetable.type.BusType import `in`.koreatech.bus.screen.timetable.type.DaytimeType import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType @@ -38,17 +40,24 @@ import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable internal fun BusTimetableScreen( modifier: Modifier = Modifier, onNavigationIconClick: () -> Unit = {}, - viewModel: BusTimetableViewModel = hiltViewModel() + viewModel: BusTimetableViewModel = hiltViewModel(), + previewTab: BusType = BusType.SHUTTLE ) { var selectedTimetableTypeTabIndex by rememberSaveable { mutableIntStateOf(0) } + val shuttleRegions by viewModel.shuttleRegions.collectAsStateWithLifecycle() + val expressTimetable by viewModel.expressTimetable.collectAsStateWithLifecycle() + val cityTimetable by viewModel.cityTimetable.collectAsStateWithLifecycle() + + Column( modifier = modifier ) { @@ -83,139 +92,26 @@ internal fun BusTimetableScreen( } item { + if (LocalInspectionMode.current) + selectedTimetableTypeTabIndex = previewTab.ordinal + when(selectedTimetableTypeTabIndex) { BusType.SHUTTLE.ordinal -> { ShuttleTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), - regions = persistentListOf( - ShuttleRegionViewState( - name = "서울", - timetableOverviews = listOf( - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKDAY, - name = "서울-대전", - ), - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKEND, - name = "서울-대전", - ), - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.CIRCULATION, - name = "서울-대전", - ) - ) - ), - ShuttleRegionViewState( - name = "대전", - timetableOverviews = listOf( - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKDAY, - name = "대전-서울", - ), - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKEND, - name = "대전-서울", - description = "대전에서 서울로 이동하는 노선입니다." - ), - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.CIRCULATION, - name = "대전-서울", - description = "대전에서 서울로 이동하는 노선입니다." - ) - ) - ), - ShuttleRegionViewState( - name = "대구", - timetableOverviews = listOf( - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKDAY, - name = "대구-서울", - ), - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKDAY, - name = "대구-서울", - ), - ShuttleTimetableOverviewViewState( - routeType = ShuttleBusRouteType.WEEKEND, - name = "대구-서울", - ) - ) - ) - ) + regions = shuttleRegions.toPersistentList() ) } BusType.EXPRESS.ordinal -> { ExpressTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), - timetable = CommonTimetableViewState( - updatedAt = "2024-09-21", - arrivals = mapOf( - DaytimeType.AM to listOf( - ArrivalViewState( - arrivalTime = "09:00" - ), - ArrivalViewState( - arrivalTime = "09:30" - ), - ArrivalViewState( - arrivalTime = "10:00" - ), - ArrivalViewState( - arrivalTime = "10:30" - ), - ), DaytimeType.PM to listOf( - ArrivalViewState( - arrivalTime = "14:30" - ), - ArrivalViewState( - arrivalTime = "21:00" - ), - ArrivalViewState( - arrivalTime = "21:30" - ), - ArrivalViewState( - arrivalTime = "22:00" - ), - ArrivalViewState( - arrivalTime = "22:30" - ), - ArrivalViewState( - arrivalTime = "23:00" - ), - ArrivalViewState( - arrivalTime = "23:30" - ) - ), - ) - ) + timetable = expressTimetable ) } BusType.CITY.ordinal -> { CityTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), - timetable = CommonTimetableViewState( - updatedAt = "2024-09-21", - arrivals = mapOf( - DaytimeType.AM to listOf( - ArrivalViewState( - arrivalTime = "09:00" - ), - ArrivalViewState( - arrivalTime = "09:30" - ), - ArrivalViewState( - arrivalTime = "10:00" - ), - ArrivalViewState( - arrivalTime = "10:30" - ), - ), DaytimeType.PM to listOf( - ArrivalViewState( - arrivalTime = "14:30" - ) - ) - ) - ) + timetable = cityTimetable ) } } @@ -227,8 +123,25 @@ internal fun BusTimetableScreen( @Preview(showBackground = true) @Composable -private fun BusTimetableScreenPreview() { +private fun BusTimetableShuttleScreenPreview() { + BusTimetableScreen( + modifier = Modifier.fillMaxSize(), + previewTab = BusType.SHUTTLE + ) +} +@Preview(showBackground = true) +@Composable +private fun BusTimetableExpressScreenPreview() { + BusTimetableScreen( + modifier = Modifier.fillMaxSize(), + previewTab = BusType.EXPRESS + ) +} +@Preview(showBackground = true) +@Composable +private fun BusTimetableCityScreenPreview() { BusTimetableScreen( - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), + previewTab = BusType.CITY ) } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt index ffd834b4a..774e380fe 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt @@ -1,7 +1,17 @@ package `in`.koreatech.bus.screen.timetable.viewmodel import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.bus.screen.timetable.type.DaytimeType +import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType +import `in`.koreatech.bus.viewstate.ArrivalViewState +import `in`.koreatech.bus.viewstate.CommonTimetableViewState +import `in`.koreatech.bus.viewstate.ShuttleRegionViewState +import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn import javax.inject.Inject @HiltViewModel @@ -9,4 +19,229 @@ class BusTimetableViewModel @Inject constructor( ) : ViewModel() { + /** 임시 데이터 모음 */ + val shuttleRegions = flow { + emit( + listOf( + ShuttleRegionViewState( + name = "서울", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "서울-대전", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "서울-대전", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.CIRCULATION, + name = "서울-대전", + ) + ) + ), + ShuttleRegionViewState( + name = "대전", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대전-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "대전-서울", + description = "토요일, 일요일 운행" + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.CIRCULATION, + name = "대전-서울", + description = "토요일, 천안아산역" + ) + ) + ), + ShuttleRegionViewState( + name = "대구", + timetableOverviews = listOf( + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대구-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKDAY, + name = "대구-서울", + ), + ShuttleTimetableOverviewViewState( + routeType = ShuttleBusRouteType.WEEKEND, + name = "대구-서울", + description = "금요일 하교 추가" + ) + ) + ) + ) + ) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = emptyList() + ) + val expressTimetable = flow { + emit( + CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ), + ArrivalViewState( + arrivalTime = "21:00" + ), + ArrivalViewState( + arrivalTime = "21:30" + ), + ArrivalViewState( + arrivalTime = "22:00" + ), + ArrivalViewState( + arrivalTime = "22:30" + ), + ArrivalViewState( + arrivalTime = "23:00" + ), + ArrivalViewState( + arrivalTime = "23:30" + ) + ), + ) + ) + ) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ), + ArrivalViewState( + arrivalTime = "21:00" + ), + ArrivalViewState( + arrivalTime = "21:30" + ), + ArrivalViewState( + arrivalTime = "22:00" + ), + ArrivalViewState( + arrivalTime = "22:30" + ), + ArrivalViewState( + arrivalTime = "23:00" + ), + ArrivalViewState( + arrivalTime = "23:30" + ) + ), + ) + ) + ) + val cityTimetable = flow { + emit( + CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ) + ) + ) + ) + ) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = CommonTimetableViewState( + updatedAt = "2024-09-21", + arrivals = mapOf( + DaytimeType.AM to listOf( + ArrivalViewState( + arrivalTime = "09:00" + ), + ArrivalViewState( + arrivalTime = "09:30" + ), + ArrivalViewState( + arrivalTime = "10:00" + ), + ArrivalViewState( + arrivalTime = "10:30" + ), + ), DaytimeType.PM to listOf( + ArrivalViewState( + arrivalTime = "14:30" + ), + ArrivalViewState( + arrivalTime = "21:00" + ), + ArrivalViewState( + arrivalTime = "21:30" + ), + ArrivalViewState( + arrivalTime = "22:00" + ), + ArrivalViewState( + arrivalTime = "22:30" + ), + ArrivalViewState( + arrivalTime = "23:00" + ), + ArrivalViewState( + arrivalTime = "23:30" + ) + ), + ) + ) + ) } \ No newline at end of file From 7d5e28314b9dfdaef6b57cdd30764718121facfa Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 02:51:17 +0900 Subject: [PATCH 110/138] =?UTF-8?q?add:=20=EB=B2=84=EC=8A=A4=20=EA=B3=B5?= =?UTF-8?q?=EC=A7=80=20=ED=97=A4=EB=93=9C=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EB=B7=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/BusTimetableScreen.kt | 45 ++++++++++++++----- .../viewmodel/BusTimetableViewModel.kt | 7 +++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index a91ff4c0c..43d212755 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -3,43 +3,42 @@ package `in`.koreatech.bus.screen.timetable.composable import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Close import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.bus.screen.timetable.type.BusType -import `in`.koreatech.bus.screen.timetable.type.DaytimeType -import `in`.koreatech.bus.screen.timetable.type.ShuttleBusRouteType import `in`.koreatech.bus.screen.timetable.viewmodel.BusTimetableViewModel -import `in`.koreatech.bus.viewstate.ArrivalViewState -import `in`.koreatech.bus.viewstate.CommonTimetableViewState -import `in`.koreatech.bus.viewstate.ShuttleRegionViewState -import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState -import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup import `in`.koreatech.koin.core.designsystem.component.tab.KoinTabRow import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R -import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @@ -57,6 +56,7 @@ internal fun BusTimetableScreen( val expressTimetable by viewModel.expressTimetable.collectAsStateWithLifecycle() val cityTimetable by viewModel.cityTimetable.collectAsStateWithLifecycle() + val headArticle by viewModel.headArticle.collectAsStateWithLifecycle() Column( modifier = modifier @@ -69,7 +69,7 @@ internal fun BusTimetableScreen( LazyColumn { item { Column( - modifier = Modifier.fillMaxWidth().background(Color.White).padding(start = 24.dp) + modifier = Modifier.fillMaxWidth().background(Color.White).padding(horizontal = 24.dp) ) { Text( text = stringResource(R.string.shuttle_timetable), @@ -80,6 +80,31 @@ internal fun BusTimetableScreen( text = stringResource(R.string.request_for_incorrect_information), iconRes = R.drawable.ic_caution ) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + .background( + color = KoinTheme.colors.info100, + shape = RoundedCornerShape(8.dp) + ).padding(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + text = headArticle, + style = KoinTheme.typography.medium14, + color = KoinTheme.colors.primary500, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Icon( + modifier = Modifier.padding(start = 4.dp).size(16.dp), + imageVector = Icons.Rounded.Close, + contentDescription = headArticle, + tint = KoinTheme.colors.neutral300 + ) + } } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt index 774e380fe..b88b2e0b5 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt @@ -244,4 +244,11 @@ class BusTimetableViewModel @Inject constructor( ) ) ) + val headArticle = flow { + emit("[긴급] 9.27(금) 대학등교방향 천안셔틀버스 터미널 미정차 알림(천안역에서 승차바람)") + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = "[긴급] 9.27(금) 대학등교방향 천안셔틀버스 터미널 미정차 알림(천안역에서 승차바람)" + ) } \ No newline at end of file From b9750cef4fcf23a47a6e430ddda9a5156728dca6 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:05:07 +0900 Subject: [PATCH 111/138] =?UTF-8?q?fix:=20Activity=20Theme=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt index cb9330110..bc15d77ba 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt @@ -13,6 +13,7 @@ import androidx.core.view.WindowInsetsCompat import androidx.navigation.compose.rememberNavController import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.bus.navigation.BusNavigation +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R @AndroidEntryPoint @@ -22,10 +23,9 @@ class Bus2Activity : AppCompatActivity() { enableEdgeToEdge() setContentView(R.layout.activity_bus2) findViewById(R.id.compose_view_bus).setContent { - MaterialTheme { + KoinTheme { BusNavigation( - modifier = Modifier.fillMaxSize(), - navController = rememberNavController(), + modifier = Modifier.fillMaxSize() ) } } From 97ef11d5b1793ebab036beb9e9437981ee0a1dc3 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:19:07 +0900 Subject: [PATCH 112/138] =?UTF-8?q?add:=20Onboarding=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/core/onboarding/OnboardingManager.kt | 13 +++++++++++++ .../koin/core/onboarding/OnboardingType.kt | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt index 5ef18fef8..090fb714d 100644 --- a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt +++ b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt @@ -99,6 +99,19 @@ class OnboardingManager @Inject internal constructor( } } + suspend fun getShouldOnboard( + type: OnboardingType, + ) : Boolean { + return onboardingRepository.getShouldOnboarding(type.name) + } + + suspend fun updateShouldOnboard( + type: OnboardingType, + shouldShow: Boolean + ) { + onboardingRepository.updateShouldOnboarding(type.name, shouldShow) + } + fun dismissTooltip() { if (::tooltip.isInitialized) tooltip.dismiss() diff --git a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt index 0dad8b6e7..c6d8746aa 100644 --- a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt +++ b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt @@ -12,5 +12,6 @@ enum class OnboardingType( DINING_IMAGE(R.string.dining_image_tooltip), DINING_NOTIFICATION(0), DINING_SHARE(0), - ARTICLE_KEYWORD(R.string.article_keyword_tooltip) + ARTICLE_KEYWORD(R.string.article_keyword_tooltip), + SHOW_BUS_HEAD_ARTICLE(0) } \ No newline at end of file From 6bf710c62c03db4fd92e885a3daf82bad0aed433 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:20:32 +0900 Subject: [PATCH 113/138] =?UTF-8?q?add:=20=EB=B2=84=EC=8A=A4=20notice=20?= =?UTF-8?q?=EB=85=B8=EC=B6=9C=20=EC=97=AC=EB=B6=80=20=EC=83=81=ED=83=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/bus/build.gradle.kts | 1 + .../composable/BusTimetableScreen.kt | 53 ++++++++++--------- .../viewmodel/BusTimetableViewModel.kt | 21 +++++++- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/feature/bus/build.gradle.kts b/feature/bus/build.gradle.kts index bac9fe443..fd7ad52b5 100644 --- a/feature/bus/build.gradle.kts +++ b/feature/bus/build.gradle.kts @@ -20,6 +20,7 @@ android { dependencies { implementation(project(":core")) implementation(project(":domain")) + implementation(project(":core:onboarding")) implementation(project(":core:designsystem")) implementation(libs.core.ktx) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index 43d212755..c34b748c4 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -56,7 +56,8 @@ internal fun BusTimetableScreen( val expressTimetable by viewModel.expressTimetable.collectAsStateWithLifecycle() val cityTimetable by viewModel.cityTimetable.collectAsStateWithLifecycle() - val headArticle by viewModel.headArticle.collectAsStateWithLifecycle() + val shouldShowNotice by viewModel.shouldShowNotice.collectAsStateWithLifecycle() + val notice by viewModel.notice.collectAsStateWithLifecycle() Column( modifier = modifier @@ -80,30 +81,32 @@ internal fun BusTimetableScreen( text = stringResource(R.string.request_for_incorrect_information), iconRes = R.drawable.ic_caution ) - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp) - .background( - color = KoinTheme.colors.info100, - shape = RoundedCornerShape(8.dp) - ).padding(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - modifier = Modifier.weight(1f), - text = headArticle, - style = KoinTheme.typography.medium14, - color = KoinTheme.colors.primary500, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Icon( - modifier = Modifier.padding(start = 4.dp).size(16.dp), - imageVector = Icons.Rounded.Close, - contentDescription = headArticle, - tint = KoinTheme.colors.neutral300 - ) + if (shouldShowNotice || LocalInspectionMode.current) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + .background( + color = KoinTheme.colors.info100, + shape = RoundedCornerShape(8.dp) + ).padding(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + text = notice, + style = KoinTheme.typography.medium14, + color = KoinTheme.colors.primary500, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Icon( + modifier = Modifier.padding(start = 4.dp).size(16.dp), + imageVector = Icons.Rounded.Close, + contentDescription = notice, + tint = KoinTheme.colors.neutral300 + ) + } } } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt index b88b2e0b5..33bccd885 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt @@ -9,14 +9,17 @@ import `in`.koreatech.bus.viewstate.ArrivalViewState import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.bus.viewstate.ShuttleRegionViewState import `in`.koreatech.bus.viewstate.ShuttleTimetableOverviewViewState +import `in`.koreatech.koin.core.onboarding.OnboardingManager +import `in`.koreatech.koin.core.onboarding.OnboardingType import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class BusTimetableViewModel @Inject constructor( - + private val onboardingManager: OnboardingManager ) : ViewModel() { /** 임시 데이터 모음 */ @@ -244,11 +247,25 @@ class BusTimetableViewModel @Inject constructor( ) ) ) - val headArticle = flow { + val notice = flow { emit("[긴급] 9.27(금) 대학등교방향 천안셔틀버스 터미널 미정차 알림(천안역에서 승차바람)") }.stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = "[긴급] 9.27(금) 대학등교방향 천안셔틀버스 터미널 미정차 알림(천안역에서 승차바람)" ) + + val shouldShowNotice = flow { + emit(onboardingManager.getShouldOnboard(OnboardingType.SHOW_BUS_HEAD_ARTICLE)) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = false + ) + + fun closeNotice() { + viewModelScope.launch { + onboardingManager.updateShouldOnboard(OnboardingType.SHOW_BUS_HEAD_ARTICLE, false) + } + } } \ No newline at end of file From 0a9ee58b91fc2df887444513ef8d955cd071360e Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:23:02 +0900 Subject: [PATCH 114/138] =?UTF-8?q?add:=20Notice=20=EB=8B=AB=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/screen/timetable/composable/BusTimetableScreen.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index c34b748c4..4481f5ffe 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -37,6 +37,7 @@ import `in`.koreatech.bus.screen.timetable.viewmodel.BusTimetableViewModel import `in`.koreatech.koin.core.designsystem.component.tab.KoinTabRow import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar +import `in`.koreatech.koin.core.designsystem.noRippleClickable import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R import kotlinx.collections.immutable.toPersistentList @@ -101,7 +102,9 @@ internal fun BusTimetableScreen( overflow = TextOverflow.Ellipsis ) Icon( - modifier = Modifier.padding(start = 4.dp).size(16.dp), + modifier = Modifier.padding(start = 4.dp).size(16.dp).noRippleClickable { + viewModel.closeNotice() + }, imageVector = Icons.Rounded.Close, contentDescription = notice, tint = KoinTheme.colors.neutral300 From c40b4ffb79fe292ab9e0355e4db88d8befaf2097 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:33:01 +0900 Subject: [PATCH 115/138] =?UTF-8?q?fix:=20Scope=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/core/onboarding/OnboardingModule.kt | 6 ++++-- .../koin/data/di/onboarding/OnboardingModule.kt | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingModule.kt b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingModule.kt index 63573dced..fc7d864f1 100644 --- a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingModule.kt +++ b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingModule.kt @@ -7,14 +7,16 @@ import dagger.hilt.InstallIn import dagger.hilt.android.components.ActivityComponent import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.scopes.ActivityScoped +import dagger.hilt.components.SingletonComponent import `in`.koreatech.koin.domain.repository.OnboardingRepository +import javax.inject.Singleton @Module -@InstallIn(ActivityComponent::class) +@InstallIn(SingletonComponent::class) object OnboardingModule { @Provides - @ActivityScoped + @Singleton fun provideOnboardingManager( onboardingRepository: OnboardingRepository, @ApplicationContext context: Context diff --git a/data/src/main/java/in/koreatech/koin/data/di/onboarding/OnboardingModule.kt b/data/src/main/java/in/koreatech/koin/data/di/onboarding/OnboardingModule.kt index 07472994b..25346c3ef 100644 --- a/data/src/main/java/in/koreatech/koin/data/di/onboarding/OnboardingModule.kt +++ b/data/src/main/java/in/koreatech/koin/data/di/onboarding/OnboardingModule.kt @@ -11,23 +11,25 @@ import dagger.hilt.InstallIn import dagger.hilt.android.components.ActivityComponent import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.scopes.ActivityScoped +import dagger.hilt.components.SingletonComponent import `in`.koreatech.koin.data.repository.OnboardingRepositoryImpl import `in`.koreatech.koin.data.source.local.OnboardingLocalDataSource import `in`.koreatech.koin.domain.repository.OnboardingRepository +import javax.inject.Singleton @Module -@InstallIn(ActivityComponent::class) +@InstallIn(SingletonComponent::class) abstract class OnboardingRepositoryModule { @Binds - @ActivityScoped + @Singleton abstract fun bindOnboardingRepository( onboardingRepositoryImpl: OnboardingRepositoryImpl ): OnboardingRepository } @Module -@InstallIn(ActivityComponent::class) +@InstallIn(SingletonComponent::class) object OnboardingLocalDataSourceModule { private val Context.onboardingDataStore: DataStore by preferencesDataStore( @@ -35,7 +37,7 @@ object OnboardingLocalDataSourceModule { ) @Provides - @ActivityScoped + @Singleton fun provideOnboardingManager( @ApplicationContext context: Context ): OnboardingLocalDataSource { From d29bbcefc71a377d24d02a2045e44c230936c619 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:33:34 +0900 Subject: [PATCH 116/138] =?UTF-8?q?add:=20=EB=8C=80=EC=84=B1=20=EA=B8=B0?= =?UTF-8?q?=EC=A0=90=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/ExpressTimetableScreen.kt | 33 ++++++++++++++----- feature/bus/src/main/res/values/strings.xml | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt index 6dc530d41..f9aecd4e9 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt @@ -2,15 +2,18 @@ package `in`.koreatech.bus.screen.timetable.composable import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -22,6 +25,7 @@ import `in`.koreatech.bus.viewstate.ArrivalViewState import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R @Composable internal fun ExpressTimetableScreen( @@ -36,16 +40,29 @@ internal fun ExpressTimetableScreen( Column( modifier = modifier ) { - TextChipGroup( + Row( modifier = Modifier .fillMaxWidth() - .padding(vertical = 8.dp, horizontal = 24.dp), - titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, - onChipSelected = { title -> - selectedDirectionTypeIndex = CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 - }, - selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) - ) + .padding(vertical = 12.dp, horizontal = 24.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.starting_point), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.neutral600 + ) + + TextChipGroup( + modifier = Modifier.padding(start = 16.dp), + titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedDirectionTypeIndex = + CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal + ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) + ) + } CommonTimetableView( timetable = timetable, diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 233e11b8c..d58e72c9c 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -21,6 +21,7 @@ 400번 405번 495번 + 기점 From f603d3dfefc7bcb764d1899df52bc596bf037f3f Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 04:39:59 +0900 Subject: [PATCH 117/138] =?UTF-8?q?add:=20=EC=8B=9C=EB=82=B4=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20"=EA=B8=B0=EC=A0=90",=20"=EC=9A=B4=ED=96=89"=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/CityTimetableScreen.kt | 56 ++++++++++++++----- feature/bus/src/main/res/values/strings.xml | 2 + 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt index 41fd8e42a..b0d960eb9 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt @@ -2,15 +2,18 @@ package `in`.koreatech.bus.screen.timetable.composable import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -23,6 +26,7 @@ import `in`.koreatech.bus.viewstate.ArrivalViewState import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R @Composable internal fun CityTimetableScreen( @@ -39,28 +43,52 @@ internal fun CityTimetableScreen( Column( modifier = modifier ) { - TextChipGroup( + Row( modifier = Modifier .fillMaxWidth() .padding(horizontal = 24.dp) .padding(top = 8.dp, bottom = 4.dp), - titles = CityBusNumberType.entries.map { stringResource(it.titleRes) }, - onChipSelected = { title -> - selectedBusNumberTypeIndex = CityBusNumberType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 - }, - selectedChipIndexes = intArrayOf(selectedBusNumberTypeIndex) - ) - TextChipGroup( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.routes), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.neutral600 + ) + TextChipGroup( + modifier = Modifier.padding(start = 16.dp), + titles = CityBusNumberType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedBusNumberTypeIndex = + CityBusNumberType.entries.find { context.getString(it.titleRes) == title }?.ordinal + ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedBusNumberTypeIndex) + ) + } + Row( modifier = Modifier .fillMaxWidth() .padding(horizontal = 24.dp) .padding(top = 4.dp, bottom = 8.dp), - titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, - onChipSelected = { title -> - selectedDirectionTypeIndex = CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 - }, - selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) - ) + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(R.string.operating), + style = KoinTheme.typography.regular16, + color = KoinTheme.colors.neutral600 + ) + TextChipGroup( + modifier = Modifier.padding(start = 16.dp), + titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, + onChipSelected = { title -> + selectedDirectionTypeIndex = + CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal + ?: 0 + }, + selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) + ) + } CommonTimetableView( timetable = timetable, diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index d58e72c9c..aa7e8c769 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -22,6 +22,8 @@ 405번 495번 기점 + 노선 + 운행 From 4f4d9b37a12f5db6ecd18d8c3538c1d3829267a8 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 21:56:13 +0900 Subject: [PATCH 118/138] =?UTF-8?q?refactor:=20layout.xml=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=B0=8F=20setContent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/in/koreatech/bus/Bus2Activity.kt | 4 ++-- feature/bus/src/main/res/layout/activity_bus2.xml | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 feature/bus/src/main/res/layout/activity_bus2.xml diff --git a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt index bc15d77ba..127541ddc 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/Bus2Activity.kt @@ -1,6 +1,7 @@ package `in`.koreatech.bus import android.os.Bundle +import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.layout.fillMaxSize @@ -21,8 +22,7 @@ class Bus2Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() - setContentView(R.layout.activity_bus2) - findViewById(R.id.compose_view_bus).setContent { + setContent { KoinTheme { BusNavigation( modifier = Modifier.fillMaxSize() diff --git a/feature/bus/src/main/res/layout/activity_bus2.xml b/feature/bus/src/main/res/layout/activity_bus2.xml deleted file mode 100644 index 684c98256..000000000 --- a/feature/bus/src/main/res/layout/activity_bus2.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - \ No newline at end of file From 620f49859054aa895e01e583e18156645bf2cdd8 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 11:26:30 +0900 Subject: [PATCH 119/138] =?UTF-8?q?fix:=20TextChip=20=EB=A6=AC=ED=94=8C=20?= =?UTF-8?q?=ED=8C=A8=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/core/designsystem/component/chip/TextChip.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChip.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChip.kt index 47e80d290..639861acb 100644 --- a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChip.kt +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/chip/TextChip.kt @@ -42,15 +42,15 @@ fun TextChip( Box( modifier = modifier .clip(shape) - .background(if(isSelected) chipColors.selectedContainerColor else chipColors.unselectedContainerColor) - .padding(contentPadding) .then( if (showClickRipple) Modifier.clickable { onSelect() } else Modifier.noRippleClickable { onSelect() } - ), + ) + .background(if(isSelected) chipColors.selectedContainerColor else chipColors.unselectedContainerColor) + .padding(contentPadding), contentAlignment = Alignment.Center ) { Text( From 25e5d97706ae26ae05c267c2c01a26983271ead9 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 11:35:50 +0900 Subject: [PATCH 120/138] add: Parcelize --- feature/bus/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/feature/bus/build.gradle.kts b/feature/bus/build.gradle.kts index fd7ad52b5..1ad02fcdf 100644 --- a/feature/bus/build.gradle.kts +++ b/feature/bus/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.koin.hilt) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlinx.serialization) + id("kotlin-parcelize") } android { From 2e5b3bd22fae9033a3557a1b0bedd6e514981137 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 11:45:09 +0900 Subject: [PATCH 121/138] =?UTF-8?q?add:=20Onboarding=20flow=EB=A1=9C?= =?UTF-8?q?=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/koin/core/onboarding/OnboardingManager.kt | 4 ++++ .../koin/data/repository/OnboardingRepositoryImpl.kt | 4 ++++ .../koin/data/source/local/OnboardingLocalDataSource.kt | 6 ++++++ .../koin/domain/repository/OnboardingRepository.kt | 3 +++ 4 files changed, 17 insertions(+) diff --git a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt index 090fb714d..625410e6a 100644 --- a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt +++ b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingManager.kt @@ -99,6 +99,10 @@ class OnboardingManager @Inject internal constructor( } } + fun getShouldOnboardFlow( + type: OnboardingType + ) = onboardingRepository.getShouldOnboardingFlow(type.name) + suspend fun getShouldOnboard( type: OnboardingType, ) : Boolean { diff --git a/data/src/main/java/in/koreatech/koin/data/repository/OnboardingRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/OnboardingRepositoryImpl.kt index 5bfbe2552..3f2314492 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/OnboardingRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/OnboardingRepositoryImpl.kt @@ -2,6 +2,7 @@ package `in`.koreatech.koin.data.repository import `in`.koreatech.koin.data.source.local.OnboardingLocalDataSource import `in`.koreatech.koin.domain.repository.OnboardingRepository +import kotlinx.coroutines.flow.Flow import javax.inject.Inject class OnboardingRepositoryImpl @Inject constructor( @@ -15,4 +16,7 @@ class OnboardingRepositoryImpl @Inject constructor( override suspend fun updateShouldOnboarding(onboardingType: String, shouldShow: Boolean) { onboardingLocalDataSource.updateShouldOnboarding(onboardingType, shouldShow) } + + override fun getShouldOnboardingFlow(onboardingType: String): Flow = + onboardingLocalDataSource.getShouldOnboardingFlow(onboardingType) } \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/source/local/OnboardingLocalDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/local/OnboardingLocalDataSource.kt index 647db6a93..3729b43dc 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/local/OnboardingLocalDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/local/OnboardingLocalDataSource.kt @@ -27,4 +27,10 @@ class OnboardingLocalDataSource @Inject constructor( preferences[booleanPreferencesKey(onboardingType)] = shouldShow } } + + fun getShouldOnboardingFlow(onboardingType: String) = dataStore.data.catch { + emit(emptyPreferences()) + }.map { preferences -> + preferences[booleanPreferencesKey(onboardingType)] ?: true + } } \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/OnboardingRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/OnboardingRepository.kt index 689070842..b3629f836 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/OnboardingRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/OnboardingRepository.kt @@ -1,6 +1,9 @@ package `in`.koreatech.koin.domain.repository +import kotlinx.coroutines.flow.Flow + interface OnboardingRepository { suspend fun getShouldOnboarding(onboardingType: String): Boolean suspend fun updateShouldOnboarding(onboardingType: String, shouldShow: Boolean) + fun getShouldOnboardingFlow(onboardingType: String): Flow } \ No newline at end of file From b53d2069266ee5716dc5e3474c88d7ec02710118 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 11:45:38 +0900 Subject: [PATCH 122/138] =?UTF-8?q?refactor:=20tab=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=83=80=EC=9D=B4=ED=8B=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composable/BusTimetableScreen.kt | 25 +++++++++++-------- .../bus/screen/timetable/type/BusType.kt | 5 +++- .../viewmodel/BusTimetableViewModel.kt | 6 ++--- feature/bus/src/main/res/values/strings.xml | 4 ++- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt index 4481f5ffe..d831dfee9 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/BusTimetableScreen.kt @@ -19,7 +19,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -51,7 +51,12 @@ internal fun BusTimetableScreen( previewTab: BusType = BusType.SHUTTLE ) { - var selectedTimetableTypeTabIndex by rememberSaveable { mutableIntStateOf(0) } + var selectedTimetableTypeTab by rememberSaveable { mutableStateOf(BusType.SHUTTLE) } + val busTypeHeadTitle = when(selectedTimetableTypeTab) { + BusType.SHUTTLE -> stringResource(R.string.shuttle_timetable) + BusType.EXPRESS -> stringResource(R.string.express_timetable) + BusType.CITY -> stringResource(R.string.city_timetable) + } val shuttleRegions by viewModel.shuttleRegions.collectAsStateWithLifecycle() val expressTimetable by viewModel.expressTimetable.collectAsStateWithLifecycle() @@ -74,7 +79,7 @@ internal fun BusTimetableScreen( modifier = Modifier.fillMaxWidth().background(Color.White).padding(horizontal = 24.dp) ) { Text( - text = stringResource(R.string.shuttle_timetable), + text = busTypeHeadTitle, style = KoinTheme.typography.bold20 ) Spacer(modifier = Modifier.height(8.dp)) @@ -117,29 +122,29 @@ internal fun BusTimetableScreen( stickyHeader { KoinTabRow( titles = BusType.entries.map { stringResource(it.titleRes) }, - selectedTabIndex = selectedTimetableTypeTabIndex, - onTabSelected = { selectedTimetableTypeTabIndex = it } + selectedTabIndex = selectedTimetableTypeTab.ordinal, + onTabSelected = { selectedTimetableTypeTab = BusType.entries[it] } ) } item { if (LocalInspectionMode.current) - selectedTimetableTypeTabIndex = previewTab.ordinal + selectedTimetableTypeTab = previewTab - when(selectedTimetableTypeTabIndex) { - BusType.SHUTTLE.ordinal -> { + when(selectedTimetableTypeTab) { + BusType.SHUTTLE -> { ShuttleTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), regions = shuttleRegions.toPersistentList() ) } - BusType.EXPRESS.ordinal -> { + BusType.EXPRESS -> { ExpressTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), timetable = expressTimetable ) } - BusType.CITY.ordinal -> { + BusType.CITY -> { CityTimetableScreen( modifier = Modifier.fillMaxSize().background(KoinTheme.colors.neutral100), timetable = cityTimetable diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt index 3f7cdc463..4b0758096 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/BusType.kt @@ -1,11 +1,14 @@ package `in`.koreatech.bus.screen.timetable.type +import android.os.Parcelable import androidx.annotation.StringRes import `in`.koreatech.koin.feature.bus.R +import kotlinx.parcelize.Parcelize +@Parcelize internal enum class BusType( @StringRes val titleRes: Int -) { +) : Parcelable { SHUTTLE(R.string.tab_shuttle), EXPRESS(R.string.tab_express), CITY(R.string.tab_city), diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt index 33bccd885..bc7d890ad 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusTimetableViewModel.kt @@ -255,9 +255,9 @@ class BusTimetableViewModel @Inject constructor( initialValue = "[긴급] 9.27(금) 대학등교방향 천안셔틀버스 터미널 미정차 알림(천안역에서 승차바람)" ) - val shouldShowNotice = flow { - emit(onboardingManager.getShouldOnboard(OnboardingType.SHOW_BUS_HEAD_ARTICLE)) - }.stateIn( + val shouldShowNotice = onboardingManager.getShouldOnboardFlow( + OnboardingType.SHOW_BUS_HEAD_ARTICLE + ).stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = false diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index aa7e8c769..fb5011bd3 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -1,7 +1,9 @@ 버스 시간표 - 교내 셔틀 시간표 + 셔틀버스 시간표 + 대성버스 시간표 + 시내버스 시간표 정보가 정확하지 않나요? 셔틀 대성 From 7f85df878a59c25f46af6e4cc6ffcac28048db80 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 11:55:46 +0900 Subject: [PATCH 123/138] refactor: enum: Parcelable --- .../composable/CityTimetableScreen.kt | 28 +++++++++---------- .../composable/ExpressTimetableScreen.kt | 17 ++++++----- .../composable/ShuttleTimetableScreen.kt | 8 +++--- .../timetable/type/CityBusNumberType.kt | 5 +++- .../timetable/type/CommonDirectionType.kt | 5 +++- .../timetable/type/ShuttleBusRouteType.kt | 5 +++- 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt index b0d960eb9..eb076468e 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CityTimetableScreen.kt @@ -10,7 +10,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -36,8 +36,8 @@ internal fun CityTimetableScreen( onDirectionChanged: (CommonDirectionType) -> Unit = {} ) { - var selectedBusNumberTypeIndex by rememberSaveable { mutableIntStateOf(CityBusNumberType.N400.ordinal) } - var selectedDirectionTypeIndex by rememberSaveable { mutableIntStateOf(CommonDirectionType.TO_BYEONGCHEON.ordinal) } + var selectedBusNumberType by rememberSaveable { mutableStateOf(CityBusNumberType.N400) } + var selectedDirectionType by rememberSaveable { mutableStateOf(CommonDirectionType.TO_BYEONGCHEON) } val context = LocalContext.current Column( @@ -59,11 +59,10 @@ internal fun CityTimetableScreen( modifier = Modifier.padding(start = 16.dp), titles = CityBusNumberType.entries.map { stringResource(it.titleRes) }, onChipSelected = { title -> - selectedBusNumberTypeIndex = - CityBusNumberType.entries.find { context.getString(it.titleRes) == title }?.ordinal - ?: 0 + selectedBusNumberType = + CityBusNumberType.entries.find { context.getString(it.titleRes) == title } ?: CityBusNumberType.N400 }, - selectedChipIndexes = intArrayOf(selectedBusNumberTypeIndex) + selectedChipIndexes = intArrayOf(selectedBusNumberType.ordinal) ) } Row( @@ -82,11 +81,10 @@ internal fun CityTimetableScreen( modifier = Modifier.padding(start = 16.dp), titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, onChipSelected = { title -> - selectedDirectionTypeIndex = - CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal - ?: 0 + selectedDirectionType = + CommonDirectionType.entries.find { context.getString(it.titleRes) == title } ?: CommonDirectionType.TO_BYEONGCHEON }, - selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) + selectedChipIndexes = intArrayOf(selectedDirectionType.ordinal) ) } @@ -96,12 +94,12 @@ internal fun CityTimetableScreen( ) } - LaunchedEffect(selectedBusNumberTypeIndex) { - onBusNumberChanged(CityBusNumberType.entries[selectedBusNumberTypeIndex]) + LaunchedEffect(selectedBusNumberType) { + onBusNumberChanged(selectedBusNumberType) } - LaunchedEffect(selectedDirectionTypeIndex) { - onDirectionChanged(CommonDirectionType.entries[selectedDirectionTypeIndex]) + LaunchedEffect(selectedDirectionType) { + onDirectionChanged(selectedDirectionType) } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt index f9aecd4e9..e975e919e 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ExpressTimetableScreen.kt @@ -10,7 +10,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -19,8 +19,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import `in`.koreatech.bus.screen.timetable.type.DaytimeType import `in`.koreatech.bus.screen.timetable.type.CommonDirectionType +import `in`.koreatech.bus.screen.timetable.type.DaytimeType import `in`.koreatech.bus.viewstate.ArrivalViewState import `in`.koreatech.bus.viewstate.CommonTimetableViewState import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup @@ -34,7 +34,7 @@ internal fun ExpressTimetableScreen( onDirectionChanged: (CommonDirectionType) -> Unit = {} ) { - var selectedDirectionTypeIndex by rememberSaveable { mutableIntStateOf(CommonDirectionType.TO_BYEONGCHEON.ordinal) } + var selectedDirectionType by rememberSaveable { mutableStateOf(CommonDirectionType.TO_BYEONGCHEON) } val context = LocalContext.current Column( @@ -56,11 +56,10 @@ internal fun ExpressTimetableScreen( modifier = Modifier.padding(start = 16.dp), titles = CommonDirectionType.entries.map { stringResource(it.titleRes) }, onChipSelected = { title -> - selectedDirectionTypeIndex = - CommonDirectionType.entries.find { context.getString(it.titleRes) == title }?.ordinal - ?: 0 + selectedDirectionType = + CommonDirectionType.entries.find { context.getString(it.titleRes) == title } ?: CommonDirectionType.TO_BYEONGCHEON }, - selectedChipIndexes = intArrayOf(selectedDirectionTypeIndex) + selectedChipIndexes = intArrayOf(selectedDirectionType.ordinal) ) } @@ -70,8 +69,8 @@ internal fun ExpressTimetableScreen( ) } - LaunchedEffect(selectedDirectionTypeIndex) { - onDirectionChanged(CommonDirectionType.entries[selectedDirectionTypeIndex]) + LaunchedEffect(selectedDirectionType) { + onDirectionChanged(selectedDirectionType) } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt index b084e5e70..5367258eb 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/ShuttleTimetableScreen.kt @@ -14,7 +14,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -40,7 +40,7 @@ internal fun ShuttleTimetableScreen( regions: ImmutableList ) { - var selectedRouteTypeIndex by rememberSaveable { mutableIntStateOf(ShuttleBusRouteType.ALL.ordinal) } + var selectedRouteType by rememberSaveable { mutableStateOf(ShuttleBusRouteType.ALL) } val context = LocalContext.current Column( @@ -50,9 +50,9 @@ internal fun ShuttleTimetableScreen( modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp, horizontal = 24.dp), titles = ShuttleBusRouteType.entries.map { stringResource(it.titleRes) }, onChipSelected = { title -> - selectedRouteTypeIndex = ShuttleBusRouteType.entries.find { context.getString(it.titleRes) == title }?.ordinal ?: 0 + selectedRouteType = ShuttleBusRouteType.entries.find { context.getString(it.titleRes) == title } ?: ShuttleBusRouteType.ALL }, - selectedChipIndexes = intArrayOf(selectedRouteTypeIndex) + selectedChipIndexes = intArrayOf(selectedRouteType.ordinal) ) regions.forEach { ShuttleRegionView( diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt index 1e21d62ad..5fa54bd36 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CityBusNumberType.kt @@ -1,10 +1,13 @@ package `in`.koreatech.bus.screen.timetable.type +import android.os.Parcelable import androidx.annotation.StringRes import `in`.koreatech.koin.feature.bus.R +import kotlinx.parcelize.Parcelize +@Parcelize enum class CityBusNumberType( @StringRes val titleRes: Int -) { +) : Parcelable { N400(R.string.n400), N405(R.string.n405), N495(R.string.n495) } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt index 108382464..6997f09c3 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/CommonDirectionType.kt @@ -1,11 +1,14 @@ package `in`.koreatech.bus.screen.timetable.type +import android.os.Parcelable import androidx.annotation.StringRes import `in`.koreatech.koin.feature.bus.R +import kotlinx.parcelize.Parcelize +@Parcelize enum class CommonDirectionType( @StringRes val titleRes: Int -) { +) : Parcelable { TO_BYEONGCHEON(R.string.to_byeongcheon), TO_CHEONAN(R.string.to_cheonan), } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt index b84afe6d4..3bd51024b 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/type/ShuttleBusRouteType.kt @@ -1,12 +1,15 @@ package `in`.koreatech.bus.screen.timetable.type +import android.os.Parcelable import androidx.annotation.StringRes import `in`.koreatech.koin.feature.bus.R +import kotlinx.parcelize.Parcelize +@Parcelize enum class ShuttleBusRouteType( @StringRes val titleRes: Int, @StringRes val simpleTitleRes: Int -) { +) : Parcelable { ALL(R.string.all_routes, 0), WEEKDAY(R.string.weekday_routes, R.string.weekday_routes_simple), WEEKEND(R.string.weekend_routes, R.string.weekend_routes_simple), From 71be2db437db1e1d398ba6d5ba8a9de03e8486db Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 22:45:32 +0900 Subject: [PATCH 124/138] add: BusSearchScreen --- .../koreatech/bus/navigation/BusNavigation.kt | 10 +- .../in/koreatech/bus/navigation/Routes.kt | 1 + .../search/composebal/BusSearchScreen.kt | 144 ++++++++++++++++++ .../search/viewmodel/BusSearchViewModel.kt | 35 +++++ feature/bus/src/main/res/drawable/ic_swap.xml | 21 +++ feature/bus/src/main/res/values/strings.xml | 9 ++ 6 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt create mode 100644 feature/bus/src/main/res/drawable/ic_swap.xml diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt index 00341c717..c74fb57b0 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt @@ -9,7 +9,8 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import `in`.koreatech.bus.screen.timetable.viewmodel.BusViewModel +import `in`.koreatech.bus.screen.search.composebal.BusSearchScreen +import `in`.koreatech.bus.screen.timetable.composable.BusTimetableScreen @Composable fun BusNavigation( @@ -32,5 +33,12 @@ fun BusNavigation( composable { } + + composable { + BusSearchScreen( + modifier = Modifier.fillMaxSize(), + onNavigationIconClick = { navController.popBackStack() } + ) + } } } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt index 9b4fc63f5..f53194a1b 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/Routes.kt @@ -5,4 +5,5 @@ import kotlinx.serialization.Serializable internal object Routes { @Serializable data object BusTimetable + @Serializable data object BusSearch } \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt new file mode 100644 index 000000000..aada8e6a7 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -0,0 +1,144 @@ +package `in`.koreatech.bus.screen.search.composebal + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import `in`.koreatech.bus.screen.search.viewmodel.BusSearchViewModel +import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BusSearchScreen( + modifier: Modifier = Modifier, + onNavigationIconClick: () -> Unit = {}, + viewModel: BusSearchViewModel = hiltViewModel() +) { + + val departure by viewModel.departure.collectAsStateWithLifecycle() + val arrival by viewModel.arrival.collectAsStateWithLifecycle() + + Column( + modifier = modifier + ) { + KoinTopAppBar( + title = stringResource(R.string.title_bus_search), + onNavigationIconClick = onNavigationIconClick + ) + + Text( + modifier = Modifier.padding(top = 16.dp), + text = stringResource(R.string.introduce_bus_search), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.neutral800 + ) + + Text( + modifier = Modifier.padding(top = 2.dp), + text = stringResource(R.string.caution_possibly_inaccurate), + style = KoinTheme.typography.regular12, + color = KoinTheme.colors.neutral600 + ) + + Row( + modifier = Modifier.fillMaxWidth().padding(top = 46.dp), + verticalAlignment = Alignment.Bottom + ) { + BusSearchInput( + title = stringResource(R.string.departure), + place = departure, + placeholder = stringResource(R.string.select_departure), + modifier = Modifier.weight(1f) + ) + + IconButton( + onClick = viewModel::swapDepartureAndArrival, + modifier = Modifier.padding(horizontal = 16.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.ic_swap), + contentDescription = stringResource(R.string.swap_content_description) + ) + } + + BusSearchInput( + title = stringResource(R.string.arrival), + place = arrival, + placeholder = stringResource(R.string.select_arrival), + modifier = Modifier.weight(1f) + ) + } + } +} + +@Composable +private fun BusSearchInput( + title: String, + place: String, + placeholder: String, + modifier: Modifier = Modifier, +) { + + val isPlaceDetermined by remember { derivedStateOf { place.isNotEmpty() } } + + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = title, + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.primary500 + ) + + Box( + modifier = Modifier + .background(if(isPlaceDetermined.not()) KoinTheme.colors.neutral100 else Color.Transparent) + .padding(vertical = 12.dp, horizontal = 39.dp), + contentAlignment = Alignment.Center + ) { + if (isPlaceDetermined.not()) + Text( + text = placeholder, + style = KoinTheme.typography.regular14, + color = KoinTheme.colors.neutral400 // TODO neutral450 ? + ) + else { + Text( + text = place, + style = KoinTheme.typography.bold18, + color = KoinTheme.colors.neutral800 + ) + } + } + } +} + +@Preview +@Composable +private fun BusSearchScreenPreview() { + BusSearchScreen( + modifier = Modifier.fillMaxWidth() + ) +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt new file mode 100644 index 000000000..6f3830a08 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt @@ -0,0 +1,35 @@ +package `in`.koreatech.bus.screen.search.viewmodel + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class BusSearchViewModel @Inject constructor( + private val savedStateHandle: SavedStateHandle +) : ViewModel() { + + val departure = savedStateHandle.getStateFlow(KEY_DEPARTURE, "") + val arrival = savedStateHandle.getStateFlow(KEY_ARRIVAL, "") + + fun setDeparture(departure: String) { + savedStateHandle[KEY_DEPARTURE] = departure + } + + fun setArrival(arrival: String) { + savedStateHandle[KEY_ARRIVAL] = arrival + } + + fun swapDepartureAndArrival() { + val currentDeparture = departure.value + val currentArrival = arrival.value + setDeparture(currentArrival) + setArrival(currentDeparture) + } + + companion object { + private const val KEY_DEPARTURE = "departure" + private const val KEY_ARRIVAL = "arrival" + } +} \ No newline at end of file diff --git a/feature/bus/src/main/res/drawable/ic_swap.xml b/feature/bus/src/main/res/drawable/ic_swap.xml new file mode 100644 index 000000000..d6d2d6a78 --- /dev/null +++ b/feature/bus/src/main/res/drawable/ic_swap.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index caaed9e72..00f578d59 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -14,6 +14,15 @@ 주말 순환 + + 교통편 조회하기 + 목적지까지 가장 빠른 교통편을 알려드릴게요. + 학기 중 시간표와 다를 수 있습니다. + 출발 + 도착 + 출발지 선택 + 도착지 선택 + 출발지와 도착지를 바꾸기 \ No newline at end of file From 421dab5b260a015cab8906e34f448e5bcd84d4cb Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 23:54:38 +0900 Subject: [PATCH 125/138] add: Compose ContraintLayout dependency --- feature/bus/build.gradle.kts | 2 ++ gradle/libs.versions.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/feature/bus/build.gradle.kts b/feature/bus/build.gradle.kts index bac9fe443..6e6b3a869 100644 --- a/feature/bus/build.gradle.kts +++ b/feature/bus/build.gradle.kts @@ -35,4 +35,6 @@ dependencies { implementation("androidx.navigation:navigation-compose:2.8.3") implementation(libs.kotlinx.serialization.json) + + implementation(libs.androidx.constraintlayout.compose) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f94ec6283..f41e5ec9e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,6 +2,7 @@ activityComposeVersion = "1.8.2" activityKtxVersion = "1.5.0" cardviewVersion = "1.0.0" +constraintlayoutComposeVersion = "1.1.0" inAppUpdateVersion = "2.1.0" featureDeliveryKtxVersion = "2.1.0" firebaseBomVersion = "32.5.0" @@ -76,6 +77,7 @@ kotlinxCollectionsImmutableVersion = "0.3.8" androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtxVersion" } androidx-cardview = { module = "androidx.cardview:cardview", version.ref = "cardviewVersion" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayoutVersion" } +androidx-constraintlayout-compose = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayoutComposeVersion" } androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtxVersion" } androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtxVersion" } androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtxVersion" } From fed5808a61cde3727557b47885c52446e8379d8c Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 23:55:01 +0900 Subject: [PATCH 126/138] =?UTF-8?q?add:=20ConstraintLayout=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20=EB=B2=84=EC=8A=A4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/composebal/BusSearchScreen.kt | 182 +++++++++++++----- 1 file changed, 136 insertions(+), 46 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index aada8e6a7..85f1c8d56 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -3,9 +3,13 @@ package `in`.koreatech.bus.screen.search.composebal import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -16,14 +20,18 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.bus.screen.search.viewmodel.BusSearchViewModel +import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R @@ -47,54 +55,123 @@ fun BusSearchScreen( onNavigationIconClick = onNavigationIconClick ) - Text( - modifier = Modifier.padding(top = 16.dp), - text = stringResource(R.string.introduce_bus_search), - style = KoinTheme.typography.medium16, - color = KoinTheme.colors.neutral800 + BusSearchContentView( + modifier = Modifier + .fillMaxSize() + .padding(top = 16.dp) + .padding(horizontal = 24.dp), + departure = departure, + arrival = arrival, + onSwapIconClicked = viewModel::swapDepartureAndArrival ) + } +} - Text( - modifier = Modifier.padding(top = 2.dp), - text = stringResource(R.string.caution_possibly_inaccurate), - style = KoinTheme.typography.regular12, - color = KoinTheme.colors.neutral600 - ) +@Composable +private fun BusSearchContentView( + departure: String, + arrival: String, + modifier: Modifier = Modifier, + onSwapIconClicked: () -> Unit = {}, +) { - Row( - modifier = Modifier.fillMaxWidth().padding(top = 46.dp), - verticalAlignment = Alignment.Bottom - ) { - BusSearchInput( - title = stringResource(R.string.departure), - place = departure, - placeholder = stringResource(R.string.select_departure), - modifier = Modifier.weight(1f) + KoinSurface { + Column(modifier = modifier) { + Text( + modifier = Modifier, + text = stringResource(R.string.introduce_bus_search), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.neutral800 + ) + + Text( + modifier = Modifier.padding(top = 2.dp), + text = stringResource(R.string.caution_possibly_inaccurate), + style = KoinTheme.typography.regular12, + color = KoinTheme.colors.neutral600 ) - IconButton( - onClick = viewModel::swapDepartureAndArrival, - modifier = Modifier.padding(horizontal = 16.dp) + ConstraintLayout( + modifier = Modifier + .fillMaxWidth() + .padding(top = 46.dp) + .height(IntrinsicSize.Min) ) { - Icon( - painter = painterResource(id = R.drawable.ic_swap), - contentDescription = stringResource(R.string.swap_content_description) + val (departureText, arrivalText, departureField, arrivalField, iconSwap) = createRefs() + + Text( + modifier = Modifier.constrainAs(departureText) { + start.linkTo(departureField.start) + top.linkTo(parent.top) + end.linkTo(departureField.end) + }, + text = stringResource(R.string.departure), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.primary500 + ) + Text( + modifier = Modifier.constrainAs(arrivalText) { + top.linkTo(parent.top) + start.linkTo(arrivalField.start) + end.linkTo(arrivalField.end) + }, + text = stringResource(R.string.arrival), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.primary500 ) - } - BusSearchInput( - title = stringResource(R.string.arrival), - place = arrival, - placeholder = stringResource(R.string.select_arrival), - modifier = Modifier.weight(1f) - ) + BusSearchInput( + place = departure, + placeholder = stringResource(R.string.select_departure), + modifier = Modifier.padding(top = 10.dp).constrainAs(departureField) { + top.linkTo(iconSwap.top) + bottom.linkTo(iconSwap.bottom) + start.linkTo(parent.start) + end.linkTo(iconSwap.start) + + width = Dimension.fillToConstraints + height = Dimension.preferredWrapContent + } + ) + + IconButton( + onClick = onSwapIconClicked, + modifier = Modifier + .padding(top = 10.dp) + .padding(horizontal = 16.dp, vertical = 12.dp) + .size(32.dp) + .constrainAs(iconSwap) { + top.linkTo(departureText.bottom) + start.linkTo(departureField.end) + end.linkTo(arrivalField.start) + } + ) { + Icon( + painter = painterResource(id = R.drawable.ic_swap), + contentDescription = stringResource(R.string.swap_content_description), + ) + } + + BusSearchInput( + place = arrival, + placeholder = stringResource(R.string.select_arrival), + modifier = Modifier.padding(top = 10.dp).constrainAs(arrivalField) { + top.linkTo(iconSwap.top) + bottom.linkTo(iconSwap.bottom) + start.linkTo(iconSwap.end) + end.linkTo(parent.end) + + width = Dimension.fillToConstraints + height = Dimension.preferredWrapContent + } + ) + } } } } @Composable private fun BusSearchInput( - title: String, place: String, placeholder: String, modifier: Modifier = Modifier, @@ -106,27 +183,24 @@ private fun BusSearchInput( modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally ) { - Text( - text = title, - style = KoinTheme.typography.medium16, - color = KoinTheme.colors.primary500 - ) - Box( modifier = Modifier - .background(if(isPlaceDetermined.not()) KoinTheme.colors.neutral100 else Color.Transparent) - .padding(vertical = 12.dp, horizontal = 39.dp), + .clip(RoundedCornerShape(4.dp)) + .background(if (isPlaceDetermined.not()) KoinTheme.colors.neutral100 else Color.Transparent) + .fillMaxSize(), contentAlignment = Alignment.Center ) { if (isPlaceDetermined.not()) Text( text = placeholder, + maxLines = 1, style = KoinTheme.typography.regular14, color = KoinTheme.colors.neutral400 // TODO neutral450 ? ) else { Text( text = place, + maxLines = 1, style = KoinTheme.typography.bold18, color = KoinTheme.colors.neutral800 ) @@ -135,10 +209,26 @@ private fun BusSearchInput( } } -@Preview +@OptIn(ExperimentalMaterial3Api::class) +@Preview(showBackground = true) @Composable private fun BusSearchScreenPreview() { - BusSearchScreen( + Column( modifier = Modifier.fillMaxWidth() - ) + ) { + KoinTopAppBar( + title = stringResource(R.string.title_bus_search), + onNavigationIconClick = { } + ) + + BusSearchContentView( + departure = "", + arrival = "도착지", + modifier = Modifier + .fillMaxSize() + .padding(top = 16.dp) + .padding(horizontal = 24.dp), + onSwapIconClicked = { } + ) + } } \ No newline at end of file From 6b57e4509c4ff9746de0d3d9ea118f589abe725c Mon Sep 17 00:00:00 2001 From: Thirfir Date: Wed, 6 Nov 2024 23:58:06 +0900 Subject: [PATCH 127/138] =?UTF-8?q?add:=20=ED=94=84=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/composebal/BusSearchScreen.kt | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index 85f1c8d56..cf44ece6c 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -223,7 +223,54 @@ private fun BusSearchScreenPreview() { BusSearchContentView( departure = "", - arrival = "도착지", + arrival = "", + modifier = Modifier + .fillMaxSize() + .padding(top = 16.dp) + .padding(horizontal = 24.dp), + onSwapIconClicked = { } + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview(showBackground = true) +@Composable +private fun BusSearchScreen2Preview() { + Column( + modifier = Modifier.fillMaxWidth() + ) { + KoinTopAppBar( + title = stringResource(R.string.title_bus_search), + onNavigationIconClick = { } + ) + + BusSearchContentView( + departure = "코리아텍", + arrival = "", + modifier = Modifier + .fillMaxSize() + .padding(top = 16.dp) + .padding(horizontal = 24.dp), + onSwapIconClicked = { } + ) + } +} +@OptIn(ExperimentalMaterial3Api::class) +@Preview(showBackground = true) +@Composable +private fun BusSearchScreen3Preview() { + Column( + modifier = Modifier.fillMaxWidth() + ) { + KoinTopAppBar( + title = stringResource(R.string.title_bus_search), + onNavigationIconClick = { } + ) + + BusSearchContentView( + departure = "코리아텍", + arrival = "천안역", modifier = Modifier .fillMaxSize() .padding(top = 16.dp) From bbcb5426e4c36cec3251fcffe990dba9066e35ae Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 00:05:36 +0900 Subject: [PATCH 128/138] =?UTF-8?q?add:=20=EC=A1=B0=ED=9A=8C=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screen/search/composebal/BusSearchScreen.kt | 14 ++++++++++++++ feature/bus/src/main/res/values/strings.xml | 1 + 2 files changed, 15 insertions(+) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index cf44ece6c..5e784a56e 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -4,12 +4,15 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -31,6 +34,7 @@ import androidx.constraintlayout.compose.Dimension import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.bus.screen.search.viewmodel.BusSearchViewModel +import `in`.koreatech.koin.core.designsystem.component.button.FilledButton import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar import `in`.koreatech.koin.core.designsystem.theme.KoinTheme @@ -166,6 +170,16 @@ private fun BusSearchContentView( } ) } + + Spacer(modifier = Modifier.weight(1f)) + FilledButton( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 30.dp), + text = stringResource(R.string.search), + contentPadding = PaddingValues(vertical = 12.dp), + onClick = { } + ) } } } diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 00f578d59..9aa0fb169 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -23,6 +23,7 @@ 출발지 선택 도착지 선택 출발지와 도착지를 바꾸기 + 조회하기 \ No newline at end of file From 0b98fcdfbfef1256554cd23f99c50d678e720bb9 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 00:09:19 +0900 Subject: [PATCH 129/138] =?UTF-8?q?add:=20=EB=B2=84=ED=8A=BC=20onClick=20?= =?UTF-8?q?=EC=9E=84=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/screen/search/composebal/BusSearchScreen.kt | 7 ++++--- .../bus/screen/search/viewmodel/BusSearchViewModel.kt | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index 5e784a56e..e4a920a10 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -66,7 +65,8 @@ fun BusSearchScreen( .padding(horizontal = 24.dp), departure = departure, arrival = arrival, - onSwapIconClicked = viewModel::swapDepartureAndArrival + onSwapIconClicked = viewModel::swapDepartureAndArrival, + onSearchClicked = viewModel::search ) } } @@ -77,6 +77,7 @@ private fun BusSearchContentView( arrival: String, modifier: Modifier = Modifier, onSwapIconClicked: () -> Unit = {}, + onSearchClicked: () -> Unit = {} ) { KoinSurface { @@ -178,7 +179,7 @@ private fun BusSearchContentView( .padding(bottom = 30.dp), text = stringResource(R.string.search), contentPadding = PaddingValues(vertical = 12.dp), - onClick = { } + onClick = onSearchClicked ) } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt index 6f3830a08..2d18fc8d1 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt @@ -28,6 +28,10 @@ class BusSearchViewModel @Inject constructor( setArrival(currentDeparture) } + fun search() { + // TODO Search bus + } + companion object { private const val KEY_DEPARTURE = "departure" private const val KEY_ARRIVAL = "arrival" From d97bcb21147711050bcf3d87957d9ae0ee4e579e Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 00:32:55 +0900 Subject: [PATCH 130/138] =?UTF-8?q?add:=20=EC=9E=84=EC=8B=9C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/domain/error/busv2/ErrorType.kt | 6 ++++ .../usecase/busv2/SearchBusV2UseCase.kt | 21 +++++++++++++ .../koreatech/bus/navigation/BusNavigation.kt | 5 +++- .../search/composebal/BusSearchScreen.kt | 14 +++++++++ .../search/viewmodel/BusSearchViewModel.kt | 30 +++++++++++++++++-- 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 domain/src/main/java/in/koreatech/koin/domain/error/busv2/ErrorType.kt create mode 100644 domain/src/main/java/in/koreatech/koin/domain/usecase/busv2/SearchBusV2UseCase.kt diff --git a/domain/src/main/java/in/koreatech/koin/domain/error/busv2/ErrorType.kt b/domain/src/main/java/in/koreatech/koin/domain/error/busv2/ErrorType.kt new file mode 100644 index 000000000..6d260a619 --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/error/busv2/ErrorType.kt @@ -0,0 +1,6 @@ +package `in`.koreatech.koin.domain.error.busv2 + +sealed class SearchBusError: Throwable() { + class EmptyDeparture: SearchBusError() + class EmptyArrival: SearchBusError() +} \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/busv2/SearchBusV2UseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/busv2/SearchBusV2UseCase.kt new file mode 100644 index 000000000..af90e655e --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/busv2/SearchBusV2UseCase.kt @@ -0,0 +1,21 @@ +package `in`.koreatech.koin.domain.usecase.busv2 + +import `in`.koreatech.koin.domain.error.busv2.SearchBusError +import javax.inject.Inject + +class SearchBusV2UseCase @Inject constructor( + // private val busRepository +) { + + suspend operator fun invoke(departure: String, arrival: String): Result { + return when { + departure.isEmpty() -> Result.failure(SearchBusError.EmptyDeparture()) + arrival.isEmpty() -> Result.failure(SearchBusError.EmptyArrival()) + else -> { + // TODO repository Search bus + // busRepository.searchBus(departure, arrival) + Result.success(Unit) + } + } + } +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt index c74fb57b0..d6115b519 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt @@ -37,7 +37,10 @@ fun BusNavigation( composable { BusSearchScreen( modifier = Modifier.fillMaxSize(), - onNavigationIconClick = { navController.popBackStack() } + onNavigationIconClick = { navController.popBackStack() }, + onSearchSuccess = { + // navController.navigate(Routes.SearchedTimetable(it)) + } ) } } diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index e4a920a10..1bd99a7f0 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -33,6 +34,7 @@ import androidx.constraintlayout.compose.Dimension import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.bus.screen.search.viewmodel.BusSearchViewModel +import `in`.koreatech.bus.screen.search.viewmodel.SearchBusUiState import `in`.koreatech.koin.core.designsystem.component.button.FilledButton import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar @@ -44,6 +46,7 @@ import `in`.koreatech.koin.feature.bus.R fun BusSearchScreen( modifier: Modifier = Modifier, onNavigationIconClick: () -> Unit = {}, + onSearchSuccess: (Unit) -> Unit = {}, viewModel: BusSearchViewModel = hiltViewModel() ) { @@ -69,6 +72,17 @@ fun BusSearchScreen( onSearchClicked = viewModel::search ) } + + LaunchedEffect(Unit) { + viewModel.searchBusUiState.collect { + when(it) { + is SearchBusUiState.Loading -> Unit + is SearchBusUiState.EmptyDeparture -> Unit + is SearchBusUiState.EmptyArrival -> Unit + is SearchBusUiState.Success -> onSearchSuccess(it.data) // TODO : data 타입 + } + } + } } @Composable diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt index 2d18fc8d1..bd25ffb26 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/viewmodel/BusSearchViewModel.kt @@ -2,17 +2,27 @@ package `in`.koreatech.bus.screen.search.viewmodel import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.koin.domain.error.busv2.SearchBusError +import `in`.koreatech.koin.domain.usecase.busv2.SearchBusV2UseCase +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class BusSearchViewModel @Inject constructor( - private val savedStateHandle: SavedStateHandle + private val savedStateHandle: SavedStateHandle, + private val searchBusV2UseCase: SearchBusV2UseCase ) : ViewModel() { val departure = savedStateHandle.getStateFlow(KEY_DEPARTURE, "") val arrival = savedStateHandle.getStateFlow(KEY_ARRIVAL, "") + private val _searchBusUiState = MutableSharedFlow() + val searchBusUiState = _searchBusUiState.asSharedFlow() + fun setDeparture(departure: String) { savedStateHandle[KEY_DEPARTURE] = departure } @@ -29,11 +39,27 @@ class BusSearchViewModel @Inject constructor( } fun search() { - // TODO Search bus + viewModelScope.launch { + searchBusV2UseCase(departure.value, arrival.value).onSuccess { + _searchBusUiState.emit(SearchBusUiState.Success(Unit)) // TODO: 리턴 타입 + }.onFailure { + when (it) { + is SearchBusError.EmptyDeparture -> _searchBusUiState.emit(SearchBusUiState.EmptyDeparture) + is SearchBusError.EmptyArrival -> _searchBusUiState.emit(SearchBusUiState.EmptyArrival) + } + } + } } companion object { private const val KEY_DEPARTURE = "departure" private const val KEY_ARRIVAL = "arrival" } +} + +sealed interface SearchBusUiState { + data object Loading : SearchBusUiState + data class Success(val data: Unit) : SearchBusUiState // TODO: 리턴 타입 + data object EmptyDeparture : SearchBusUiState + data object EmptyArrival : SearchBusUiState } \ No newline at end of file From 74f101ec5824fe540141231bd7415f486aa195f5 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 00:35:15 +0900 Subject: [PATCH 131/138] =?UTF-8?q?add:=20Button=20enabled=20=EC=83=81?= =?UTF-8?q?=ED=83=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/screen/search/composebal/BusSearchScreen.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index 1bd99a7f0..8eb724fb3 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -52,6 +52,8 @@ fun BusSearchScreen( val departure by viewModel.departure.collectAsStateWithLifecycle() val arrival by viewModel.arrival.collectAsStateWithLifecycle() + + val searchButtonEnabled by remember { derivedStateOf { departure.isNotEmpty() && arrival.isNotEmpty() } } Column( modifier = modifier @@ -68,6 +70,7 @@ fun BusSearchScreen( .padding(horizontal = 24.dp), departure = departure, arrival = arrival, + searchButtonEnabled = searchButtonEnabled, onSwapIconClicked = viewModel::swapDepartureAndArrival, onSearchClicked = viewModel::search ) @@ -90,6 +93,7 @@ private fun BusSearchContentView( departure: String, arrival: String, modifier: Modifier = Modifier, + searchButtonEnabled: Boolean = false, onSwapIconClicked: () -> Unit = {}, onSearchClicked: () -> Unit = {} ) { @@ -191,6 +195,7 @@ private fun BusSearchContentView( modifier = Modifier .fillMaxWidth() .padding(bottom = 30.dp), + enabled = searchButtonEnabled, text = stringResource(R.string.search), contentPadding = PaddingValues(vertical = 12.dp), onClick = onSearchClicked @@ -304,7 +309,8 @@ private fun BusSearchScreen3Preview() { .fillMaxSize() .padding(top = 16.dp) .padding(horizontal = 24.dp), - onSwapIconClicked = { } + onSwapIconClicked = { }, + searchButtonEnabled = true ) } } \ No newline at end of file From 2b8edebfcfac8fc98c62b18a2aca715251b035e7 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 13:36:17 +0900 Subject: [PATCH 132/138] =?UTF-8?q?add:=20place=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=EB=B0=94=ED=85=80=EC=8B=9C=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/dialog/ChoiceDialog.kt | 2 +- .../search/composebal/BusSearchScreen.kt | 91 +++++++++++---- .../composebal/SelectPlaceBottomSheet.kt | 108 ++++++++++++++++++ .../bus/screen/search/type/PlaceSelectMode.kt | 7 ++ .../bus/screen/search/type/PlaceType.kt | 12 ++ feature/bus/src/main/res/values/strings.xml | 7 ++ 6 files changed, 204 insertions(+), 23 deletions(-) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceSelectMode.kt create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceType.kt diff --git a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/dialog/ChoiceDialog.kt b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/dialog/ChoiceDialog.kt index 4d2f97fac..136d7cd68 100644 --- a/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/dialog/ChoiceDialog.kt +++ b/core/designsystem/src/main/java/in/koreatech/koin/core/designsystem/component/dialog/ChoiceDialog.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.koin.core.designsystem.component +package `in`.koreatech.koin.core.designsystem.component.dialog import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index 8eb724fb3..6acb20bb0 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -20,11 +20,14 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -33,11 +36,13 @@ import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import `in`.koreatech.bus.screen.search.type.PlaceSelectMode import `in`.koreatech.bus.screen.search.viewmodel.BusSearchViewModel import `in`.koreatech.bus.screen.search.viewmodel.SearchBusUiState import `in`.koreatech.koin.core.designsystem.component.button.FilledButton import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar +import `in`.koreatech.koin.core.designsystem.noRippleClickable import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R @@ -50,11 +55,15 @@ fun BusSearchScreen( viewModel: BusSearchViewModel = hiltViewModel() ) { + val context = LocalContext.current + val departure by viewModel.departure.collectAsStateWithLifecycle() val arrival by viewModel.arrival.collectAsStateWithLifecycle() - + val searchButtonEnabled by remember { derivedStateOf { departure.isNotEmpty() && arrival.isNotEmpty() } } + var placeSelectMode by remember { mutableStateOf(PlaceSelectMode.NONE) } + Column( modifier = modifier ) { @@ -72,10 +81,36 @@ fun BusSearchScreen( arrival = arrival, searchButtonEnabled = searchButtonEnabled, onSwapIconClicked = viewModel::swapDepartureAndArrival, - onSearchClicked = viewModel::search + onSearchClicked = viewModel::search, + onDepartureFieldClicked = { placeSelectMode = PlaceSelectMode.DEPARTURE }, + onArrivalFieldClicked = { placeSelectMode = PlaceSelectMode.ARRIVAL } + ) + } + + if (placeSelectMode != PlaceSelectMode.NONE) { + SelectPlaceBottomSheet( + onDismissRequest = { placeSelectMode = PlaceSelectMode.NONE }, + selectMode = placeSelectMode, + onConfirmSelection = { + when (placeSelectMode) { + PlaceSelectMode.DEPARTURE -> { + placeSelectMode = PlaceSelectMode.ARRIVAL + viewModel.setDeparture(context.getString(it.titleRes)) + } + + PlaceSelectMode.ARRIVAL -> { + placeSelectMode = PlaceSelectMode.NONE + viewModel.setArrival(context.getString(it.titleRes)) + } + + PlaceSelectMode.NONE -> Unit + } + }, + modifier = Modifier, ) } + LaunchedEffect(Unit) { viewModel.searchBusUiState.collect { when(it) { @@ -95,7 +130,9 @@ private fun BusSearchContentView( modifier: Modifier = Modifier, searchButtonEnabled: Boolean = false, onSwapIconClicked: () -> Unit = {}, - onSearchClicked: () -> Unit = {} + onSearchClicked: () -> Unit = {}, + onDepartureFieldClicked: () -> Unit = {}, + onArrivalFieldClicked: () -> Unit = {} ) { KoinSurface { @@ -146,15 +183,20 @@ private fun BusSearchContentView( BusSearchInput( place = departure, placeholder = stringResource(R.string.select_departure), - modifier = Modifier.padding(top = 10.dp).constrainAs(departureField) { - top.linkTo(iconSwap.top) - bottom.linkTo(iconSwap.bottom) - start.linkTo(parent.start) - end.linkTo(iconSwap.start) - - width = Dimension.fillToConstraints - height = Dimension.preferredWrapContent - } + modifier = Modifier + .padding(top = 10.dp) + .noRippleClickable { + onDepartureFieldClicked() + } + .constrainAs(departureField) { + top.linkTo(iconSwap.top) + bottom.linkTo(iconSwap.bottom) + start.linkTo(parent.start) + end.linkTo(iconSwap.start) + + width = Dimension.fillToConstraints + height = Dimension.preferredWrapContent + } ) IconButton( @@ -178,15 +220,20 @@ private fun BusSearchContentView( BusSearchInput( place = arrival, placeholder = stringResource(R.string.select_arrival), - modifier = Modifier.padding(top = 10.dp).constrainAs(arrivalField) { - top.linkTo(iconSwap.top) - bottom.linkTo(iconSwap.bottom) - start.linkTo(iconSwap.end) - end.linkTo(parent.end) - - width = Dimension.fillToConstraints - height = Dimension.preferredWrapContent - } + modifier = Modifier + .padding(top = 10.dp) + .noRippleClickable { + onArrivalFieldClicked() + } + .constrainAs(arrivalField) { + top.linkTo(iconSwap.top) + bottom.linkTo(iconSwap.bottom) + start.linkTo(iconSwap.end) + end.linkTo(parent.end) + + width = Dimension.fillToConstraints + height = Dimension.preferredWrapContent + } ) } @@ -211,7 +258,7 @@ private fun BusSearchInput( modifier: Modifier = Modifier, ) { - val isPlaceDetermined by remember { derivedStateOf { place.isNotEmpty() } } + val isPlaceDetermined = place.isNotEmpty() Column( modifier = modifier, diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt new file mode 100644 index 000000000..cd1f72c68 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt @@ -0,0 +1,108 @@ +package `in`.koreatech.bus.screen.search.composebal + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import `in`.koreatech.bus.screen.search.type.PlaceSelectMode +import `in`.koreatech.bus.screen.search.type.PlaceType +import `in`.koreatech.koin.core.designsystem.component.button.FilledButton +import `in`.koreatech.koin.core.designsystem.component.chip.TextChipGroup +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun SelectPlaceBottomSheet( + onDismissRequest: () -> Unit, + selectMode: PlaceSelectMode, + onConfirmSelection: (selectedPlace: PlaceType) -> Unit, + modifier: Modifier = Modifier, +) { + require(selectMode != PlaceSelectMode.NONE) { + "SelectPlaceBottomSheet should not be used with PlaceSelectMode.NONE" + } + + val context = LocalContext.current + + var selectedPlace by remember { mutableStateOf(PlaceType.KOREATECH) } + val sheetTitle = when (selectMode) { + PlaceSelectMode.DEPARTURE -> stringResource(R.string.question_departure) + PlaceSelectMode.ARRIVAL -> stringResource(R.string.question_arrival) + PlaceSelectMode.NONE -> "" + } + val buttonText = when (selectMode) { + PlaceSelectMode.DEPARTURE -> stringResource(R.string.action_select_arrival) + PlaceSelectMode.ARRIVAL -> stringResource(R.string.confirm_selection) + PlaceSelectMode.NONE -> "" + } + + ModalBottomSheet( + onDismissRequest = onDismissRequest, + modifier = modifier, + containerColor = Color.White, + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), + ) { + + Text( + text = sheetTitle, + style = KoinTheme.typography.medium18, + fontWeight = FontWeight.SemiBold, + modifier = Modifier.padding(horizontal = 32.dp).padding(bottom = 12.dp) + ) + + HorizontalDivider( + color = KoinTheme.colors.neutral200 + ) + + TextChipGroup( + modifier = Modifier.padding(horizontal = 32.dp, vertical = 16.dp), + titles = PlaceType.entries.map { context.getString(it.titleRes) }, + onChipSelected = { + selectedPlace = PlaceType.entries.find { type -> + context.getString(type.titleRes) == it + } ?: PlaceType.KOREATECH + }, + selectedChipIndexes = intArrayOf(selectedPlace.ordinal), + shape = RoundedCornerShape(4.dp), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 12.dp), + showClickRipple = false + ) + + Spacer(modifier = Modifier.height(140.dp)) + FilledButton( + modifier = Modifier.fillMaxWidth().padding(horizontal = 32.dp).padding(bottom = 36.dp), + text = buttonText, + onClick = { onConfirmSelection(selectedPlace) }, + contentPadding = PaddingValues(vertical = 12.dp) + ) + } +} + +@Preview +@Composable +private fun SelectPlaceBottomSheetPreview() { + SelectPlaceBottomSheet( + onDismissRequest = {}, + selectMode = PlaceSelectMode.DEPARTURE, + onConfirmSelection = {} + ) +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceSelectMode.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceSelectMode.kt new file mode 100644 index 000000000..84865ecdc --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceSelectMode.kt @@ -0,0 +1,7 @@ +package `in`.koreatech.bus.screen.search.type + +enum class PlaceSelectMode { + DEPARTURE, + ARRIVAL, + NONE +} diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceType.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceType.kt new file mode 100644 index 000000000..6a3c2335e --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/type/PlaceType.kt @@ -0,0 +1,12 @@ +package `in`.koreatech.bus.screen.search.type + +import androidx.annotation.StringRes +import `in`.koreatech.koin.feature.bus.R + +internal enum class PlaceType( + @StringRes val titleRes: Int +) { + KOREATECH(R.string.koreatech), + CHEONAN_STATION(R.string.cheonan_station), + CHEONAN_TERMINAL(R.string.cheonan_terminal), +} \ No newline at end of file diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index 9aa0fb169..dde5efdbb 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -24,6 +24,13 @@ 도착지 선택 출발지와 도착지를 바꾸기 조회하기 + 어디서 출발하시나요? + 목적지가 어디인가요? + 도착지 선택하기 + 확인하기 + 코리아텍 + 천안역 + 천안터미널 \ No newline at end of file From a62d78137eb2c9a40733425215bec7feddc21b90 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 13:37:47 +0900 Subject: [PATCH 133/138] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/composebal/BusSearchContentView.kt | 199 ++++++++++++++++++ .../search/composebal/BusSearchScreen.kt | 188 ----------------- 2 files changed, 199 insertions(+), 188 deletions(-) create mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt new file mode 100644 index 000000000..f82c8a834 --- /dev/null +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt @@ -0,0 +1,199 @@ +package `in`.koreatech.bus.screen.search.composebal + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension +import `in`.koreatech.koin.core.designsystem.component.button.FilledButton +import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface +import `in`.koreatech.koin.core.designsystem.noRippleClickable +import `in`.koreatech.koin.core.designsystem.theme.KoinTheme +import `in`.koreatech.koin.feature.bus.R + +@Composable +internal fun BusSearchContentView( + departure: String, + arrival: String, + modifier: Modifier = Modifier, + searchButtonEnabled: Boolean = false, + onSwapIconClicked: () -> Unit = {}, + onSearchClicked: () -> Unit = {}, + onDepartureFieldClicked: () -> Unit = {}, + onArrivalFieldClicked: () -> Unit = {} +) { + + KoinSurface { + Column(modifier = modifier) { + Text( + modifier = Modifier, + text = stringResource(R.string.introduce_bus_search), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.neutral800 + ) + + Text( + modifier = Modifier.padding(top = 2.dp), + text = stringResource(R.string.caution_possibly_inaccurate), + style = KoinTheme.typography.regular12, + color = KoinTheme.colors.neutral600 + ) + + ConstraintLayout( + modifier = Modifier + .fillMaxWidth() + .padding(top = 46.dp) + .height(IntrinsicSize.Min) + ) { + val (departureText, arrivalText, departureField, arrivalField, iconSwap) = createRefs() + + Text( + modifier = Modifier.constrainAs(departureText) { + start.linkTo(departureField.start) + top.linkTo(parent.top) + end.linkTo(departureField.end) + }, + text = stringResource(R.string.departure), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.primary500 + ) + Text( + modifier = Modifier.constrainAs(arrivalText) { + top.linkTo(parent.top) + start.linkTo(arrivalField.start) + end.linkTo(arrivalField.end) + }, + text = stringResource(R.string.arrival), + style = KoinTheme.typography.medium16, + color = KoinTheme.colors.primary500 + ) + + BusSearchInput( + place = departure, + placeholder = stringResource(R.string.select_departure), + modifier = Modifier + .padding(top = 10.dp) + .noRippleClickable { + onDepartureFieldClicked() + } + .constrainAs(departureField) { + top.linkTo(iconSwap.top) + bottom.linkTo(iconSwap.bottom) + start.linkTo(parent.start) + end.linkTo(iconSwap.start) + + width = Dimension.fillToConstraints + height = Dimension.preferredWrapContent + } + ) + + IconButton( + onClick = onSwapIconClicked, + modifier = Modifier + .padding(top = 10.dp) + .padding(horizontal = 16.dp, vertical = 12.dp) + .size(32.dp) + .constrainAs(iconSwap) { + top.linkTo(departureText.bottom) + start.linkTo(departureField.end) + end.linkTo(arrivalField.start) + } + ) { + Icon( + painter = painterResource(id = R.drawable.ic_swap), + contentDescription = stringResource(R.string.swap_content_description), + ) + } + + BusSearchInput( + place = arrival, + placeholder = stringResource(R.string.select_arrival), + modifier = Modifier + .padding(top = 10.dp) + .noRippleClickable { + onArrivalFieldClicked() + } + .constrainAs(arrivalField) { + top.linkTo(iconSwap.top) + bottom.linkTo(iconSwap.bottom) + start.linkTo(iconSwap.end) + end.linkTo(parent.end) + + width = Dimension.fillToConstraints + height = Dimension.preferredWrapContent + } + ) + } + + Spacer(modifier = Modifier.weight(1f)) + FilledButton( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 30.dp), + enabled = searchButtonEnabled, + text = stringResource(R.string.search), + contentPadding = PaddingValues(vertical = 12.dp), + onClick = onSearchClicked + ) + } + } +} + +@Composable +private fun BusSearchInput( + place: String, + placeholder: String, + modifier: Modifier = Modifier, +) { + + val isPlaceDetermined = place.isNotEmpty() + + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .clip(RoundedCornerShape(4.dp)) + .background(if (isPlaceDetermined.not()) KoinTheme.colors.neutral100 else Color.Transparent) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + if (isPlaceDetermined.not()) + Text( + text = placeholder, + maxLines = 1, + style = KoinTheme.typography.regular14, + color = KoinTheme.colors.neutral400 // TODO neutral450 ? + ) + else { + Text( + text = place, + maxLines = 1, + style = KoinTheme.typography.bold18, + color = KoinTheme.colors.neutral800 + ) + } + } + } +} \ No newline at end of file diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt index 6acb20bb0..06262dabe 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt @@ -1,21 +1,10 @@ package `in`.koreatech.bus.screen.search.composebal -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -23,27 +12,17 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.constraintlayout.compose.ConstraintLayout -import androidx.constraintlayout.compose.Dimension import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import `in`.koreatech.bus.screen.search.type.PlaceSelectMode import `in`.koreatech.bus.screen.search.viewmodel.BusSearchViewModel import `in`.koreatech.bus.screen.search.viewmodel.SearchBusUiState -import `in`.koreatech.koin.core.designsystem.component.button.FilledButton -import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar -import `in`.koreatech.koin.core.designsystem.noRippleClickable -import `in`.koreatech.koin.core.designsystem.theme.KoinTheme import `in`.koreatech.koin.feature.bus.R @OptIn(ExperimentalMaterial3Api::class) @@ -123,173 +102,6 @@ fun BusSearchScreen( } } -@Composable -private fun BusSearchContentView( - departure: String, - arrival: String, - modifier: Modifier = Modifier, - searchButtonEnabled: Boolean = false, - onSwapIconClicked: () -> Unit = {}, - onSearchClicked: () -> Unit = {}, - onDepartureFieldClicked: () -> Unit = {}, - onArrivalFieldClicked: () -> Unit = {} -) { - - KoinSurface { - Column(modifier = modifier) { - Text( - modifier = Modifier, - text = stringResource(R.string.introduce_bus_search), - style = KoinTheme.typography.medium16, - color = KoinTheme.colors.neutral800 - ) - - Text( - modifier = Modifier.padding(top = 2.dp), - text = stringResource(R.string.caution_possibly_inaccurate), - style = KoinTheme.typography.regular12, - color = KoinTheme.colors.neutral600 - ) - - ConstraintLayout( - modifier = Modifier - .fillMaxWidth() - .padding(top = 46.dp) - .height(IntrinsicSize.Min) - ) { - val (departureText, arrivalText, departureField, arrivalField, iconSwap) = createRefs() - - Text( - modifier = Modifier.constrainAs(departureText) { - start.linkTo(departureField.start) - top.linkTo(parent.top) - end.linkTo(departureField.end) - }, - text = stringResource(R.string.departure), - style = KoinTheme.typography.medium16, - color = KoinTheme.colors.primary500 - ) - Text( - modifier = Modifier.constrainAs(arrivalText) { - top.linkTo(parent.top) - start.linkTo(arrivalField.start) - end.linkTo(arrivalField.end) - }, - text = stringResource(R.string.arrival), - style = KoinTheme.typography.medium16, - color = KoinTheme.colors.primary500 - ) - - BusSearchInput( - place = departure, - placeholder = stringResource(R.string.select_departure), - modifier = Modifier - .padding(top = 10.dp) - .noRippleClickable { - onDepartureFieldClicked() - } - .constrainAs(departureField) { - top.linkTo(iconSwap.top) - bottom.linkTo(iconSwap.bottom) - start.linkTo(parent.start) - end.linkTo(iconSwap.start) - - width = Dimension.fillToConstraints - height = Dimension.preferredWrapContent - } - ) - - IconButton( - onClick = onSwapIconClicked, - modifier = Modifier - .padding(top = 10.dp) - .padding(horizontal = 16.dp, vertical = 12.dp) - .size(32.dp) - .constrainAs(iconSwap) { - top.linkTo(departureText.bottom) - start.linkTo(departureField.end) - end.linkTo(arrivalField.start) - } - ) { - Icon( - painter = painterResource(id = R.drawable.ic_swap), - contentDescription = stringResource(R.string.swap_content_description), - ) - } - - BusSearchInput( - place = arrival, - placeholder = stringResource(R.string.select_arrival), - modifier = Modifier - .padding(top = 10.dp) - .noRippleClickable { - onArrivalFieldClicked() - } - .constrainAs(arrivalField) { - top.linkTo(iconSwap.top) - bottom.linkTo(iconSwap.bottom) - start.linkTo(iconSwap.end) - end.linkTo(parent.end) - - width = Dimension.fillToConstraints - height = Dimension.preferredWrapContent - } - ) - } - - Spacer(modifier = Modifier.weight(1f)) - FilledButton( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 30.dp), - enabled = searchButtonEnabled, - text = stringResource(R.string.search), - contentPadding = PaddingValues(vertical = 12.dp), - onClick = onSearchClicked - ) - } - } -} - -@Composable -private fun BusSearchInput( - place: String, - placeholder: String, - modifier: Modifier = Modifier, -) { - - val isPlaceDetermined = place.isNotEmpty() - - Column( - modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Box( - modifier = Modifier - .clip(RoundedCornerShape(4.dp)) - .background(if (isPlaceDetermined.not()) KoinTheme.colors.neutral100 else Color.Transparent) - .fillMaxSize(), - contentAlignment = Alignment.Center - ) { - if (isPlaceDetermined.not()) - Text( - text = placeholder, - maxLines = 1, - style = KoinTheme.typography.regular14, - color = KoinTheme.colors.neutral400 // TODO neutral450 ? - ) - else { - Text( - text = place, - maxLines = 1, - style = KoinTheme.typography.bold18, - color = KoinTheme.colors.neutral800 - ) - } - } - } -} - @OptIn(ExperimentalMaterial3Api::class) @Preview(showBackground = true) @Composable From eff679d1e6e1b9d62ad1366d14879ab4dde4bb38 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 13:39:33 +0900 Subject: [PATCH 134/138] =?UTF-8?q?chore:=20TODO=20=EC=A3=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/screen/search/composebal/BusSearchContentView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt index f82c8a834..b6f987401 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt @@ -120,7 +120,7 @@ internal fun BusSearchContentView( } ) { Icon( - painter = painterResource(id = R.drawable.ic_swap), + painter = painterResource(id = R.drawable.ic_swap), // TODO : 아이콘 깨짐 contentDescription = stringResource(R.string.swap_content_description), ) } From 9a65dc935dcd95de1d0d1eb7336e95814b33787d Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 18:07:37 +0900 Subject: [PATCH 135/138] =?UTF-8?q?chore:=20=EC=98=A4=ED=83=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/in/koreatech/bus/navigation/BusNavigation.kt | 2 +- .../search/{composebal => composable}/BusSearchContentView.kt | 2 +- .../screen/search/{composebal => composable}/BusSearchScreen.kt | 2 +- .../search/{composebal => composable}/SelectPlaceBottomSheet.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename feature/bus/src/main/java/in/koreatech/bus/screen/search/{composebal => composable}/BusSearchContentView.kt (99%) rename feature/bus/src/main/java/in/koreatech/bus/screen/search/{composebal => composable}/BusSearchScreen.kt (99%) rename feature/bus/src/main/java/in/koreatech/bus/screen/search/{composebal => composable}/SelectPlaceBottomSheet.kt (98%) diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt index d6115b519..9323317fc 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt @@ -9,7 +9,7 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import `in`.koreatech.bus.screen.search.composebal.BusSearchScreen +import `in`.koreatech.bus.screen.search.composable.BusSearchScreen import `in`.koreatech.bus.screen.timetable.composable.BusTimetableScreen @Composable diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/BusSearchContentView.kt similarity index 99% rename from feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt rename to feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/BusSearchContentView.kt index b6f987401..05aeafd3c 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchContentView.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/BusSearchContentView.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.bus.screen.search.composebal +package `in`.koreatech.bus.screen.search.composable import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/BusSearchScreen.kt similarity index 99% rename from feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt rename to feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/BusSearchScreen.kt index 06262dabe..55af22c5f 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/BusSearchScreen.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/BusSearchScreen.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.bus.screen.search.composebal +package `in`.koreatech.bus.screen.search.composable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/SelectPlaceBottomSheet.kt similarity index 98% rename from feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt rename to feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/SelectPlaceBottomSheet.kt index cd1f72c68..cdef4448c 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/search/composebal/SelectPlaceBottomSheet.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/search/composable/SelectPlaceBottomSheet.kt @@ -1,4 +1,4 @@ -package `in`.koreatech.bus.screen.search.composebal +package `in`.koreatech.bus.screen.search.composable import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer From 32ff1fc076fc6317f9c69dbaf309b305a8de9020 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Thu, 7 Nov 2024 22:05:34 +0900 Subject: [PATCH 136/138] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/in/koreatech/bus/navigation/BusNavigation.kt | 8 +++++--- .../bus/screen/timetable/viewmodel/BusViewModel.kt | 11 ----------- 2 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt diff --git a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt index 9323317fc..6e59f2fe9 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/navigation/BusNavigation.kt @@ -2,9 +2,9 @@ package `in`.koreatech.bus.navigation import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -16,7 +16,6 @@ import `in`.koreatech.bus.screen.timetable.composable.BusTimetableScreen fun BusNavigation( modifier: Modifier = Modifier, navController: NavHostController = rememberNavController(), - viewModel: BusViewModel = hiltViewModel() ) { NavHost( @@ -31,7 +30,10 @@ fun BusNavigation( ) { composable { - + BusTimetableScreen( + modifier = Modifier.fillMaxSize(), + onNavigationIconClick = { navController.popBackStack() } + ) } composable { diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt deleted file mode 100644 index aa0234d35..000000000 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/viewmodel/BusViewModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package `in`.koreatech.bus.screen.timetable.viewmodel - -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class BusViewModel @Inject constructor( - -) : ViewModel() { -} \ No newline at end of file From fd91a58378c233055b43642e0b05e55ce8f4bba1 Mon Sep 17 00:00:00 2001 From: Thirfir Date: Fri, 8 Nov 2024 19:53:40 +0900 Subject: [PATCH 137/138] fix: String resource --- .../bus/screen/timetable/composable/CommonTimetableView.kt | 2 +- feature/bus/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt index 2c87b184a..b2d8288e8 100644 --- a/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt +++ b/feature/bus/src/main/java/in/koreatech/bus/screen/timetable/composable/CommonTimetableView.kt @@ -75,7 +75,7 @@ internal fun CommonTimetableView( Text( modifier = Modifier.padding(vertical = 8.dp), - text = stringResource(R.string.updated_at) + " " + timetable.updatedAt, + text = stringResource(R.string.updated_at, timetable.updatedAt), style = KoinTheme.typography.regular14, color = KoinTheme.colors.neutral500 ) diff --git a/feature/bus/src/main/res/values/strings.xml b/feature/bus/src/main/res/values/strings.xml index fb5011bd3..3e3d52010 100644 --- a/feature/bus/src/main/res/values/strings.xml +++ b/feature/bus/src/main/res/values/strings.xml @@ -19,7 +19,7 @@ 천안방면 오전 오후 - 업데이트 날짜 : + 업데이트 날짜 : %s 400번 405번 495번 From 852383f2bffb2ef045e9f2eacc27e6e54aa9d5b9 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Tue, 12 Nov 2024 22:08:34 +0900 Subject: [PATCH 138/138] =?UTF-8?q?fix:=20=EA=B5=AC=EA=B8=80=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=EC=A0=95=EC=B1=85=20=EC=A4=80=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 4 +-- .../feature/forcrupdate/ForceUpdateDialog.kt | 9 +++++-- .../feature/forcrupdate/ForceUpdateScreen.kt | 3 ++- .../store/storedetail/event/EventScreen.kt | 4 ++- .../store/storedetail/event/EventToolbar.kt | 19 +++++++++++--- .../store/storedetail/menu/MenuScreen.kt | 4 +-- .../business/util/ext/ContextExtension.kt | 26 +++++++++++++++++++ business/src/main/res/values/strings.xml | 1 + 8 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 business/src/main/java/in/koreatech/business/util/ext/ContextExtension.kt diff --git a/build.gradle.kts b/build.gradle.kts index 15af55c43..1707aada1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,8 +11,8 @@ buildscript { set("versionCode", 40005) // 코인 버전 관리 - set("versionBusinessName", "1.0.0") - set("versionBusinessCode", 10000) + set("versionBusinessName", "1.0.1") + set("versionBusinessCode", 1000002) //코안 사장님 버전 관리 } diff --git a/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateDialog.kt b/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateDialog.kt index 8f755d40c..a526283ad 100644 --- a/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateDialog.kt +++ b/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateDialog.kt @@ -1,5 +1,6 @@ package `in`.koreatech.business.feature.forcrupdate +import android.content.Context import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -19,6 +20,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -29,12 +31,15 @@ import androidx.compose.ui.window.Dialog import `in`.koreatech.business.ui.theme.ColorPrimary import `in`.koreatech.business.ui.theme.Gray1 import `in`.koreatech.business.ui.theme.Gray500 +import `in`.koreatech.business.util.ext.navigateToPlayStore import `in`.koreatech.koin.core.R +import org.checkerframework.checker.units.qual.Current @Composable fun ForceUpdateDialog( isShow :MutableState = remember { mutableStateOf(true) } ) { + val context = LocalContext.current if(isShow.value){ Dialog( onDismissRequest = { isShow.value = false } @@ -96,7 +101,7 @@ fun ForceUpdateDialog( Button( onClick = { isShow.value = false - //Todo: 플레이스토어 링크 넣기 + context.navigateToPlayStore() }, shape = RoundedCornerShape(4.dp), colors = ButtonDefaults.buttonColors(ColorPrimary), @@ -120,5 +125,5 @@ fun ForceUpdateDialog( @Preview @Composable fun PreviewForceUpdateDialog(){ - ForceUpdateDialog() + //ForceUpdateDialog() } \ No newline at end of file diff --git a/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateScreen.kt b/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateScreen.kt index 6eacc43df..3343696c4 100644 --- a/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/forcrupdate/ForceUpdateScreen.kt @@ -39,6 +39,7 @@ import coil.size.Size import `in`.koreatech.business.ui.theme.ColorPrimary600 import `in`.koreatech.business.ui.theme.ColorSecondary import `in`.koreatech.business.util.GifImage +import `in`.koreatech.business.util.ext.navigateToPlayStore import `in`.koreatech.business.util.getDrawableResSize import `in`.koreatech.koin.core.R @@ -118,7 +119,7 @@ fun ForceUpdateScreen( Button( onClick = { - //Todo: 플레이스토어 링크 넣기 + context.navigateToPlayStore() }, colors = ButtonDefaults.buttonColors(ColorSecondary), shape = RoundedCornerShape(4.dp), diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventScreen.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventScreen.kt index 8f7fce358..978b46610 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import `in`.koreatech.business.R import `in`.koreatech.business.feature.store.storedetail.MyStoreDetailState @@ -20,6 +21,7 @@ fun EventScreen( state: MyStoreDetailState, onDeleteEvent: () -> Unit ) { + val context = LocalContext.current val scrollState = rememberScrollState() val enabledScroll by remember( verticalOffset, scrollState.value @@ -39,7 +41,7 @@ fun EventScreen( if (state.isEditMode) { EventEditToolbar(viewModel, state) } else { - EventToolbar() + EventToolbar(context) } EventItem(enabledScroll, scrollState, viewModel, state) OwnerStoreDialog( diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventToolbar.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventToolbar.kt index ef8a62356..832ee3645 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventToolbar.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/event/EventToolbar.kt @@ -1,5 +1,6 @@ package `in`.koreatech.business.feature.store.storedetail.event +import android.content.Context import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -31,6 +32,7 @@ import `in`.koreatech.business.ui.theme.ColorTextField import `in`.koreatech.business.ui.theme.Gray1 import `in`.koreatech.business.ui.theme.Gray4 import `in`.koreatech.business.ui.theme.Gray6 +import `in`.koreatech.koin.core.toast.ToastUtil @Composable @@ -119,7 +121,9 @@ fun EventEditToolbar(viewModel: MyStoreDetailViewModel, state: MyStoreDetailStat } @Composable -fun EventToolbar() { +fun EventToolbar( + context: Context +) { val viewModel: MyStoreDetailViewModel = hiltViewModel() Row( modifier = Modifier @@ -127,7 +131,12 @@ fun EventToolbar() { .height(52.dp) ) { Button( - onClick = { viewModel.onChangeEditMode() }, + onClick = { + //viewModel.onChangeEditMode() + ToastUtil.getInstance().makeShort( + context.getString(R.string.update_soon) + ) + }, modifier = Modifier .weight(1f) .padding(8.dp), @@ -143,7 +152,11 @@ fun EventToolbar() { Text(text = stringResource(R.string.edit), color= Gray1) } Button( - onClick = { /*TODO*/ }, + onClick = { + ToastUtil.getInstance().makeShort( + context.getString(R.string.update_soon) + ) + }, modifier = Modifier .weight(1f) .padding(8.dp), diff --git a/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt b/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt index e8153c150..a5d95e571 100644 --- a/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt +++ b/business/src/main/java/in/koreatech/business/feature/store/storedetail/menu/MenuScreen.kt @@ -54,7 +54,7 @@ fun MenuScreen( scrollState.scrollTo(0) } } - LazyRow( + /*LazyRow( modifier = Modifier .padding(horizontal = 16.dp, vertical = 9.dp) .fillMaxWidth() @@ -80,7 +80,7 @@ fun MenuScreen( ) } } - } + }*/ LazyColumn( modifier = Modifier .fillMaxSize(), diff --git a/business/src/main/java/in/koreatech/business/util/ext/ContextExtension.kt b/business/src/main/java/in/koreatech/business/util/ext/ContextExtension.kt new file mode 100644 index 000000000..d7a37c211 --- /dev/null +++ b/business/src/main/java/in/koreatech/business/util/ext/ContextExtension.kt @@ -0,0 +1,26 @@ +package `in`.koreatech.business.util.ext + +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.core.content.ContextCompat + +fun Context.navigateToPlayStore() { + val appPackageName: String = packageName + try { + val appStoreIntent = + Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$appPackageName")) + appStoreIntent.setPackage("com.android.vending") + ContextCompat.startActivity(this, appStoreIntent, null) + } catch (exception: ActivityNotFoundException) { + ContextCompat.startActivity( + this, + Intent( + Intent.ACTION_VIEW, + Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName") + ), + null + ) + } +} \ No newline at end of file diff --git a/business/src/main/res/values/strings.xml b/business/src/main/res/values/strings.xml index 299aed591..18a208314 100644 --- a/business/src/main/res/values/strings.xml +++ b/business/src/main/res/values/strings.xml @@ -187,4 +187,5 @@ 회원 탈퇴 현재 로그인 되어 있는 계정을\n 탈퇴하시겠습니까? 탈퇴가 완료되었습니다. + 추후 업데이트로 추가 예정입니다