diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3afdf50a..d7f247c7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -39,8 +39,11 @@ dependencies { implementation(project(":feature:signin")) implementation(project(":feature:signup")) - implementation(project(":feature:home")) + implementation(project(":feature:program")) implementation(project(":feature:expo")) + implementation(project(":feature:standard")) + implementation(project(":feature:training")) + implementation(project(":feature:sms")) implementation(libs.androidx.core.splashscreen) diff --git a/app/src/main/java/com/school_of_company/expo_android/navigation/ExpoNavHost.kt b/app/src/main/java/com/school_of_company/expo_android/navigation/ExpoNavHost.kt index 8328e135..2df1029f 100644 --- a/app/src/main/java/com/school_of_company/expo_android/navigation/ExpoNavHost.kt +++ b/app/src/main/java/com/school_of_company/expo_android/navigation/ExpoNavHost.kt @@ -14,23 +14,23 @@ import com.school_of_company.expo.navigation.navigateToExpoDetail import com.school_of_company.expo.navigation.navigateToExpoModify import com.school_of_company.expo.navigation.navigateToHome import com.school_of_company.expo_android.ui.ExpoAppState -import com.school_of_company.home.navigation.homeDetailParticipantManagementScreen -import com.school_of_company.home.navigation.homeDetailProgramScreen -import com.school_of_company.home.navigation.homeDetailStandardProgramParticipantScreen -import com.school_of_company.home.navigation.homeDetailTrainingProgramParticipantScreen -import com.school_of_company.home.navigation.homeSendMessageScreen -import com.school_of_company.home.navigation.navigateQrScanner -import com.school_of_company.home.navigation.navigateToHomeDetailParticipantManagement -import com.school_of_company.home.navigation.navigateToHomeDetailProgram -import com.school_of_company.home.navigation.navigateToHomeDetailStandardProgramParticipant -import com.school_of_company.home.navigation.navigateToHomeDetailTrainingProgramParticipant -import com.school_of_company.home.navigation.navigateToHomeSendMessage -import com.school_of_company.home.navigation.qrScannerScreen +import com.school_of_company.program.navigation.navigateQrScanner +import com.school_of_company.program.navigation.qrScannerScreen import com.school_of_company.navigation.navigateToSignIn import com.school_of_company.navigation.sigInRoute import com.school_of_company.navigation.signInScreen +import com.school_of_company.program.navigation.navigateToProgramDetailParticipantManagement +import com.school_of_company.program.navigation.navigateToProgramDetailProgram +import com.school_of_company.program.navigation.programDetailParticipantManagementScreen +import com.school_of_company.program.navigation.programDetailProgramScreen import com.school_of_company.signup.navigation.navigationToSignUp import com.school_of_company.signup.navigation.signUpScreen +import com.school_of_company.sms.navigation.navigateToSmsSendMessage +import com.school_of_company.sms.navigation.smsSendMessageScreen +import com.school_of_company.standard.navigation.navigateToStandardProgramParticipant +import com.school_of_company.standard.navigation.standardProgramParticipantScreen +import com.school_of_company.training.navigation.navigateToTrainingProgramParticipant +import com.school_of_company.training.navigation.trainingProgramParticipantScreen import com.school_of_company.ui.toast.makeToast @Composable @@ -82,42 +82,42 @@ fun ExpoNavHost( expoDetailScreen( onBackClick = navController::popBackStack, - onMessageClick = navController::navigateToHomeSendMessage, - onCheckClick = navController::navigateToHomeDetailParticipantManagement, + onMessageClick = navController::navigateToSmsSendMessage, + onCheckClick = navController::navigateToProgramDetailParticipantManagement, onQrGenerateClick = {}, onModifyClick = { id -> navController.navigateToExpoModify(id) }, onProgramClick = { id -> - navController.navigateToHomeDetailProgram(id) + navController.navigateToProgramDetailProgram(id) } ) - homeSendMessageScreen( + smsSendMessageScreen( onBackClick = navController::popBackStack, ) - homeDetailProgramScreen( + programDetailProgramScreen( onBackClick = navController::popBackStack, navigateToTrainingProgramDetail = { id -> - navController.navigateToHomeDetailTrainingProgramParticipant(id) + navController.navigateToTrainingProgramParticipant(id) }, navigateToStandardProgramDetail = { id -> - navController.navigateToHomeDetailStandardProgramParticipant(id) + navController.navigateToStandardProgramParticipant(id) } ) - homeDetailTrainingProgramParticipantScreen( + trainingProgramParticipantScreen( onBackClick = navController::popBackStack, navigateToQrScanner = navController::navigateQrScanner ) - homeDetailStandardProgramParticipantScreen( + standardProgramParticipantScreen( onBackClick = navController::popBackStack, navigateToQrScanner = navController::navigateQrScanner ) - homeDetailParticipantManagementScreen( + programDetailParticipantManagementScreen( onBackClick = navController::popBackStack ) diff --git a/feature/home/src/main/java/com/school_of_company/home/navigation/HomeNavigation.kt b/feature/home/src/main/java/com/school_of_company/home/navigation/HomeNavigation.kt deleted file mode 100644 index 9355d672..00000000 --- a/feature/home/src/main/java/com/school_of_company/home/navigation/HomeNavigation.kt +++ /dev/null @@ -1,156 +0,0 @@ -package com.school_of_company.home.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHost -import androidx.navigation.NavOptions -import androidx.navigation.compose.composable -import com.school_of_company.home.view.HomeDetailParticipantManagementRoute -import com.school_of_company.home.view.HomeDetailProgramParticipantRoute -import com.school_of_company.home.view.HomeDetailProgramRoute -import com.school_of_company.home.view.HomeDetailStandardProgramParticipantRoute -import com.school_of_company.home.view.HomeDetailStandardProgramParticipantScreen -import com.school_of_company.home.view.QrScannerRoute -import com.school_of_company.home.view.SendMessageRoute - -const val homeSendMessageRoute = "home_send_message_route" -const val homeDetailProgramRoute = "home_detail_program_route" -const val homeDetailTrainingProgramParticipantRoute = "home_detail_program_participant_route" -const val homeDetailStandardProgramParticipantRoute = "home_detail_standard_program_participant_route" -const val homeDetailParticipantManagementRoute = "home_detail_participant_management_route" -const val qrScannerRoute = "qr_scanner_route" - -fun NavController.navigateToHomeSendMessage(navOptions: NavOptions? = null) { - this.navigate(homeSendMessageRoute, navOptions) -} - -fun NavController.navigateToHomeDetailProgram( - id: String, - navOptions: NavOptions? = null -) { - this.navigate( - route = "$homeDetailProgramRoute/${id}", - navOptions - ) -} - -fun NavController.navigateToHomeDetailTrainingProgramParticipant( - id: Long, - navOptions: NavOptions? = null -) { - this.navigate( - route = "$homeDetailTrainingProgramParticipantRoute/${id}", - navOptions - ) -} - -fun NavController.navigateToHomeDetailStandardProgramParticipant( - id: Long, - navOptions: NavOptions? = null -) { - this.navigate( - route = "$homeDetailStandardProgramParticipantRoute/${id}", - navOptions - ) -} - -fun NavController.navigateToHomeDetailParticipantManagement(navOptions: NavOptions? = null) { - this.navigate(homeDetailParticipantManagementRoute, navOptions) -} - -fun NavGraphBuilder.homeSendMessageScreen( - onBackClick: () -> Unit -) { - composable(route = homeSendMessageRoute) { - SendMessageRoute( - onBackClick = onBackClick - ) - } -} - -fun NavController.navigateQrScanner( - id: Long, - traineeId: Long, - navOptions: NavOptions? = null -) { - this.navigate( - route = "$qrScannerRoute/${id}/${traineeId}", - navOptions - ) -} - -fun NavGraphBuilder.homeDetailProgramScreen( - onBackClick: () -> Unit, - navigateToTrainingProgramDetail: (Long) -> Unit, - navigateToStandardProgramDetail: (Long) -> Unit -) { - composable(route = "$homeDetailProgramRoute/{id}") { backStackEntry -> - val id = backStackEntry.arguments?.getString("id") ?: "" - HomeDetailProgramRoute( - id = id, - onBackClick = onBackClick, - navigateToTrainingProgramDetail = navigateToTrainingProgramDetail, - navigateToStandardProgramDetail = navigateToStandardProgramDetail - ) - } -} - -fun NavGraphBuilder.homeDetailTrainingProgramParticipantScreen( - onBackClick: () -> Unit, - navigateToQrScanner: (Long, Long) -> Unit -) { - composable(route = "$homeDetailTrainingProgramParticipantRoute/{id}") { backStackEntry -> - val id = backStackEntry.arguments?.getString("id")?.toLongOrNull() - if (id != null) { - HomeDetailProgramParticipantRoute( - id = id, - onBackClick = onBackClick, - navigateToQrScanner = navigateToQrScanner - ) - } - } -} - -fun NavGraphBuilder.homeDetailStandardProgramParticipantScreen( - onBackClick: () -> Unit, - navigateToQrScanner: (Long, Long) -> Unit -) { - composable(route = "$homeDetailStandardProgramParticipantRoute/{id}") { backStackEntry -> - val id = backStackEntry.arguments?.getString("id")?.toLongOrNull() - if (id != null) { - HomeDetailStandardProgramParticipantRoute( - id = id, - onBackClick = onBackClick, - navigateToQrScanner = navigateToQrScanner - ) - } - } -} - -fun NavGraphBuilder.homeDetailParticipantManagementScreen( - onBackClick: () -> Unit -) { - composable(route = homeDetailParticipantManagementRoute) { - HomeDetailParticipantManagementRoute( - onBackClick = onBackClick - ) - } -} - -fun NavGraphBuilder.qrScannerScreen( - onBackClick: () -> Unit, - onPermissionBlock: () -> Unit -) { - composable(route = "$qrScannerRoute/{id}/{traineeId}") { backStackEntry -> - val id = backStackEntry.arguments?.getString("id")?.toLongOrNull() - val traineeId = backStackEntry.arguments?.getString("traineeId")?.toLongOrNull() - if (id != null && traineeId != null) { - QrScannerRoute( - id = id, - traineeId = traineeId, - onBackClick = onBackClick, - onPermissionBlock = onPermissionBlock - ) - } - } -} \ No newline at end of file diff --git a/feature/home/.gitignore b/feature/program/.gitignore similarity index 100% rename from feature/home/.gitignore rename to feature/program/.gitignore diff --git a/feature/home/build.gradle.kts b/feature/program/build.gradle.kts similarity index 100% rename from feature/home/build.gradle.kts rename to feature/program/build.gradle.kts diff --git a/feature/home/consumer-rules.pro b/feature/program/consumer-rules.pro similarity index 100% rename from feature/home/consumer-rules.pro rename to feature/program/consumer-rules.pro diff --git a/feature/home/proguard-rules.pro b/feature/program/proguard-rules.pro similarity index 100% rename from feature/home/proguard-rules.pro rename to feature/program/proguard-rules.pro diff --git a/feature/home/src/androidTest/java/com/school_of_company/home/ExampleInstrumentedTest.kt b/feature/program/src/androidTest/java/com/school_of_company/program/ExampleInstrumentedTest.kt similarity index 94% rename from feature/home/src/androidTest/java/com/school_of_company/home/ExampleInstrumentedTest.kt rename to feature/program/src/androidTest/java/com/school_of_company/program/ExampleInstrumentedTest.kt index 2c37f695..f7f0095a 100644 --- a/feature/home/src/androidTest/java/com/school_of_company/home/ExampleInstrumentedTest.kt +++ b/feature/program/src/androidTest/java/com/school_of_company/program/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home +package com.school_of_company.program import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 diff --git a/feature/home/src/main/AndroidManifest.xml b/feature/program/src/main/AndroidManifest.xml similarity index 100% rename from feature/home/src/main/AndroidManifest.xml rename to feature/program/src/main/AndroidManifest.xml diff --git a/feature/home/src/main/java/com/school_of_company/home/enum/ProgramEnum.kt b/feature/program/src/main/java/com/school_of_company/program/enum/ProgramEnum.kt similarity index 54% rename from feature/home/src/main/java/com/school_of_company/home/enum/ProgramEnum.kt rename to feature/program/src/main/java/com/school_of_company/program/enum/ProgramEnum.kt index 9037ddec..1d5491c4 100644 --- a/feature/home/src/main/java/com/school_of_company/home/enum/ProgramEnum.kt +++ b/feature/program/src/main/java/com/school_of_company/program/enum/ProgramEnum.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.enum +package com.school_of_company.program.enum enum class ProgramEnum { NORMAL, diff --git a/feature/program/src/main/java/com/school_of_company/program/navigation/ProgramNavigation.kt b/feature/program/src/main/java/com/school_of_company/program/navigation/ProgramNavigation.kt new file mode 100644 index 00000000..42cbdb80 --- /dev/null +++ b/feature/program/src/main/java/com/school_of_company/program/navigation/ProgramNavigation.kt @@ -0,0 +1,82 @@ +package com.school_of_company.program.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.school_of_company.program.view.ProgramDetailParticipantManagementRoute +import com.school_of_company.program.view.ProgramDetailProgramRoute +import com.school_of_company.program.view.QrScannerRoute + +const val programDetailProgramRoute = "program_detail_program_route" +const val programDetailParticipantManagementRoute = "program_detail_participant_management_route" +const val qrScannerRoute = "qr_scanner_route" + +fun NavController.navigateToProgramDetailProgram( + id: String, + navOptions: NavOptions? = null +) { + this.navigate( + route = "$programDetailProgramRoute/${id}", + navOptions + ) +} + +fun NavController.navigateToProgramDetailParticipantManagement(navOptions: NavOptions? = null) { + this.navigate(programDetailParticipantManagementRoute, navOptions) +} + +fun NavController.navigateQrScanner( + id: Long, + traineeId: Long, + navOptions: NavOptions? = null +) { + this.navigate( + route = "$qrScannerRoute/${id}/${traineeId}", + navOptions + ) +} + +fun NavGraphBuilder.programDetailProgramScreen( + onBackClick: () -> Unit, + navigateToTrainingProgramDetail: (Long) -> Unit, + navigateToStandardProgramDetail: (Long) -> Unit +) { + composable(route = "$programDetailProgramRoute/{id}") { backStackEntry -> + val id = backStackEntry.arguments?.getString("id") ?: "" + ProgramDetailProgramRoute( + id = id, + onBackClick = onBackClick, + navigateToTrainingProgramDetail = navigateToTrainingProgramDetail, + navigateToStandardProgramDetail = navigateToStandardProgramDetail + ) + } +} + +fun NavGraphBuilder.programDetailParticipantManagementScreen( + onBackClick: () -> Unit +) { + composable(route = programDetailParticipantManagementRoute) { + ProgramDetailParticipantManagementRoute( + onBackClick = onBackClick + ) + } +} + +fun NavGraphBuilder.qrScannerScreen( + onBackClick: () -> Unit, + onPermissionBlock: () -> Unit +) { + composable(route = "$qrScannerRoute/{id}/{traineeId}") { backStackEntry -> + val id = backStackEntry.arguments?.getString("id")?.toLongOrNull() + val traineeId = backStackEntry.arguments?.getString("traineeId")?.toLongOrNull() + if (id != null && traineeId != null) { + QrScannerRoute( + id = id, + traineeId = traineeId, + onBackClick = onBackClick, + onPermissionBlock = onPermissionBlock + ) + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/util/QrcodeScanner.kt b/feature/program/src/main/java/com/school_of_company/program/util/QrcodeScanner.kt similarity index 98% rename from feature/home/src/main/java/com/school_of_company/home/util/QrcodeScanner.kt rename to feature/program/src/main/java/com/school_of_company/program/util/QrcodeScanner.kt index f2aabe1a..df4ba057 100644 --- a/feature/home/src/main/java/com/school_of_company/home/util/QrcodeScanner.kt +++ b/feature/program/src/main/java/com/school_of_company/program/util/QrcodeScanner.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.util +package com.school_of_company.program.util import android.util.Log import androidx.camera.core.ImageAnalysis diff --git a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailParticipantManagementScreen.kt b/feature/program/src/main/java/com/school_of_company/program/view/ProgramDetailParticipantManagementScreen.kt similarity index 93% rename from feature/home/src/main/java/com/school_of_company/home/view/HomeDetailParticipantManagementScreen.kt rename to feature/program/src/main/java/com/school_of_company/program/view/ProgramDetailParticipantManagementScreen.kt index ad2dd839..900927c0 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailParticipantManagementScreen.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/ProgramDetailParticipantManagementScreen.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view +package com.school_of_company.program.view import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -26,8 +26,8 @@ import com.school_of_company.design_system.component.topbar.ExpoTopBar import com.school_of_company.design_system.icon.LeftArrowIcon import com.school_of_company.design_system.icon.WarnIcon import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.component.HomeDetailParticipantManagementData -import com.school_of_company.home.view.component.HomeDetailParticipantManagementList +import com.school_of_company.program.view.component.HomeDetailParticipantManagementData +import com.school_of_company.program.view.component.ProgramDetailParticipantManagementList import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList @@ -46,17 +46,17 @@ fun generateParticipantManagementSampleData(): ImmutableList Unit ) { - HomeDetailParticipantManagementScreen( + ProgramDetailParticipantManagementScreen( onBackClick = onBackClick, participantManagementData = generateParticipantManagementSampleData() ) } @Composable -internal fun HomeDetailParticipantManagementScreen( +internal fun ProgramDetailParticipantManagementScreen( modifier: Modifier = Modifier, participantManagementData: ImmutableList, onBackClick: () -> Unit @@ -204,7 +204,7 @@ internal fun HomeDetailParticipantManagementScreen( } } - HomeDetailParticipantManagementList(item = participantManagementData) + ProgramDetailParticipantManagementList(item = participantManagementData) } } } @@ -212,7 +212,7 @@ internal fun HomeDetailParticipantManagementScreen( @Preview @Composable private fun HomeDetailParticipantManagementScreenPreview() { - HomeDetailParticipantManagementScreen( + ProgramDetailParticipantManagementScreen( onBackClick = {}, participantManagementData = generateParticipantManagementSampleData() ) diff --git a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailProgramScreen.kt b/feature/program/src/main/java/com/school_of_company/program/view/ProgramDetailProgramScreen.kt similarity index 95% rename from feature/home/src/main/java/com/school_of_company/home/view/HomeDetailProgramScreen.kt rename to feature/program/src/main/java/com/school_of_company/program/view/ProgramDetailProgramScreen.kt index 8e338e5d..6201e53d 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailProgramScreen.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/ProgramDetailProgramScreen.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view +package com.school_of_company.program.view import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState @@ -32,7 +31,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -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 @@ -47,24 +45,24 @@ import com.school_of_company.design_system.icon.ExpoIcon import com.school_of_company.design_system.icon.LeftArrowIcon import com.school_of_company.design_system.icon.WarnIcon import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.component.ProgramList -import com.school_of_company.home.view.component.ProgramTabRowItem -import com.school_of_company.home.view.component.StandardProgramList -import com.school_of_company.home.viewmodel.HomeViewModel -import com.school_of_company.home.viewmodel.uistate.StandardProgramListUiState -import com.school_of_company.home.viewmodel.uistate.TrainingProgramListUiState +import com.school_of_company.program.view.component.ProgramList +import com.school_of_company.program.view.component.ProgramTabRowItem +import com.school_of_company.program.view.component.StandardProgramList +import com.school_of_company.program.viewmodel.ProgramViewModel +import com.school_of_company.program.viewmodel.uistate.StandardProgramListUiState +import com.school_of_company.program.viewmodel.uistate.TrainingProgramListUiState import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @Composable -internal fun HomeDetailProgramRoute( +internal fun ProgramDetailProgramRoute( id: String, onBackClick: () -> Unit, navigateToTrainingProgramDetail: (Long) -> Unit, navigateToStandardProgramDetail: (Long) -> Unit, - viewModel: HomeViewModel = hiltViewModel() + viewModel: ProgramViewModel = hiltViewModel() ) { val swipeRefreshLoading by viewModel.swipeRefreshLoading.collectAsStateWithLifecycle() val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = swipeRefreshLoading) @@ -73,7 +71,7 @@ internal fun HomeDetailProgramRoute( val standardProgramListUiState by viewModel.standardProgramListUiState.collectAsStateWithLifecycle() - HomeDetailProgramScreen( + ProgramDetailProgramScreen( onBackClick = onBackClick, navigateToTrainingProgramDetail = navigateToTrainingProgramDetail, navigateToStandardProgramDetail = navigateToStandardProgramDetail, @@ -91,7 +89,7 @@ internal fun HomeDetailProgramRoute( } @Composable -internal fun HomeDetailProgramScreen( +internal fun ProgramDetailProgramScreen( modifier: Modifier = Modifier, swipeRefreshState: SwipeRefreshState, trainingProgramUiState: TrainingProgramListUiState, @@ -357,7 +355,7 @@ internal fun HomeDetailProgramScreen( @Preview @Composable private fun HomeDetailProgramScreenPreview() { - HomeDetailProgramScreen( + ProgramDetailProgramScreen( onBackClick = {}, trainingProgramUiState = TrainingProgramListUiState.Loading, standardProgramListUiState = StandardProgramListUiState.Loading, diff --git a/feature/home/src/main/java/com/school_of_company/home/view/QrScannerScreen.kt b/feature/program/src/main/java/com/school_of_company/program/view/QrScannerScreen.kt similarity index 92% rename from feature/home/src/main/java/com/school_of_company/home/view/QrScannerScreen.kt rename to feature/program/src/main/java/com/school_of_company/program/view/QrScannerScreen.kt index f02efb5f..48d5ad38 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/QrScannerScreen.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/QrScannerScreen.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view +package com.school_of_company.program.view import android.Manifest import androidx.compose.foundation.layout.Column @@ -23,9 +23,9 @@ import com.school_of_company.design_system.component.modifier.clickable.expoClic import com.school_of_company.design_system.component.topbar.ExpoTopBar import com.school_of_company.design_system.icon.LeftArrowIcon import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.component.QrcodeScanView -import com.school_of_company.home.viewmodel.HomeViewModel -import com.school_of_company.home.viewmodel.uistate.TrainingQrCodeUiState +import com.school_of_company.program.view.component.QrcodeScanView +import com.school_of_company.program.viewmodel.ProgramViewModel +import com.school_of_company.program.viewmodel.uistate.TrainingQrCodeUiState import com.school_of_company.model.param.attendance.TrainingQrCodeRequestParam import com.school_of_company.ui.toast.makeToast @@ -36,7 +36,7 @@ internal fun QrScannerRoute( traineeId: Long, onBackClick: () -> Unit, onPermissionBlock: () -> Unit, - viewModel: HomeViewModel = hiltViewModel() + viewModel: ProgramViewModel = hiltViewModel() ) { val trainingQrCodeUiState by viewModel.trainingQrCodeUiState.collectAsStateWithLifecycle() diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailParticipantManagementList.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramDetailParticipantManagementList.kt similarity index 81% rename from feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailParticipantManagementList.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/ProgramDetailParticipantManagementList.kt index e1221a09..c75547d7 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailParticipantManagementList.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramDetailParticipantManagementList.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.background import androidx.compose.foundation.layout.fillMaxSize @@ -10,12 +10,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.generateParticipantManagementSampleData +import com.school_of_company.program.view.generateParticipantManagementSampleData import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @Composable -fun HomeDetailParticipantManagementList( +fun ProgramDetailParticipantManagementList( modifier: Modifier = Modifier, item: ImmutableList = persistentListOf() ) { @@ -27,7 +27,7 @@ fun HomeDetailParticipantManagementList( .padding(start = 16.dp) ) { itemsIndexed(item) { index, item -> - HomeDetailParticipantManagementListItem( + ProgramDetailParticipantManagementListItem( index = index + 1, data = item ) @@ -39,7 +39,7 @@ fun HomeDetailParticipantManagementList( @Preview @Composable private fun HomeDetailParticipantManagementListPreview() { - HomeDetailParticipantManagementList( + ProgramDetailParticipantManagementList( item = generateParticipantManagementSampleData() ) } \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailParticipantManagementListItem.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramDetailParticipantManagementListItem.kt similarity index 96% rename from feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailParticipantManagementListItem.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/ProgramDetailParticipantManagementListItem.kt index 3fbeea14..9441824b 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailParticipantManagementListItem.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramDetailParticipantManagementListItem.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.horizontalScroll @@ -29,7 +29,7 @@ data class HomeDetailParticipantManagementData( ) @Composable -fun HomeDetailParticipantManagementListItem( +fun ProgramDetailParticipantManagementListItem( modifier: Modifier = Modifier, index: Int, data: HomeDetailParticipantManagementData, @@ -108,7 +108,7 @@ fun HomeDetailParticipantManagementListItem( @Preview @Composable private fun HomeDetailParticipantManagementListItemPreview() { - HomeDetailParticipantManagementListItem( + ProgramDetailParticipantManagementListItem( index = 1, data = HomeDetailParticipantManagementData( name = "이명훈", diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/ProgramList.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramList.kt similarity index 98% rename from feature/home/src/main/java/com/school_of_company/home/view/component/ProgramList.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/ProgramList.kt index 641891a1..6d61ecda 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/ProgramList.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramList.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/ProgramListItem.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramListItem.kt similarity index 98% rename from feature/home/src/main/java/com/school_of_company/home/view/component/ProgramListItem.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/ProgramListItem.kt index 9f9ed826..34af3037 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/ProgramListItem.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramListItem.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/ProgramTabRowItem.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramTabRowItem.kt similarity index 96% rename from feature/home/src/main/java/com/school_of_company/home/view/component/ProgramTabRowItem.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/ProgramTabRowItem.kt index 3b1473e2..daeca443 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/ProgramTabRowItem.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/ProgramTabRowItem.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/QrButton.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/QrButton.kt similarity index 94% rename from feature/home/src/main/java/com/school_of_company/home/view/component/QrButton.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/QrButton.kt index 6a37bbc6..4b67bce5 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/QrButton.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/QrButton.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.school_of_company.design_system.component.modifier.clickable.expoClickable import com.school_of_company.design_system.theme.ExpoAndroidTheme diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/QrScannView.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/QrScannView.kt similarity index 97% rename from feature/home/src/main/java/com/school_of_company/home/view/component/QrScannView.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/QrScannView.kt index 817cdb2c..12416a48 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/QrScannView.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/QrScannView.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import android.util.Log import androidx.camera.core.CameraSelector @@ -19,7 +19,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat import androidx.lifecycle.LifecycleOwner -import com.school_of_company.home.util.QrcodeScanner +import com.school_of_company.program.util.QrcodeScanner import java.util.concurrent.Executors @androidx.camera.core.ExperimentalGetImage diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/StandardProgramListItem.kt b/feature/program/src/main/java/com/school_of_company/program/view/component/StandardProgramListItem.kt similarity index 98% rename from feature/home/src/main/java/com/school_of_company/home/view/component/StandardProgramListItem.kt rename to feature/program/src/main/java/com/school_of_company/program/view/component/StandardProgramListItem.kt index c9c14c13..aa24934f 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/StandardProgramListItem.kt +++ b/feature/program/src/main/java/com/school_of_company/program/view/component/StandardProgramListItem.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.program.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background diff --git a/feature/home/src/main/java/com/school_of_company/home/viewmodel/HomeViewModel.kt b/feature/program/src/main/java/com/school_of_company/program/viewmodel/ProgramViewModel.kt similarity index 59% rename from feature/home/src/main/java/com/school_of_company/home/viewmodel/HomeViewModel.kt rename to feature/program/src/main/java/com/school_of_company/program/viewmodel/ProgramViewModel.kt index 1f568304..f33a9b1c 100644 --- a/feature/home/src/main/java/com/school_of_company/home/viewmodel/HomeViewModel.kt +++ b/feature/program/src/main/java/com/school_of_company/program/viewmodel/ProgramViewModel.kt @@ -1,21 +1,16 @@ -package com.school_of_company.home.viewmodel +package com.school_of_company.program.viewmodel -import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.school_of_company.common.result.Result import com.school_of_company.common.result.asResult import com.school_of_company.domain.usecase.attendance.TrainingQrCodeRequestUseCase -import com.school_of_company.domain.usecase.standard.StandardProgramAttendListUseCase import com.school_of_company.domain.usecase.standard.StandardProgramListUseCase -import com.school_of_company.domain.usecase.training.TeacherTrainingProgramListUseCase import com.school_of_company.domain.usecase.training.TrainingProgramListUseCase -import com.school_of_company.home.viewmodel.uistate.StandardProgramAttendListUiState -import com.school_of_company.home.viewmodel.uistate.StandardProgramListUiState -import com.school_of_company.home.viewmodel.uistate.TeacherTrainingProgramListUiState -import com.school_of_company.home.viewmodel.uistate.TrainingProgramListUiState -import com.school_of_company.home.viewmodel.uistate.TrainingQrCodeUiState +import com.school_of_company.program.viewmodel.uistate.StandardProgramListUiState +import com.school_of_company.program.viewmodel.uistate.TrainingProgramListUiState +import com.school_of_company.program.viewmodel.uistate.TrainingQrCodeUiState import com.school_of_company.model.param.attendance.TrainingQrCodeRequestParam import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -26,11 +21,9 @@ import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class HomeViewModel @Inject constructor( +class ProgramViewModel @Inject constructor( private val trainingProgramListUseCase: TrainingProgramListUseCase, private val standardProgramListUseCase: StandardProgramListUseCase, - private val teacherTrainingProgramListUseCase: TeacherTrainingProgramListUseCase, - private val standardProgramAttendListUseCase: StandardProgramAttendListUseCase, private val trainingQrCodeRequestUseCase: TrainingQrCodeRequestUseCase, private val savedStateHandle: SavedStateHandle ) : ViewModel() { @@ -48,12 +41,6 @@ class HomeViewModel @Inject constructor( private val _standardProgramListUiState = MutableStateFlow(StandardProgramListUiState.Loading) internal val standardProgramListUiState = _standardProgramListUiState.asStateFlow() - private val _teacherTrainingProgramListUiState = MutableStateFlow(TeacherTrainingProgramListUiState.Loading) - internal val teacherTrainingProgramListUiState = _teacherTrainingProgramListUiState.asStateFlow() - - private val _standardProgramAttendListUiState = MutableStateFlow(StandardProgramAttendListUiState.Loading) - internal val standardProgramAttendListUiState = _standardProgramAttendListUiState.asStateFlow() - private val _trainingQrCodeUiState = MutableStateFlow(TrainingQrCodeUiState.Loading) internal val trainingQrCodeUiState = _trainingQrCodeUiState.asStateFlow() @@ -109,51 +96,6 @@ class HomeViewModel @Inject constructor( } } - internal fun teacherTrainingProgramList(trainingProId: Long) = viewModelScope.launch { - _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Loading - teacherTrainingProgramListUseCase(trainingProId = trainingProId) - .asResult() - .collectLatest { result -> - when (result) { - is Result.Loading -> _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Loading - is Result.Success -> { - if (result.data.isEmpty()) { - _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Empty - } else { - _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Success(result.data) - } - } - is Result.Error -> { - _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Error(result.exception) - } - } - } - } - - internal fun standardProgramList(standardProId: Long) = viewModelScope.launch { - _swipeRefreshLoading.value = true - standardProgramAttendListUseCase(standardProId = standardProId) - .asResult() - .collectLatest { result -> - when (result) { - is Result.Loading -> _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Loading - is Result.Success -> { - if (result.data.isEmpty()) { - _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Empty - _swipeRefreshLoading.value = false - } else { - _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Success(result.data) - _swipeRefreshLoading.value = false - } - } - is Result.Error -> { - _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Error(result.exception) - _swipeRefreshLoading.value = false - } - } - } - } - internal fun trainingQrCode( trainingId: Long, body: TrainingQrCodeRequestParam diff --git a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/StandardProgramListUiState.kt b/feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/StandardProgramListUiState.kt similarity index 87% rename from feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/StandardProgramListUiState.kt rename to feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/StandardProgramListUiState.kt index 6c212037..63ae63d7 100644 --- a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/StandardProgramListUiState.kt +++ b/feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/StandardProgramListUiState.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.viewmodel.uistate +package com.school_of_company.program.viewmodel.uistate import com.school_of_company.model.entity.standard.StandardProgramListResponseEntity diff --git a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TrainingProgramListUiState.kt b/feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/TrainingProgramListUiState.kt similarity index 87% rename from feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TrainingProgramListUiState.kt rename to feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/TrainingProgramListUiState.kt index e9840ed6..9af0d5f8 100644 --- a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TrainingProgramListUiState.kt +++ b/feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/TrainingProgramListUiState.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.viewmodel.uistate +package com.school_of_company.program.viewmodel.uistate import com.school_of_company.model.entity.training.TrainingProgramListResponseEntity diff --git a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TrainingQrCodeUiState.kt b/feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/TrainingQrCodeUiState.kt similarity index 78% rename from feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TrainingQrCodeUiState.kt rename to feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/TrainingQrCodeUiState.kt index d01485e1..ae722e3e 100644 --- a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TrainingQrCodeUiState.kt +++ b/feature/program/src/main/java/com/school_of_company/program/viewmodel/uistate/TrainingQrCodeUiState.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.viewmodel.uistate +package com.school_of_company.program.viewmodel.uistate sealed interface TrainingQrCodeUiState { object Loading : TrainingQrCodeUiState diff --git a/feature/program/src/test/java/com/school_of_company/program/ExampleUnitTest.kt b/feature/program/src/test/java/com/school_of_company/program/ExampleUnitTest.kt new file mode 100644 index 00000000..b6094cc7 --- /dev/null +++ b/feature/program/src/test/java/com/school_of_company/program/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.school_of_company.program + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/feature/sms/.gitignore b/feature/sms/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature/sms/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/sms/build.gradle.kts b/feature/sms/build.gradle.kts new file mode 100644 index 00000000..7393777f --- /dev/null +++ b/feature/sms/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + id("expo.android.feature") + id("expo.android.hilt") +} + +android { + namespace = "com.school_of_company.sms" +} \ No newline at end of file diff --git a/feature/sms/consumer-rules.pro b/feature/sms/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/feature/sms/proguard-rules.pro b/feature/sms/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/feature/sms/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature/sms/src/androidTest/java/com/school_of_company/sms/ExampleInstrumentedTest.kt b/feature/sms/src/androidTest/java/com/school_of_company/sms/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..3b33ef70 --- /dev/null +++ b/feature/sms/src/androidTest/java/com/school_of_company/sms/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.school_of_company.sms + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.school_of_company.sms.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature/sms/src/main/AndroidManifest.xml b/feature/sms/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/feature/sms/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature/sms/src/main/java/com/school_of_company/sms/navigation/SmsNavigation.kt b/feature/sms/src/main/java/com/school_of_company/sms/navigation/SmsNavigation.kt new file mode 100644 index 00000000..3ac7f5e3 --- /dev/null +++ b/feature/sms/src/main/java/com/school_of_company/sms/navigation/SmsNavigation.kt @@ -0,0 +1,23 @@ +package com.school_of_company.sms.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.school_of_company.sms.view.SendMessageRoute + +const val smsSendMessageRoute = "sms_send_message_route" + +fun NavController.navigateToSmsSendMessage(navOptions: NavOptions? = null) { + this.navigate(smsSendMessageRoute, navOptions) +} + +fun NavGraphBuilder.smsSendMessageScreen( + onBackClick: () -> Unit +) { + composable(route = smsSendMessageRoute) { + SendMessageRoute( + onBackClick = onBackClick + ) + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/SendMessageScreen.kt b/feature/sms/src/main/java/com/school_of_company/sms/view/SendMessageScreen.kt similarity index 94% rename from feature/home/src/main/java/com/school_of_company/home/view/SendMessageScreen.kt rename to feature/sms/src/main/java/com/school_of_company/sms/view/SendMessageScreen.kt index 6bcc5ac9..3b0399ac 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/SendMessageScreen.kt +++ b/feature/sms/src/main/java/com/school_of_company/sms/view/SendMessageScreen.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view +package com.school_of_company.sms.view import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectTapGestures @@ -24,13 +24,13 @@ import com.school_of_company.design_system.component.modifier.padding.paddingHor import com.school_of_company.design_system.component.textfield.LimitedLengthTextField import com.school_of_company.design_system.icon.LeftArrowIcon import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.component.HomeSendMessageTopBar -import com.school_of_company.home.viewmodel.HomeViewModel +import com.school_of_company.sms.view.component.HomeSendMessageTopBar +import com.school_of_company.sms.viewmodel.SmsViewModel @Composable internal fun SendMessageRoute( onBackClick: () -> Unit, - viewModel: HomeViewModel = hiltViewModel() + viewModel: SmsViewModel = hiltViewModel() ) { val title by viewModel.title.collectAsStateWithLifecycle() val content by viewModel.content.collectAsStateWithLifecycle() @@ -54,7 +54,7 @@ internal fun SendMessageScreen( onContentChange: (String) -> Unit, focusManager: FocusManager = LocalFocusManager.current ) { - ExpoAndroidTheme { colors, typography -> + ExpoAndroidTheme { colors, _ -> Column( modifier = modifier diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeSendMessageTopBar.kt b/feature/sms/src/main/java/com/school_of_company/sms/view/component/SendMessageTopBar.kt similarity index 96% rename from feature/home/src/main/java/com/school_of_company/home/view/component/HomeSendMessageTopBar.kt rename to feature/sms/src/main/java/com/school_of_company/sms/view/component/SendMessageTopBar.kt index 3d4b5c8d..789d5734 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeSendMessageTopBar.kt +++ b/feature/sms/src/main/java/com/school_of_company/sms/view/component/SendMessageTopBar.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.sms.view.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row diff --git a/feature/sms/src/main/java/com/school_of_company/sms/viewmodel/SmsViewModel.kt b/feature/sms/src/main/java/com/school_of_company/sms/viewmodel/SmsViewModel.kt new file mode 100644 index 00000000..e02c4b15 --- /dev/null +++ b/feature/sms/src/main/java/com/school_of_company/sms/viewmodel/SmsViewModel.kt @@ -0,0 +1,26 @@ +package com.school_of_company.sms.viewmodel + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import javax.inject.Inject + +class SmsViewModel @Inject constructor( + private val savedStateHandle: SavedStateHandle +) : ViewModel() { + companion object { + private const val TITLE = "title" + private const val CONTENT = "content" + } + + internal var title = savedStateHandle.getStateFlow(key = TITLE, initialValue = "") + + internal var content = savedStateHandle.getStateFlow(key = CONTENT, initialValue = "") + + internal fun onTitleChange(value: String) { + savedStateHandle[TITLE] = value + } + + internal fun onContentChange(value: String) { + savedStateHandle[CONTENT] = value + } +} \ No newline at end of file diff --git a/feature/home/src/test/java/com/school_of_company/home/ExampleUnitTest.kt b/feature/sms/src/test/java/com/school_of_company/sms/ExampleUnitTest.kt similarity index 90% rename from feature/home/src/test/java/com/school_of_company/home/ExampleUnitTest.kt rename to feature/sms/src/test/java/com/school_of_company/sms/ExampleUnitTest.kt index 3d268f53..4fec0590 100644 --- a/feature/home/src/test/java/com/school_of_company/home/ExampleUnitTest.kt +++ b/feature/sms/src/test/java/com/school_of_company/sms/ExampleUnitTest.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home +package com.school_of_company.sms import org.junit.Test diff --git a/feature/standard/.gitignore b/feature/standard/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature/standard/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/standard/build.gradle.kts b/feature/standard/build.gradle.kts new file mode 100644 index 00000000..83c35de3 --- /dev/null +++ b/feature/standard/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("expo.android.feature") + id("expo.android.hilt") +} + +android { + namespace = "com.school_of_company.standard" +} + +dependencies { + implementation(libs.swiperefresh) +} \ No newline at end of file diff --git a/feature/standard/consumer-rules.pro b/feature/standard/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/feature/standard/proguard-rules.pro b/feature/standard/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/feature/standard/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature/standard/src/androidTest/java/com/school_of_company/standard/ExampleInstrumentedTest.kt b/feature/standard/src/androidTest/java/com/school_of_company/standard/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..5bde696c --- /dev/null +++ b/feature/standard/src/androidTest/java/com/school_of_company/standard/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.school_of_company.standard + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.school_of_company.standard.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature/standard/src/main/AndroidManifest.xml b/feature/standard/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/feature/standard/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature/standard/src/main/java/com/school_of_company/standard/navigation/StandardNavigation.kt b/feature/standard/src/main/java/com/school_of_company/standard/navigation/StandardNavigation.kt new file mode 100644 index 00000000..9a87064a --- /dev/null +++ b/feature/standard/src/main/java/com/school_of_company/standard/navigation/StandardNavigation.kt @@ -0,0 +1,35 @@ +package com.school_of_company.standard.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.school_of_company.standard.view.StandardProgramParticipantRoute + +const val standardProgramParticipantRoute = "standard_program_participant_route" + +fun NavController.navigateToStandardProgramParticipant( + id: Long, + navOptions: NavOptions? = null +) { + this.navigate( + route = "$standardProgramParticipantRoute/${id}", + navOptions + ) +} + +fun NavGraphBuilder.standardProgramParticipantScreen( + onBackClick: () -> Unit, + navigateToQrScanner: (Long, Long) -> Unit +) { + composable(route = "$standardProgramParticipantRoute/{id}") { backStackEntry -> + val id = backStackEntry.arguments?.getString("id")?.toLongOrNull() + if (id != null) { + StandardProgramParticipantRoute( + id = id, + onBackClick = onBackClick, + navigateToQrScanner = navigateToQrScanner + ) + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailStandardProgramParticipantScreen.kt b/feature/standard/src/main/java/com/school_of_company/standard/view/StandardProgramParticipantScreen.kt similarity index 95% rename from feature/home/src/main/java/com/school_of_company/home/view/HomeDetailStandardProgramParticipantScreen.kt rename to feature/standard/src/main/java/com/school_of_company/standard/view/StandardProgramParticipantScreen.kt index 5307be49..e0c2dc86 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailStandardProgramParticipantScreen.kt +++ b/feature/standard/src/main/java/com/school_of_company/standard/view/StandardProgramParticipantScreen.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view +package com.school_of_company.standard.view import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background @@ -36,18 +36,18 @@ import com.school_of_company.design_system.icon.ExpoIcon import com.school_of_company.design_system.icon.LeftArrowIcon import com.school_of_company.design_system.icon.WarnIcon import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.component.HomeDetailStandardParticipantList -import com.school_of_company.home.view.component.QrButton -import com.school_of_company.home.viewmodel.HomeViewModel -import com.school_of_company.home.viewmodel.uistate.StandardProgramAttendListUiState +import com.school_of_company.standard.view.component.QrButton +import com.school_of_company.standard.view.component.StandardParticipantList +import com.school_of_company.standard.viewmodel.StandardViewModel +import com.school_of_company.standard.viewmodel.uistate.StandardProgramAttendListUiState import kotlinx.collections.immutable.toImmutableList @Composable -internal fun HomeDetailStandardProgramParticipantRoute( +internal fun StandardProgramParticipantRoute( id: Long, onBackClick: () -> Unit, navigateToQrScanner: (Long, Long) -> Unit, - viewModel: HomeViewModel = hiltViewModel() + viewModel: StandardViewModel = hiltViewModel() ) { val swipeRefreshLoading by viewModel.swipeRefreshLoading.collectAsStateWithLifecycle() val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = swipeRefreshLoading) @@ -61,7 +61,7 @@ internal fun HomeDetailStandardProgramParticipantRoute( else -> -1L } - HomeDetailStandardProgramParticipantScreen( + StandardProgramParticipantScreen( id = id, onBackClick = onBackClick, standardProgramAttendListUiState = standardProgramAttendListUiState, @@ -77,7 +77,7 @@ internal fun HomeDetailStandardProgramParticipantRoute( } @Composable -internal fun HomeDetailStandardProgramParticipantScreen( +internal fun StandardProgramParticipantScreen( id: Long, modifier: Modifier = Modifier, swipeRefreshState: SwipeRefreshState, @@ -271,7 +271,7 @@ internal fun HomeDetailStandardProgramParticipantScreen( when (standardProgramAttendListUiState) { is StandardProgramAttendListUiState.Loading -> Unit is StandardProgramAttendListUiState.Success -> { - HomeDetailStandardParticipantList( + StandardParticipantList( item = standardProgramAttendListUiState.data.toImmutableList(), horizontalScrollState = scrollState ) diff --git a/feature/standard/src/main/java/com/school_of_company/standard/view/component/QrButton.kt b/feature/standard/src/main/java/com/school_of_company/standard/view/component/QrButton.kt new file mode 100644 index 00000000..bd18a3ea --- /dev/null +++ b/feature/standard/src/main/java/com/school_of_company/standard/view/component/QrButton.kt @@ -0,0 +1,54 @@ +package com.school_of_company.standard.view.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +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.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.school_of_company.design_system.component.modifier.clickable.expoClickable +import com.school_of_company.design_system.theme.ExpoAndroidTheme + +@Composable +fun QrButton( + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + ExpoAndroidTheme { colors, typography -> + + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .background( + color = colors.main, + shape = RoundedCornerShape(10.dp), + ) + .expoClickable( + onClick = onClick, + rippleColor = colors.white + ) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding( + horizontal = 12.dp, + vertical = 8.dp + ) + ) { + Text( + text = "QR 스캔", + style = typography.bodyBold2, + fontWeight = FontWeight.SemiBold, + color = colors.white, + ) + } + } + } +} \ No newline at end of file diff --git a/feature/standard/src/main/java/com/school_of_company/standard/view/component/StandardParticipantList.kt b/feature/standard/src/main/java/com/school_of_company/standard/view/component/StandardParticipantList.kt new file mode 100644 index 00000000..68d13f1d --- /dev/null +++ b/feature/standard/src/main/java/com/school_of_company/standard/view/component/StandardParticipantList.kt @@ -0,0 +1,39 @@ +package com.school_of_company.standard.view.component + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.school_of_company.design_system.theme.ExpoAndroidTheme +import com.school_of_company.model.entity.standard.StandardAttendListResponseEntity +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +@Composable +fun StandardParticipantList( + modifier: Modifier = Modifier, + item: ImmutableList = persistentListOf(), + horizontalScrollState: ScrollState +) { + ExpoAndroidTheme { colors, _ -> + LazyColumn( + modifier = modifier + .fillMaxSize() + .background(color = colors.white) + .padding(start = 16.dp) + ) { + itemsIndexed(item) { index, item -> + StandardProgramParticipantListItem( + index = index + 1, + data = item, + horizontalScrollState = horizontalScrollState + ) + } + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailStandardProgramParticipantListItem.kt b/feature/standard/src/main/java/com/school_of_company/standard/view/component/StandardProgramParticipantListItem.kt similarity index 92% rename from feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailStandardProgramParticipantListItem.kt rename to feature/standard/src/main/java/com/school_of_company/standard/view/component/StandardProgramParticipantListItem.kt index c1f76a03..1616ba2c 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailStandardProgramParticipantListItem.kt +++ b/feature/standard/src/main/java/com/school_of_company/standard/view/component/StandardProgramParticipantListItem.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.standard.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background @@ -10,7 +10,6 @@ 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.foundation.rememberScrollState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -18,10 +17,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.school_of_company.design_system.theme.ExpoAndroidTheme import com.school_of_company.model.entity.standard.StandardAttendListResponseEntity -import com.school_of_company.model.entity.training.TeacherTrainingProgramResponseEntity @Composable -fun HomeDetailStandardProgramParticipantListItem( +fun StandardProgramParticipantListItem( modifier: Modifier = Modifier, index: Int, data: StandardAttendListResponseEntity, diff --git a/feature/standard/src/main/java/com/school_of_company/standard/viewmodel/StandardViewModel.kt b/feature/standard/src/main/java/com/school_of_company/standard/viewmodel/StandardViewModel.kt new file mode 100644 index 00000000..e8595c9c --- /dev/null +++ b/feature/standard/src/main/java/com/school_of_company/standard/viewmodel/StandardViewModel.kt @@ -0,0 +1,50 @@ +package com.school_of_company.standard.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.school_of_company.common.result.Result +import com.school_of_company.common.result.asResult +import com.school_of_company.domain.usecase.standard.StandardProgramAttendListUseCase +import com.school_of_company.standard.viewmodel.uistate.StandardProgramAttendListUiState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class StandardViewModel @Inject constructor( + private val standardProgramAttendListUseCase: StandardProgramAttendListUseCase +) : ViewModel() { + + private val _swipeRefreshLoading = MutableStateFlow(false) + internal val swipeRefreshLoading = _swipeRefreshLoading.asStateFlow() + + private val _standardProgramAttendListUiState = MutableStateFlow(StandardProgramAttendListUiState.Loading) + internal val standardProgramAttendListUiState = _standardProgramAttendListUiState.asStateFlow() + + internal fun standardProgramList(standardProId: Long) = viewModelScope.launch { + _swipeRefreshLoading.value = true + standardProgramAttendListUseCase(standardProId = standardProId) + .asResult() + .collectLatest { result -> + when (result) { + is Result.Loading -> _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Loading + is Result.Success -> { + if (result.data.isEmpty()) { + _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Empty + _swipeRefreshLoading.value = false + } else { + _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Success(result.data) + _swipeRefreshLoading.value = false + } + } + is Result.Error -> { + _standardProgramAttendListUiState.value = StandardProgramAttendListUiState.Error(result.exception) + _swipeRefreshLoading.value = false + } + } + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/StandardProgramAttendListUiState.kt b/feature/standard/src/main/java/com/school_of_company/standard/viewmodel/uistate/StandardProgramAttendListUiState.kt similarity index 78% rename from feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/StandardProgramAttendListUiState.kt rename to feature/standard/src/main/java/com/school_of_company/standard/viewmodel/uistate/StandardProgramAttendListUiState.kt index 058c8465..53fa6782 100644 --- a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/StandardProgramAttendListUiState.kt +++ b/feature/standard/src/main/java/com/school_of_company/standard/viewmodel/uistate/StandardProgramAttendListUiState.kt @@ -1,10 +1,11 @@ -package com.school_of_company.home.viewmodel.uistate +package com.school_of_company.standard.viewmodel.uistate import com.school_of_company.model.entity.standard.StandardAttendListResponseEntity sealed interface StandardProgramAttendListUiState { object Loading : StandardProgramAttendListUiState object Empty : StandardProgramAttendListUiState - data class Success(val data: List) : StandardProgramAttendListUiState + data class Success(val data: List) : + StandardProgramAttendListUiState data class Error(val exception: Throwable) : StandardProgramAttendListUiState } \ No newline at end of file diff --git a/feature/standard/src/test/java/com/school_of_company/standard/ExampleUnitTest.kt b/feature/standard/src/test/java/com/school_of_company/standard/ExampleUnitTest.kt new file mode 100644 index 00000000..b29ba493 --- /dev/null +++ b/feature/standard/src/test/java/com/school_of_company/standard/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.school_of_company.standard + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/feature/training/.gitignore b/feature/training/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature/training/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/training/build.gradle.kts b/feature/training/build.gradle.kts new file mode 100644 index 00000000..a836e9b2 --- /dev/null +++ b/feature/training/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("expo.android.feature") + id("expo.android.hilt") +} + +android { + namespace = "com.school_of_company.training" +} + +dependencies { + + implementation(libs.swiperefresh) +} \ No newline at end of file diff --git a/feature/training/consumer-rules.pro b/feature/training/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/feature/training/proguard-rules.pro b/feature/training/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/feature/training/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature/training/src/androidTest/java/com/school_of_company/training/ExampleInstrumentedTest.kt b/feature/training/src/androidTest/java/com/school_of_company/training/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..71c9688e --- /dev/null +++ b/feature/training/src/androidTest/java/com/school_of_company/training/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.school_of_company.training + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.school_of_company.training.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature/training/src/main/AndroidManifest.xml b/feature/training/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/feature/training/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature/training/src/main/java/com/school_of_company/training/navigation/TrainingNavigation.kt b/feature/training/src/main/java/com/school_of_company/training/navigation/TrainingNavigation.kt new file mode 100644 index 00000000..3d48f37e --- /dev/null +++ b/feature/training/src/main/java/com/school_of_company/training/navigation/TrainingNavigation.kt @@ -0,0 +1,35 @@ +package com.school_of_company.training.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.school_of_company.training.view.TrainingProgramParticipantRoute + +const val trainingProgramParticipantRoute = "training_program_participant_route" + +fun NavController.navigateToTrainingProgramParticipant( + id: Long, + navOptions: NavOptions? = null +) { + this.navigate( + route = "$trainingProgramParticipantRoute/${id}", + navOptions + ) +} + +fun NavGraphBuilder.trainingProgramParticipantScreen( + onBackClick: () -> Unit, + navigateToQrScanner: (Long, Long) -> Unit +) { + composable(route = "$trainingProgramParticipantRoute/{id}") { backStackEntry -> + val id = backStackEntry.arguments?.getString("id")?.toLongOrNull() + if (id != null) { + TrainingProgramParticipantRoute( + id = id, + onBackClick = onBackClick, + navigateToQrScanner = navigateToQrScanner + ) + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailTrainingProgramParticipantScreen.kt b/feature/training/src/main/java/com/school_of_company/training/view/TrainingProgramParticipantScreen.kt similarity index 95% rename from feature/home/src/main/java/com/school_of_company/home/view/HomeDetailTrainingProgramParticipantScreen.kt rename to feature/training/src/main/java/com/school_of_company/training/view/TrainingProgramParticipantScreen.kt index 7e4701e8..b850f3c2 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/HomeDetailTrainingProgramParticipantScreen.kt +++ b/feature/training/src/main/java/com/school_of_company/training/view/TrainingProgramParticipantScreen.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view +package com.school_of_company.training.view import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background @@ -37,18 +37,18 @@ import com.school_of_company.design_system.icon.ExpoIcon import com.school_of_company.design_system.icon.LeftArrowIcon import com.school_of_company.design_system.icon.WarnIcon import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.home.view.component.HomeDetailProgramParticipantList -import com.school_of_company.home.view.component.QrButton -import com.school_of_company.home.viewmodel.HomeViewModel -import com.school_of_company.home.viewmodel.uistate.TeacherTrainingProgramListUiState +import com.school_of_company.training.view.component.QrButton +import com.school_of_company.training.view.component.TrainingProgramParticipantList +import com.school_of_company.training.viewmodel.TrainingViewModel +import com.school_of_company.training.viewmodel.uistate.TeacherTrainingProgramListUiState import kotlinx.collections.immutable.toImmutableList @Composable -internal fun HomeDetailProgramParticipantRoute( +internal fun TrainingProgramParticipantRoute( id: Long, onBackClick: () -> Unit, navigateToQrScanner: (Long, Long) -> Unit, - viewModel: HomeViewModel = hiltViewModel() + viewModel: TrainingViewModel = hiltViewModel() ) { val swipeRefreshLoading by viewModel.swipeRefreshLoading.collectAsStateWithLifecycle() val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = swipeRefreshLoading) @@ -62,7 +62,7 @@ internal fun HomeDetailProgramParticipantRoute( else -> -1L } - HomeDetailProgramParticipantScreen( + TrainingProgramParticipantScreen( id = id, onBackClick = onBackClick, teacherTrainingProgramListUiState = teacherTrainingProgramListUiState, @@ -78,7 +78,7 @@ internal fun HomeDetailProgramParticipantRoute( } @Composable -internal fun HomeDetailProgramParticipantScreen( +internal fun TrainingProgramParticipantScreen( id: Long, modifier: Modifier = Modifier, swipeRefreshState: SwipeRefreshState, @@ -273,7 +273,7 @@ internal fun HomeDetailProgramParticipantScreen( when (teacherTrainingProgramListUiState) { is TeacherTrainingProgramListUiState.Loading -> Unit is TeacherTrainingProgramListUiState.Success -> { - HomeDetailProgramParticipantList( + TrainingProgramParticipantList( item = teacherTrainingProgramListUiState.data.toImmutableList(), horizontalScrollState = scrollState ) @@ -330,7 +330,7 @@ internal fun HomeDetailProgramParticipantScreen( @Preview @Composable private fun HomeDetailProgramParticipantScreenPreview() { - HomeDetailProgramParticipantScreen( + TrainingProgramParticipantScreen( id = 0, onBackClick = {}, teacherTrainingProgramListUiState = TeacherTrainingProgramListUiState.Loading, diff --git a/feature/training/src/main/java/com/school_of_company/training/view/component/QrButton.kt b/feature/training/src/main/java/com/school_of_company/training/view/component/QrButton.kt new file mode 100644 index 00000000..59459329 --- /dev/null +++ b/feature/training/src/main/java/com/school_of_company/training/view/component/QrButton.kt @@ -0,0 +1,54 @@ +package com.school_of_company.training.view.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +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.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.school_of_company.design_system.component.modifier.clickable.expoClickable +import com.school_of_company.design_system.theme.ExpoAndroidTheme + +@Composable +fun QrButton( + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + ExpoAndroidTheme { colors, typography -> + + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .background( + color = colors.main, + shape = RoundedCornerShape(10.dp), + ) + .expoClickable( + onClick = onClick, + rippleColor = colors.white + ) + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding( + horizontal = 12.dp, + vertical = 8.dp + ) + ) { + Text( + text = "QR 스캔", + style = typography.bodyBold2, + fontWeight = FontWeight.SemiBold, + color = colors.white, + ) + } + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailProgramParticipantList.kt b/feature/training/src/main/java/com/school_of_company/training/view/component/TrainingProgramParticipantList.kt similarity index 60% rename from feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailProgramParticipantList.kt rename to feature/training/src/main/java/com/school_of_company/training/view/component/TrainingProgramParticipantList.kt index de402476..962a4d5f 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailProgramParticipantList.kt +++ b/feature/training/src/main/java/com/school_of_company/training/view/component/TrainingProgramParticipantList.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.training.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background @@ -11,13 +11,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.school_of_company.design_system.theme.ExpoAndroidTheme -import com.school_of_company.model.entity.standard.StandardAttendListResponseEntity import com.school_of_company.model.entity.training.TeacherTrainingProgramResponseEntity import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @Composable -fun HomeDetailProgramParticipantList( +fun TrainingProgramParticipantList( modifier: Modifier = Modifier, item: ImmutableList = persistentListOf(), horizontalScrollState: ScrollState @@ -30,31 +29,7 @@ fun HomeDetailProgramParticipantList( .padding(start = 16.dp) ) { itemsIndexed(item) { index, item -> - HomeDetailProgramParticipantListItem( - index = index + 1, - data = item, - horizontalScrollState = horizontalScrollState - ) - } - } - } -} - -@Composable -fun HomeDetailStandardParticipantList( - modifier: Modifier = Modifier, - item: ImmutableList = persistentListOf(), - horizontalScrollState: ScrollState -) { - ExpoAndroidTheme { colors, _ -> - LazyColumn( - modifier = modifier - .fillMaxSize() - .background(color = colors.white) - .padding(start = 16.dp) - ) { - itemsIndexed(item) { index, item -> - HomeDetailStandardProgramParticipantListItem( + TrainingProgramParticipantListItem( index = index + 1, data = item, horizontalScrollState = horizontalScrollState @@ -67,5 +42,4 @@ fun HomeDetailStandardParticipantList( @Preview @Composable private fun HomeDetailProgramParticipantListPreview() { - } \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailProgramParticipantListItem.kt b/feature/training/src/main/java/com/school_of_company/training/view/component/TrainingProgramParticipantListItem.kt similarity index 96% rename from feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailProgramParticipantListItem.kt rename to feature/training/src/main/java/com/school_of_company/training/view/component/TrainingProgramParticipantListItem.kt index dfab3885..8923d9d1 100644 --- a/feature/home/src/main/java/com/school_of_company/home/view/component/HomeDetailProgramParticipantListItem.kt +++ b/feature/training/src/main/java/com/school_of_company/training/view/component/TrainingProgramParticipantListItem.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.view.component +package com.school_of_company.training.view.component import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background @@ -21,7 +21,7 @@ import com.school_of_company.design_system.theme.ExpoAndroidTheme import com.school_of_company.model.entity.training.TeacherTrainingProgramResponseEntity @Composable -fun HomeDetailProgramParticipantListItem( +fun TrainingProgramParticipantListItem( modifier: Modifier = Modifier, index: Int, data: TeacherTrainingProgramResponseEntity, @@ -94,7 +94,7 @@ fun HomeDetailProgramParticipantListItem( @Preview @Composable private fun HomeDetailProgramParticipantListItemPreview() { - HomeDetailProgramParticipantListItem( + TrainingProgramParticipantListItem( index = 1, data = TeacherTrainingProgramResponseEntity( id = 0, diff --git a/feature/training/src/main/java/com/school_of_company/training/viewmodel/TrainingViewModel.kt b/feature/training/src/main/java/com/school_of_company/training/viewmodel/TrainingViewModel.kt new file mode 100644 index 00000000..1df8ebc0 --- /dev/null +++ b/feature/training/src/main/java/com/school_of_company/training/viewmodel/TrainingViewModel.kt @@ -0,0 +1,46 @@ +package com.school_of_company.training.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.school_of_company.common.result.Result +import com.school_of_company.common.result.asResult +import com.school_of_company.domain.usecase.training.TeacherTrainingProgramListUseCase +import com.school_of_company.training.viewmodel.uistate.TeacherTrainingProgramListUiState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class TrainingViewModel @Inject constructor( + private val teacherTrainingProgramListUseCase: TeacherTrainingProgramListUseCase +) : ViewModel() { + private val _swipeRefreshLoading = MutableStateFlow(false) + internal val swipeRefreshLoading = _swipeRefreshLoading.asStateFlow() + + private val _teacherTrainingProgramListUiState = MutableStateFlow(TeacherTrainingProgramListUiState.Loading) + internal val teacherTrainingProgramListUiState = _teacherTrainingProgramListUiState.asStateFlow() + + internal fun teacherTrainingProgramList(trainingProId: Long) = viewModelScope.launch { + _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Loading + teacherTrainingProgramListUseCase(trainingProId = trainingProId) + .asResult() + .collectLatest { result -> + when (result) { + is Result.Loading -> _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Loading + is Result.Success -> { + if (result.data.isEmpty()) { + _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Empty + } else { + _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Success(result.data) + } + } + is Result.Error -> { + _teacherTrainingProgramListUiState.value = TeacherTrainingProgramListUiState.Error(result.exception) + } + } + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TeacherTrainingProgramListUiState.kt b/feature/training/src/main/java/com/school_of_company/training/viewmodel/uistate/TeacherTrainingProgramListUiState.kt similarity index 88% rename from feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TeacherTrainingProgramListUiState.kt rename to feature/training/src/main/java/com/school_of_company/training/viewmodel/uistate/TeacherTrainingProgramListUiState.kt index c020a481..61e06878 100644 --- a/feature/home/src/main/java/com/school_of_company/home/viewmodel/uistate/TeacherTrainingProgramListUiState.kt +++ b/feature/training/src/main/java/com/school_of_company/training/viewmodel/uistate/TeacherTrainingProgramListUiState.kt @@ -1,4 +1,4 @@ -package com.school_of_company.home.viewmodel.uistate +package com.school_of_company.training.viewmodel.uistate import com.school_of_company.model.entity.training.TeacherTrainingProgramResponseEntity diff --git a/feature/training/src/test/java/com/school_of_company/training/ExampleUnitTest.kt b/feature/training/src/test/java/com/school_of_company/training/ExampleUnitTest.kt new file mode 100644 index 00000000..b75bca9a --- /dev/null +++ b/feature/training/src/test/java/com/school_of_company/training/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.school_of_company.training + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 30baa498..73013093 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,6 +33,9 @@ include(":core:ui") include(":feature") include(":feature:signin") include(":feature:signup") -include(":feature:home") +include(":feature:program") include(":feature:expo") gradle.startParameter.excludedTaskNames.addAll(listOf(":build-logic:convention:testClasses")) +include(":feature:training") +include(":feature:standard") +include(":feature:sms")