diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/container/SuwikiExamReviewContainer.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/container/SuwikiExamReviewContainer.kt index 982d58dcb..75dfdff18 100644 --- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/container/SuwikiExamReviewContainer.kt +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/container/SuwikiExamReviewContainer.kt @@ -29,6 +29,8 @@ fun SuwikiExamReviewContainer( modifier: Modifier = Modifier, difficulty: String, examType: String, + semester: String, + examInfo: String, content: String, isAuthor: Boolean = false, onClickButton: () -> Unit, @@ -53,12 +55,12 @@ fun SuwikiExamReviewContainer( } SuwikiBadge( color = BadgeColor.Gray, - text = stringResource(id = R.string.word_semester), + text = semester, ) Spacer(modifier = Modifier.width(6.dp)) SuwikiBadge( color = BadgeColor.Gray, - text = stringResource(id = R.string.word_type_exam), + text = examType, ) Spacer(modifier = Modifier.weight(1f)) SuwikiContainedSmallButton(text = buttonText, onClick = onClickButton) @@ -90,7 +92,7 @@ fun SuwikiExamReviewContainer( color = Gray95, ) Text( - text = examType, + text = examInfo, style = SuwikiTheme.typography.caption1, color = Black, ) @@ -112,16 +114,20 @@ fun SuwikiExamReviewContainerPreview() { SuwikiExamReviewContainer( isAuthor = false, difficulty = "어려움", - examType = "응용,실습,과제,PPT", + examInfo = "응용,실습,과제,PPT", content = "거의 한 학기 팀플하시는데... 팀원 잘 만나면 잘 모르겠네요. 굉장히 오픈 마인드시긴해요.", onClickButton = {}, + examType = "중간고사", + semester = "2023-1", ) SuwikiExamReviewContainer( isAuthor = true, difficulty = "어려움", - examType = "응용,실습,과제,PPT", + examType = "중간고사", content = "거의 한 학기 팀플하시는데... 팀원 잘 만나면 잘 모르겠네요. 굉장히 오픈 마인드시긴해요.", onClickButton = {}, + semester = "2023-1", + examInfo = "응용,실습,과제,PPT", ) } } diff --git a/core/model/src/main/java/com/suwiki/core/model/lectureevaluation/lecture/MyLectureEvaluation.kt b/core/model/src/main/java/com/suwiki/core/model/lectureevaluation/lecture/MyLectureEvaluation.kt index 5b1af3dfd..4fe8f1b45 100644 --- a/core/model/src/main/java/com/suwiki/core/model/lectureevaluation/lecture/MyLectureEvaluation.kt +++ b/core/model/src/main/java/com/suwiki/core/model/lectureevaluation/lecture/MyLectureEvaluation.kt @@ -9,12 +9,12 @@ data class MyLectureEvaluation( val id: Long = 0, val lectureInfo: LectureInfo = LectureInfo(), val selectedSemester: String = "", - val totalAvg: Float = 0f, // 총점 - val satisfaction: Float = 0f, // 만족도 - val learning: Float = 0f, // 배움지수 - val honey: Float = 0f, // 꿀강지수 + val totalAvg: Float = 2.5f, // 총점 + val satisfaction: Float = 2.5f, // 만족도 + val learning: Float = 2.5f, // 배움지수 + val honey: Float = 2.5f, // 꿀강지수 val team: Int = 0, // 조별모임 유무(없음 == 0, 있음 == 1) - val difficulty: Int = 0, // 학점 잘주는가? (까다로움 == 0, 보통 == 1, 학점느님 ==2) - val homework: Int = 0, // 과제양 (없음 ==0, 보통 == 1, 많음 == 2) + val difficulty: Int = 1, // 학점 잘주는가? (까다로움 == 0, 보통 == 1, 학점느님 ==2) + val homework: Int = 1, // 과제양 (없음 ==0, 보통 == 1, 많음 == 2) val content: String = "", ) diff --git a/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/datasource/RemoteLectureEditorDataSource.kt b/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/datasource/RemoteLectureEditorDataSource.kt index ed141936b..b06724179 100644 --- a/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/datasource/RemoteLectureEditorDataSource.kt +++ b/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/datasource/RemoteLectureEditorDataSource.kt @@ -3,6 +3,7 @@ package com.suwiki.data.lectureevaluation.editor.datasource interface RemoteLectureEditorDataSource { suspend fun postLectureEvaluation( + lectureId: Long, lectureName: String, professor: String, selectedSemester: String, diff --git a/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/repository/LectureEditorRepositoryImpl.kt b/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/repository/LectureEditorRepositoryImpl.kt index 5dee060d8..ddb771e33 100644 --- a/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/repository/LectureEditorRepositoryImpl.kt +++ b/data/lectureevaluation/editor/src/main/java/com/suwiki/data/lectureevaluation/editor/repository/LectureEditorRepositoryImpl.kt @@ -8,6 +8,7 @@ class LectureEditorRepositoryImpl @Inject constructor( private val lectureEditorDataSource: RemoteLectureEditorDataSource, ) : LectureEditorRepository { override suspend fun postLectureEvaluation( + lectureId: Long, lectureName: String, professor: String, selectedSemester: String, @@ -20,6 +21,7 @@ class LectureEditorRepositoryImpl @Inject constructor( content: String, ) { lectureEditorDataSource.postLectureEvaluation( + lectureId = lectureId, lectureName = lectureName, professor = professor, selectedSemester = selectedSemester, diff --git a/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSource.kt b/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSource.kt index 017a5b5ae..3e2c3a4ec 100644 --- a/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSource.kt +++ b/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSource.kt @@ -3,7 +3,7 @@ package com.suwiki.data.lectureevaluation.viewerreporter.datasource interface RemoteExamReportDataSource { suspend fun reportExam( - evaluateIdx: Long, + examIdx: Long, content: String = "", ) } diff --git a/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/repository/ExamReportRepositoryImpl.kt b/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/repository/ExamReportRepositoryImpl.kt index 947b03b43..6d73a0584 100644 --- a/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/repository/ExamReportRepositoryImpl.kt +++ b/data/lectureevaluation/viewerreporter/src/main/java/com/suwiki/data/lectureevaluation/viewerreporter/repository/ExamReportRepositoryImpl.kt @@ -8,9 +8,9 @@ class ExamReportRepositoryImpl @Inject constructor( private val remoteExamReportDataSource: RemoteExamReportDataSource, ) : ExamReportRepository { - override suspend fun reportExam(evaluateIdx: Long, content: String) { + override suspend fun reportExam(examIdx: Long, content: String) { remoteExamReportDataSource.reportExam( - evaluateIdx = evaluateIdx, + examIdx = examIdx, content = content, ) } diff --git a/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/repository/LectureEditorRepository.kt b/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/repository/LectureEditorRepository.kt index 3deff18a2..1b13fc39a 100644 --- a/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/repository/LectureEditorRepository.kt +++ b/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/repository/LectureEditorRepository.kt @@ -3,6 +3,7 @@ package com.suwiki.domain.lectureevaluation.editor.repository interface LectureEditorRepository { suspend fun postLectureEvaluation( + lectureId: Long, lectureName: String, professor: String, selectedSemester: String, diff --git a/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/PostLectureEvaluationUseCase.kt b/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/PostLectureEvaluationUseCase.kt index 2e1a37685..d04fb7d50 100644 --- a/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/PostLectureEvaluationUseCase.kt +++ b/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/PostLectureEvaluationUseCase.kt @@ -10,6 +10,7 @@ class PostLectureEvaluationUseCase @Inject constructor( suspend operator fun invoke(param: Param): Result = runCatchingIgnoreCancelled { param.run { lectureEditorRepository.postLectureEvaluation( + lectureId = id, lectureName = lectureName, professor = professor, selectedSemester = selectedSemester, @@ -25,6 +26,7 @@ class PostLectureEvaluationUseCase @Inject constructor( } data class Param( + val id: Long, val lectureName: String, val professor: String, val selectedSemester: String, diff --git a/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/UpdateLectureEvaluationUseCase.kt b/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/UpdateLectureEvaluationUseCase.kt index 4aa2bd4b5..c3034a33f 100644 --- a/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/UpdateLectureEvaluationUseCase.kt +++ b/domain/lectureevaluation/editor/src/main/java/com/suwiki/domain/lectureevaluation/editor/usecase/lecture/UpdateLectureEvaluationUseCase.kt @@ -25,7 +25,6 @@ class UpdateLectureEvaluationUseCase @Inject constructor( data class Param( val lectureId: Long, - val professor: String, val selectedSemester: String, val satisfaction: Float, val learning: Float, diff --git a/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/repository/ExamReportRepository.kt b/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/repository/ExamReportRepository.kt index 6334aca64..b0de432e8 100644 --- a/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/repository/ExamReportRepository.kt +++ b/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/repository/ExamReportRepository.kt @@ -3,7 +3,7 @@ package com.suwiki.domain.lectureevaluation.viewerreporter.repository interface ExamReportRepository { suspend fun reportExam( - evaluateIdx: Long, + examIdx: Long, content: String = "", ) } diff --git a/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/usecase/exam/ReportExamUseCase.kt b/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/usecase/exam/ReportExamUseCase.kt index 7ea9814a1..1622b5bca 100644 --- a/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/usecase/exam/ReportExamUseCase.kt +++ b/domain/lectureevaluation/viewerreporter/src/main/java/com/suwiki/domain/lectureevaluation/viewerreporter/usecase/exam/ReportExamUseCase.kt @@ -7,7 +7,7 @@ import javax.inject.Inject class ReportExamUseCase @Inject constructor( private val examReportRepository: ExamReportRepository, ) { - suspend operator fun invoke(evaluateIdx: Long): Result = runCatchingIgnoreCancelled { - examReportRepository.reportExam(evaluateIdx = evaluateIdx) + suspend operator fun invoke(examIdx: Long): Result = runCatchingIgnoreCancelled { + examReportRepository.reportExam(examIdx = examIdx) } } diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvaluationEditViewModel.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvaluationEditorViewModel.kt similarity index 64% rename from feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvaluationEditViewModel.kt rename to feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvaluationEditorViewModel.kt index 9171cf062..b7c381257 100644 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvaluationEditViewModel.kt +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvaluationEditorViewModel.kt @@ -7,8 +7,9 @@ import com.suwiki.core.model.enums.ExamLevel import com.suwiki.core.model.enums.ExamType import com.suwiki.core.model.lectureevaluation.exam.MyExamEvaluation import com.suwiki.core.ui.extension.decodeFromUri +import com.suwiki.domain.lectureevaluation.editor.usecase.exam.PostExamEvaluationUseCase import com.suwiki.domain.lectureevaluation.editor.usecase.exam.UpdateExamEvaluationUseCase -import com.suwiki.feature.lectureevaluation.editor.navigation.MyEvaluationEditRoute +import com.suwiki.feature.lectureevaluation.editor.navigation.EvaluationEditorRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.serialization.json.Json @@ -23,15 +24,17 @@ import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject @HiltViewModel -class MyExamEvaluationEditViewModel @Inject constructor( +class ExamEvaluationEditorViewModel @Inject constructor( savedStateHandle: SavedStateHandle, + val postExamEvaluationUseCase: PostExamEvaluationUseCase, val updateExamEvaluationUseCase: UpdateExamEvaluationUseCase, -) : ContainerHost, ViewModel() { - override val container: Container = - container(MyExamEvaluationEditState()) +) : ContainerHost, ViewModel() { + override val container: Container = + container(ExamEvaluationEditorState()) - private val myExamEvaluation = savedStateHandle.get(MyEvaluationEditRoute.myExamEvaluation)!! + private val myExamEvaluation = savedStateHandle.get(EvaluationEditorRoute.examEvaluation)!! private val myExamEvaluationItem: MyExamEvaluation = Json.decodeFromUri(myExamEvaluation) + private val isEditMode = myExamEvaluationItem.content.isNotEmpty() suspend fun initData() = intent { showLoadingScreen() @@ -60,7 +63,52 @@ class MyExamEvaluationEditViewModel @Inject constructor( } hideLoadingScreen() } - fun updateExamEvaluation() = intent { + + fun postOrUpdateExamEvaluation() = intent { + if (state.examEvaluation.length < 30) { + postSideEffect(ExamEvaluationEditorSideEffect.ShowInputMoreTextToast) + return@intent + } + + if (state.selectedSemester.isNullOrEmpty()) { + postSideEffect(ExamEvaluationEditorSideEffect.ShowSelectSemesterToast) + return@intent + } + + if (state.selectedExamType.isNullOrEmpty()) { + postSideEffect(ExamEvaluationEditorSideEffect.ShowSelectExamTypeToast) + return@intent + } + + if (isEditMode) { + updateExamEvaluation() + } else { + postExamEvaluation() + } + } + + private fun postExamEvaluation() = intent { + postExamEvaluationUseCase( + PostExamEvaluationUseCase.Param( + lectureId = myExamEvaluationItem.id, + lectureName = myExamEvaluationItem.lectureName, + professor = myExamEvaluationItem.professor, + selectedSemester = state.selectedSemester, + examInfo = state.examInfo.filter { it.isNotBlank() }.joinToString(", "), + examType = state.selectedExamType, + examDifficulty = state.examLevel!!.value, + content = state.examEvaluation, + ), + ) + .onSuccess { + popBackStack() + } + .onFailure { + postSideEffect(ExamEvaluationEditorSideEffect.HandleException(it)) + } + } + + private fun updateExamEvaluation() = intent { updateExamEvaluationUseCase( UpdateExamEvaluationUseCase.Param( lectureId = myExamEvaluationItem.id, @@ -75,7 +123,7 @@ class MyExamEvaluationEditViewModel @Inject constructor( popBackStack() } .onFailure { - postSideEffect(MyExamEvaluationEditSideEffect.HandleException(it)) + postSideEffect(ExamEvaluationEditorSideEffect.HandleException(it)) } } @@ -120,5 +168,5 @@ class MyExamEvaluationEditViewModel @Inject constructor( fun showExamTypeBottomSheet() = intent { reduce { state.copy(showExamTypeBottomSheet = true) } } fun hideExamTypeBottomSheet() = intent { reduce { state.copy(showExamTypeBottomSheet = false) } } - fun popBackStack() = intent { postSideEffect(MyExamEvaluationEditSideEffect.PopBackStack) } + fun popBackStack() = intent { postSideEffect(ExamEvaluationEditorSideEffect.PopBackStack) } } diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvalutionEditContract.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvalutionEditorContract.kt similarity index 53% rename from feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvalutionEditContract.kt rename to feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvalutionEditorContract.kt index e21557a04..50510f996 100644 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvalutionEditContract.kt +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvalutionEditorContract.kt @@ -4,7 +4,7 @@ import com.suwiki.core.model.enums.ExamLevel import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf -data class MyExamEvaluationEditState( +data class ExamEvaluationEditorState( val isLoading: Boolean = false, val point: Int = 0, val semesterList: PersistentList = persistentListOf(""), @@ -17,10 +17,17 @@ data class MyExamEvaluationEditState( val examInfo: PersistentList = persistentListOf(), val showSemesterBottomSheet: Boolean = false, val showExamTypeBottomSheet: Boolean = false, -) +) { + val buttonEnabled = examLevel != null && + examInfo.isNotEmpty() && + examEvaluation.isNotEmpty() +} -sealed interface MyExamEvaluationEditSideEffect { - data object PopBackStack : MyExamEvaluationEditSideEffect - data object ShowMyExamEvaluationDeleteToast : MyExamEvaluationEditSideEffect - data class HandleException(val throwable: Throwable) : MyExamEvaluationEditSideEffect +sealed interface ExamEvaluationEditorSideEffect { + data object ShowInputMoreTextToast : ExamEvaluationEditorSideEffect + data object ShowSelectSemesterToast : ExamEvaluationEditorSideEffect + data object ShowSelectExamTypeToast : ExamEvaluationEditorSideEffect + data object PopBackStack : ExamEvaluationEditorSideEffect + data object ShowExamEvaluationDeleteToast : ExamEvaluationEditorSideEffect + data class HandleException(val throwable: Throwable) : ExamEvaluationEditorSideEffect } diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvalutionEditScreen.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvalutionEditorScreen.kt similarity index 81% rename from feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvalutionEditScreen.kt rename to feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvalutionEditorScreen.kt index 7811ddb76..e51d32eca 100644 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/MyExamEvalutionEditScreen.kt +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/examevaluation/ExamEvalutionEditorScreen.kt @@ -3,6 +3,7 @@ package com.suwiki.feature.lectureevaluation.editor.examevaluation import androidx.compose.foundation.ScrollState 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.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -46,8 +47,8 @@ import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @Composable -fun MyExamEvaluationEditRoute( - viewModel: MyExamEvaluationEditViewModel = hiltViewModel(), +fun ExamEvaluationEditorRoute( + viewModel: ExamEvaluationEditorViewModel = hiltViewModel(), popBackStack: () -> Unit = {}, onShowToast: (String) -> Unit = {}, handleException: (Throwable) -> Unit, @@ -57,12 +58,15 @@ fun MyExamEvaluationEditRoute( val uiState = viewModel.collectAsState().value viewModel.collectSideEffect { sideEffect -> when (sideEffect) { - MyExamEvaluationEditSideEffect.PopBackStack -> popBackStack() - MyExamEvaluationEditSideEffect.ShowMyExamEvaluationDeleteToast -> { + ExamEvaluationEditorSideEffect.PopBackStack -> popBackStack() + ExamEvaluationEditorSideEffect.ShowExamEvaluationDeleteToast -> { onShowToast(context.getString(R.string.exam_evaluation_delete_toast_msg)) } - is MyExamEvaluationEditSideEffect.HandleException -> handleException(sideEffect.throwable) + is ExamEvaluationEditorSideEffect.HandleException -> handleException(sideEffect.throwable) + ExamEvaluationEditorSideEffect.ShowInputMoreTextToast -> onShowToast(context.getString(R.string.toast_need_input_30)) + ExamEvaluationEditorSideEffect.ShowSelectExamTypeToast -> onShowToast(context.getString(R.string.toast_select_exam_type)) + ExamEvaluationEditorSideEffect.ShowSelectSemesterToast -> onShowToast(context.getString(R.string.toast_select_semester)) } } @@ -70,7 +74,7 @@ fun MyExamEvaluationEditRoute( viewModel.initData() } - MyExamEvaluationEditScreen( + ExamEvaluationEditorScreen( scrollState = scrollState, uiState = uiState, popBackStack = viewModel::popBackStack, @@ -83,15 +87,15 @@ fun MyExamEvaluationEditRoute( onClickExamLevelChip = viewModel::updateExamLevel, onClickExamInfoChip = viewModel::updateExamInfo, onExamEvaluationValueChange = viewModel::updateMyExamEvaluationValue, - onClickExamEvaluationReviseButton = viewModel::updateExamEvaluation, + onClickExamEvaluationReviseButton = viewModel::postOrUpdateExamEvaluation, ) } @OptIn(ExperimentalLayoutApi::class) @Composable -fun MyExamEvaluationEditScreen( +fun ExamEvaluationEditorScreen( scrollState: ScrollState, - uiState: MyExamEvaluationEditState, + uiState: ExamEvaluationEditorState, popBackStack: () -> Unit = {}, onClickSemesterButton: () -> Unit = {}, onClickSemesterItem: (Int) -> Unit = {}, @@ -119,18 +123,19 @@ fun MyExamEvaluationEditScreen( Column( modifier = Modifier .weight(1f) - .padding(24.dp) + .padding(horizontal = 24.dp) .verticalScroll(scrollState), ) { Spacer(modifier = Modifier.height(20.dp)) SuwikiSelectionContainer( - title = uiState.selectedSemester ?: stringResource(R.string.word_choose_semester), + title = uiState.selectedSemester?.ifEmpty { stringResource(R.string.word_choose_semester) } ?: stringResource(R.string.word_choose_semester), onClick = onClickSemesterButton, ) Spacer(modifier = Modifier.height(14.dp)) SuwikiSelectionContainer( - title = uiState.selectedExamType ?: stringResource(R.string.word_choose_test_type), + title = uiState.selectedExamType?.ifEmpty { stringResource(R.string.word_choose_test_type) } + ?: stringResource(R.string.word_choose_test_type), onClick = onClickExamTypeButton, ) @@ -183,15 +188,19 @@ fun MyExamEvaluationEditScreen( ) } - SuwikiContainedMediumButton( - modifier = Modifier - .padding(24.dp) - .fillMaxWidth() - .height(50.dp) - .imePadding(), - text = stringResource(R.string.text_complete), - onClick = onClickExamEvaluationReviseButton, - ) + Box(modifier = Modifier.imePadding()) { + SuwikiContainedMediumButton( + modifier = Modifier + .padding(24.dp) + .fillMaxWidth() + .height(50.dp) + .imePadding(), + text = stringResource(R.string.text_complete), + enabled = uiState.buttonEnabled, + clickable = uiState.buttonEnabled, + onClick = onClickExamEvaluationReviseButton, + ) + } } SuwikiSelectBottomSheet( @@ -199,7 +208,7 @@ fun MyExamEvaluationEditScreen( onDismissRequest = onExamTypeBottomSheetDismissRequest, onClickItem = { onClickExamTypeItem(it) }, itemList = ExamType.entries.map { it.value }.toPersistentList(), - title = stringResource(R.string.word_choose_semester), + title = stringResource(R.string.word_choose_test_type), selectedPosition = uiState.selectedExamTypePosition, ) @@ -208,7 +217,7 @@ fun MyExamEvaluationEditScreen( onDismissRequest = onSemesterBottomSheetDismissRequest, onClickItem = { onClickSemesterItem(it) }, itemList = uiState.semesterList, - title = stringResource(R.string.word_choose_test_type), + title = stringResource(R.string.word_choose_semester), selectedPosition = uiState.selectedSemesterPosition, ) @@ -239,13 +248,13 @@ fun LectureExamEditContainer( @Preview @Composable -fun MyExamEvaluationEditScreenPreview() { +fun ExamEvaluationEditorScreenPreview() { val scrollState = rememberScrollState() SuwikiTheme { - MyExamEvaluationEditScreen( + ExamEvaluationEditorScreen( scrollState = scrollState, - uiState = MyExamEvaluationEditState(), + uiState = ExamEvaluationEditorState(), ) } } diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditContract.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorContract.kt similarity index 57% rename from feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditContract.kt rename to feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorContract.kt index 400fe8127..8aceb93b6 100644 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditContract.kt +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorContract.kt @@ -6,9 +6,8 @@ import com.suwiki.core.model.enums.TeamLevel import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf -data class MyLectureEvaluationEditState( +data class LectureEvaluationEditorState( val isLoading: Boolean = false, - val point: Int = 0, val semesterList: PersistentList = persistentListOf(""), val selectedSemester: String = "", val selectedSemesterPosition: Int? = null, @@ -21,10 +20,17 @@ data class MyLectureEvaluationEditState( val teamLevel: TeamLevel? = null, val lectureEvaluation: String = "", val showSemesterBottomSheet: Boolean = false, -) +) { + val buttonEnabled = gradeLevel != null && + homeworkLevel != null && + teamLevel != null && + lectureEvaluation.isNotEmpty() +} -sealed interface MyLectureEvaluationEditSideEffect { - data object PopBackStack : MyLectureEvaluationEditSideEffect - data object ShowMyLectureEvaluationDeleteToast : MyLectureEvaluationEditSideEffect - data class HandleException(val throwable: Throwable) : MyLectureEvaluationEditSideEffect +sealed interface LectureEvaluationEditorSideEffect { + data object ShowInputMoreTextToast : LectureEvaluationEditorSideEffect + data object ShowSelectSemesterToast : LectureEvaluationEditorSideEffect + data object PopBackStack : LectureEvaluationEditorSideEffect + data object ShowLectureEvaluationDeleteToast : LectureEvaluationEditorSideEffect + data class HandleException(val throwable: Throwable) : LectureEvaluationEditorSideEffect } diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditScreen.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorScreen.kt similarity index 87% rename from feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditScreen.kt rename to feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorScreen.kt index 782ea7d14..4ac81a36a 100644 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditScreen.kt +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorScreen.kt @@ -3,6 +3,7 @@ package com.suwiki.feature.lectureevaluation.editor.lectureevaluation import androidx.compose.foundation.ScrollState 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.RowScope @@ -50,8 +51,8 @@ import org.orbitmvi.orbit.compose.collectSideEffect import java.util.Locale @Composable -fun MyLectureEvaluationEditRoute( - viewModel: MyLectureEvaluationEditViewModel = hiltViewModel(), +fun LectureEvaluationEditorRoute( + viewModel: LectureEvaluationEditorViewModel = hiltViewModel(), popBackStack: () -> Unit = {}, onShowToast: (String) -> Unit = {}, handleException: (Throwable) -> Unit, @@ -61,11 +62,13 @@ fun MyLectureEvaluationEditRoute( val uiState = viewModel.collectAsState().value viewModel.collectSideEffect { sideEffect -> when (sideEffect) { - MyLectureEvaluationEditSideEffect.PopBackStack -> popBackStack() - MyLectureEvaluationEditSideEffect.ShowMyLectureEvaluationDeleteToast -> { + LectureEvaluationEditorSideEffect.PopBackStack -> popBackStack() + LectureEvaluationEditorSideEffect.ShowLectureEvaluationDeleteToast -> { onShowToast(context.getString(R.string.lecture_evaluation_delete_toast_msg)) } - is MyLectureEvaluationEditSideEffect.HandleException -> handleException(sideEffect.throwable) + is LectureEvaluationEditorSideEffect.HandleException -> handleException(sideEffect.throwable) + LectureEvaluationEditorSideEffect.ShowInputMoreTextToast -> onShowToast(context.getString(R.string.toast_need_input_30)) + LectureEvaluationEditorSideEffect.ShowSelectSemesterToast -> onShowToast(context.getString(R.string.toast_select_semester)) } } @@ -81,7 +84,7 @@ fun MyLectureEvaluationEditRoute( viewModel.updateTotalAvg() } - MyLectureEvaluationEditScreen( + LectureEvaluationEditorScreen( uiState = uiState, scrollState = scrollState, popBackStack = viewModel::popBackStack, @@ -95,13 +98,13 @@ fun MyLectureEvaluationEditRoute( onClickGradeChip = viewModel::updateGradeLevel, onClickHomeworkChip = viewModel::updateHomeworkLevel, onClickTeamChip = viewModel::updateTeamLevel, - onClickLectureEvaluationReviseButton = viewModel::updateLectureEvaluation, + onClickLectureEvaluationReviseButton = viewModel::postOrUpdateLectureEvaluation, ) } @Composable -fun MyLectureEvaluationEditScreen( - uiState: MyLectureEvaluationEditState, +fun LectureEvaluationEditorScreen( + uiState: LectureEvaluationEditorState, scrollState: ScrollState, popBackStack: () -> Unit, onClickSemesterButton: () -> Unit = {}, @@ -131,7 +134,7 @@ fun MyLectureEvaluationEditScreen( Column( modifier = Modifier .weight(1f) - .padding(24.dp) + .padding(horizontal = 24.dp) .verticalScroll(scrollState), ) { Spacer(modifier = Modifier.height(20.dp)) @@ -142,7 +145,7 @@ fun MyLectureEvaluationEditScreen( .fillMaxWidth(), ) { SuwikiSelectionContainer( - title = uiState.selectedSemester, + title = uiState.selectedSemester.ifEmpty { stringResource(id = R.string.word_choose_semester) }, onClick = onClickSemesterButton, ) @@ -267,15 +270,19 @@ fun MyLectureEvaluationEditScreen( ) } - SuwikiContainedMediumButton( - modifier = Modifier - .padding(24.dp) - .fillMaxWidth() - .height(50.dp) - .imePadding(), - text = stringResource(R.string.text_complete), - onClick = onClickLectureEvaluationReviseButton, - ) + Box(modifier = Modifier.imePadding()) { + SuwikiContainedMediumButton( + modifier = Modifier + .padding(24.dp) + .fillMaxWidth() + .height(50.dp) + .imePadding(), + text = stringResource(R.string.text_complete), + enabled = uiState.buttonEnabled, + clickable = uiState.buttonEnabled, + onClick = onClickLectureEvaluationReviseButton, + ) + } } SuwikiSelectBottomSheet( @@ -314,12 +321,12 @@ fun LectureEvaluationEditContainer( @Preview @Composable -fun MyLectureEvaluationEditPreview() { +fun LectureEvaluationEditorPreview() { SuwikiTheme { val scrollState = rememberScrollState() - MyLectureEvaluationEditScreen( - uiState = MyLectureEvaluationEditState(), + LectureEvaluationEditorScreen( + uiState = LectureEvaluationEditorState(), scrollState = scrollState, popBackStack = {}, ) diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditViewModel.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorViewModel.kt similarity index 68% rename from feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditViewModel.kt rename to feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorViewModel.kt index 86097bef6..8f6669155 100644 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/MyLectureEvaluationEditViewModel.kt +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/lectureevaluation/LectureEvaluationEditorViewModel.kt @@ -6,11 +6,10 @@ import com.suwiki.core.model.enums.GradeLevel import com.suwiki.core.model.enums.HomeworkLevel import com.suwiki.core.model.enums.TeamLevel import com.suwiki.core.model.lectureevaluation.lecture.MyLectureEvaluation -import com.suwiki.core.model.user.User import com.suwiki.core.ui.extension.decodeFromUri +import com.suwiki.domain.lectureevaluation.editor.usecase.lecture.PostLectureEvaluationUseCase import com.suwiki.domain.lectureevaluation.editor.usecase.lecture.UpdateLectureEvaluationUseCase -import com.suwiki.domain.user.usecase.GetUserInfoUseCase -import com.suwiki.feature.lectureevaluation.editor.navigation.MyEvaluationEditRoute +import com.suwiki.feature.lectureevaluation.editor.navigation.EvaluationEditorRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.serialization.json.Json @@ -25,24 +24,21 @@ import org.orbitmvi.orbit.viewmodel.container import javax.inject.Inject @HiltViewModel -class MyLectureEvaluationEditViewModel @Inject constructor( +class LectureEvaluationEditorViewModel @Inject constructor( savedStateHandle: SavedStateHandle, - val getUserInfoUseCase: GetUserInfoUseCase, + val postLectureEvaluationUseCase: PostLectureEvaluationUseCase, val updateLectureEvaluationUseCase: UpdateLectureEvaluationUseCase, -) : ContainerHost, ViewModel() { - override val container: Container = - container(MyLectureEvaluationEditState()) +) : ContainerHost, ViewModel() { + override val container: Container = + container(LectureEvaluationEditorState()) - private val myLectureEvaluation = savedStateHandle.get(MyEvaluationEditRoute.myLectureEvaluation)!! + private val myLectureEvaluation = savedStateHandle.get(EvaluationEditorRoute.lectureEvaluation)!! private val myLectureEvaluationItem: MyLectureEvaluation = Json.decodeFromUri(myLectureEvaluation) + private val isEditMode = myLectureEvaluationItem.content.isNotEmpty() suspend fun initData() = intent { showLoadingScreen() with(myLectureEvaluationItem) { - getUserInfoUseCase().collect(::getPoint).runCatching {} - .onFailure { - postSideEffect(MyLectureEvaluationEditSideEffect.HandleException(it)) - } reduce { state.copy( selectedSemester = selectedSemester, @@ -73,13 +69,52 @@ class MyLectureEvaluationEditViewModel @Inject constructor( hideLoadingScreen() } - private fun getPoint(user: User) = intent { reduce { state.copy(point = user.point) } } + fun postOrUpdateLectureEvaluation() = intent { + if (state.lectureEvaluation.length < 30) { + postSideEffect(LectureEvaluationEditorSideEffect.ShowInputMoreTextToast) + return@intent + } + + if (state.selectedSemester.isEmpty()) { + postSideEffect(LectureEvaluationEditorSideEffect.ShowSelectSemesterToast) + return@intent + } + + if (isEditMode) { + updateLectureEvaluation() + } else { + postLectureEvaluation() + } + } + + private fun postLectureEvaluation() = intent { + postLectureEvaluationUseCase( + PostLectureEvaluationUseCase.Param( + id = myLectureEvaluationItem.id, + lectureName = myLectureEvaluationItem.lectureInfo.lectureName, + professor = myLectureEvaluationItem.lectureInfo.professor, + selectedSemester = state.selectedSemester, + satisfaction = "%.1f".format(state.satisfactionRating).toFloat(), + learning = "%.1f".format(state.learningRating).toFloat(), + honey = "%.1f".format(state.honeyRating).toFloat(), + team = state.teamLevel!!.value, + difficulty = state.gradeLevel!!.value, + homework = state.homeworkLevel!!.value, + content = state.lectureEvaluation, + ), + ) + .onSuccess { + popBackStack() + } + .onFailure { + postSideEffect(LectureEvaluationEditorSideEffect.HandleException(it)) + } + } - fun updateLectureEvaluation() = intent { + private fun updateLectureEvaluation() = intent { updateLectureEvaluationUseCase( UpdateLectureEvaluationUseCase.Param( lectureId = myLectureEvaluationItem.id, - professor = myLectureEvaluationItem.lectureInfo.professor, selectedSemester = state.selectedSemester, satisfaction = "%.1f".format(state.satisfactionRating).toFloat(), learning = "%.1f".format(state.learningRating).toFloat(), @@ -94,7 +129,7 @@ class MyLectureEvaluationEditViewModel @Inject constructor( popBackStack() } .onFailure { - postSideEffect(MyLectureEvaluationEditSideEffect.HandleException(it)) + postSideEffect(LectureEvaluationEditorSideEffect.HandleException(it)) } } @@ -138,5 +173,5 @@ class MyLectureEvaluationEditViewModel @Inject constructor( fun showSemesterBottomSheet() = intent { reduce { state.copy(showSemesterBottomSheet = true) } } fun hideSemesterBottomSheet() = intent { reduce { state.copy(showSemesterBottomSheet = false) } } - fun popBackStack() = intent { postSideEffect(MyLectureEvaluationEditSideEffect.PopBackStack) } + fun popBackStack() = intent { postSideEffect(LectureEvaluationEditorSideEffect.PopBackStack) } } diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/navigation/EvaluationEditorNavigation.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/navigation/EvaluationEditorNavigation.kt new file mode 100644 index 000000000..20a9bf167 --- /dev/null +++ b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/navigation/EvaluationEditorNavigation.kt @@ -0,0 +1,61 @@ +package com.suwiki.feature.lectureevaluation.editor.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import com.suwiki.feature.lectureevaluation.editor.examevaluation.ExamEvaluationEditorRoute +import com.suwiki.feature.lectureevaluation.editor.lectureevaluation.LectureEvaluationEditorRoute + +// TODO 리팩토링 +fun NavController.navigateLectureEvaluationEditor(lectureEvaluation: String) { + navigate(EvaluationEditorRoute.lectureEvaluationEditorRoute(lectureEvaluation)) +} + +// TODO 리팩토링 +fun NavController.navigateExamEvaluationEditor(examEvaluation: String) { + navigate(EvaluationEditorRoute.examEvaluationEditorRoute(examEvaluation)) +} + +fun NavGraphBuilder.myEvaluationEditNavGraph( + popBackStack: () -> Unit = {}, + onShowToast: (String) -> Unit = {}, + handleException: (Throwable) -> Unit, +) { + composable( + route = EvaluationEditorRoute.lectureEvaluationEditorRoute("{${EvaluationEditorRoute.lectureEvaluation}}"), + arguments = listOf( + navArgument(EvaluationEditorRoute.lectureEvaluation) { + type = NavType.StringType + }, + ), + ) { + LectureEvaluationEditorRoute( + popBackStack = popBackStack, + onShowToast = onShowToast, + handleException = handleException, + ) + } + composable( + route = EvaluationEditorRoute.examEvaluationEditorRoute("{${EvaluationEditorRoute.examEvaluation}}"), + arguments = listOf( + navArgument(EvaluationEditorRoute.examEvaluation) { + type = NavType.StringType + }, + ), + ) { + ExamEvaluationEditorRoute( + popBackStack = popBackStack, + onShowToast = onShowToast, + handleException = handleException, + ) + } +} + +object EvaluationEditorRoute { + const val lectureEvaluation = "lecture-evaluation" + const val examEvaluation = "exam-evaluation" + fun lectureEvaluationEditorRoute(lectureEvaluation: String) = "lecture-evaluation-editor/$lectureEvaluation" + fun examEvaluationEditorRoute(examEvaluation: String) = "exam-evaluation-editor/$examEvaluation" +} diff --git a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/navigation/MyEvaluationEditNavigation.kt b/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/navigation/MyEvaluationEditNavigation.kt deleted file mode 100644 index 8cb9a86be..000000000 --- a/feature/lectureevaluation/editor/src/main/java/com/suwiki/feature/lectureevaluation/editor/navigation/MyEvaluationEditNavigation.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.suwiki.feature.lectureevaluation.editor.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavType -import androidx.navigation.compose.composable -import androidx.navigation.navArgument -import com.suwiki.feature.lectureevaluation.editor.examevaluation.MyExamEvaluationEditRoute -import com.suwiki.feature.lectureevaluation.editor.lectureevaluation.MyLectureEvaluationEditRoute - -// TODO 리팩토링 -fun NavController.navigateMyLectureEvaluation(lectureEvaluation: String) { - navigate(MyEvaluationEditRoute.myLectureEvaluationEditRoute(lectureEvaluation)) -} - -// TODO 리팩토링 -fun NavController.navigateMyExamEvaluation(examEvaluation: String) { - navigate(MyEvaluationEditRoute.myExamEvaluationEditRoute(examEvaluation)) -} - -fun NavGraphBuilder.myEvaluationEditNavGraph( - popBackStack: () -> Unit = {}, - onShowToast: (String) -> Unit = {}, - handleException: (Throwable) -> Unit, -) { - composable( - route = MyEvaluationEditRoute.myLectureEvaluationEditRoute("{${MyEvaluationEditRoute.myLectureEvaluation}}"), - arguments = listOf( - navArgument(MyEvaluationEditRoute.myLectureEvaluation) { - type = NavType.StringType - }, - ), - ) { - MyLectureEvaluationEditRoute( - popBackStack = popBackStack, - onShowToast = onShowToast, - handleException = handleException, - ) - } - composable( - route = MyEvaluationEditRoute.myExamEvaluationEditRoute("{${MyEvaluationEditRoute.myExamEvaluation}}"), - arguments = listOf( - navArgument(MyEvaluationEditRoute.myExamEvaluation) { - type = NavType.StringType - }, - ), - ) { - MyExamEvaluationEditRoute( - popBackStack = popBackStack, - onShowToast = onShowToast, - handleException = handleException, - ) - } -} - -object MyEvaluationEditRoute { - const val myLectureEvaluation = "lecture-evaluation" - const val myExamEvaluation = "exam-evaluation" - fun myLectureEvaluationEditRoute(lectureEvaluation: String) = "my-lecture-evaluation-edit/$lectureEvaluation" - fun myExamEvaluationEditRoute(examEvaluation: String) = "my-exam-evaluation-edit/$examEvaluation" -} diff --git a/feature/lectureevaluation/editor/src/main/res/values/strings.xml b/feature/lectureevaluation/editor/src/main/res/values/strings.xml index 28ae09297..01c0c2098 100644 --- a/feature/lectureevaluation/editor/src/main/res/values/strings.xml +++ b/feature/lectureevaluation/editor/src/main/res/values/strings.xml @@ -22,4 +22,7 @@ 시험정보를 입력해주세요. 시험정보가 수정되었습니다. 시험정보가 삭제되었습니다. + 30자 이상 작성해주세요 + 수강학기를 선택해주세요 + 시험종류을 선택해주세요 diff --git a/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/MyEvaluationViewModel.kt b/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/MyEvaluationViewModel.kt index 204793857..0828199c5 100644 --- a/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/MyEvaluationViewModel.kt +++ b/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/MyEvaluationViewModel.kt @@ -15,6 +15,8 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.joinAll +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.syntax.simple.intent @@ -41,52 +43,58 @@ class MyEvaluationViewModel @Inject constructor( private var toDeleteExamId: Long = 0 private var toDeleteLectureId: Long = 0 + private val mutex: Mutex = Mutex() + fun getMyLectureEvaluations(needClear: Boolean = false) = intent { - val currentList = if (needClear) { - lectureEvaluationPage = 1 - isLastLectureEvaluation = false - persistentListOf() - } else { - state.myLectureEvaluationList - } + mutex.withLock { + val currentList = if (needClear) { + lectureEvaluationPage = 1 + isLastLectureEvaluation = false + persistentListOf() + } else { + state.myLectureEvaluationList + } - if (isLastLectureEvaluation) return@intent + if (isLastLectureEvaluation) return@intent - getMyLectureEvaluationListUseCase(lectureEvaluationPage) - .onSuccess { - reduce { - lectureEvaluationPage++ - isLastLectureEvaluation = it.isEmpty() - state.copy(myLectureEvaluationList = currentList.addAll(it).distinctBy { it.id }.toPersistentList()) + getMyLectureEvaluationListUseCase(lectureEvaluationPage) + .onSuccess { + reduce { + lectureEvaluationPage++ + isLastLectureEvaluation = it.isEmpty() + state.copy(myLectureEvaluationList = currentList.addAll(it).distinctBy { it.id }.toPersistentList()) + } } - } - .onFailure { - postSideEffect(MyEvaluationSideEffect.HandleException(it)) - } + .onFailure { + postSideEffect(MyEvaluationSideEffect.HandleException(it)) + } + } } fun getMyExamEvaluations(needClear: Boolean = false) = intent { - val currentList = if (needClear) { - examEvaluationPage = 1 - isLastExamEvaluation = false - persistentListOf() - } else { - state.myExamEvaluationList - } + mutex.withLock { + val currentList = if (needClear) { + examEvaluationPage = 1 + isLastExamEvaluation = false + persistentListOf() + } else { + state.myExamEvaluationList + } - if (isLastExamEvaluation) return@intent + if (isLastExamEvaluation) return@intent - getMyExamEvaluationListUseCase(examEvaluationPage) - .onSuccess { - reduce { - examEvaluationPage++ - isLastExamEvaluation = it.isEmpty() - state.copy(myExamEvaluationList = currentList.addAll(it).distinctBy { it.id }.toPersistentList()) + getMyExamEvaluationListUseCase(examEvaluationPage) + .onSuccess { + reduce { + examEvaluationPage++ + isLastExamEvaluation = it.isEmpty() + state.copy(myExamEvaluationList = currentList.addAll(it).distinctBy { it.id }.toPersistentList()) + } } - } - .onFailure { - postSideEffect(MyEvaluationSideEffect.HandleException(it)) - } + .onFailure { + postSideEffect(MyEvaluationSideEffect.HandleException(it)) + } + } } fun initData() = intent { diff --git a/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/navigation/MyEvaluationNavigation.kt b/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/navigation/MyEvaluationNavigation.kt index ca87e2103..6c9d2f02f 100644 --- a/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/navigation/MyEvaluationNavigation.kt +++ b/feature/lectureevaluation/my/src/main/java/com/suwiki/feature/lectureevaluation/my/navigation/MyEvaluationNavigation.kt @@ -11,15 +11,15 @@ fun NavController.navigateMyEvaluation() { fun NavGraphBuilder.myEvaluationNavGraph( popBackStack: () -> Unit = {}, - navigateMyLectureEvaluationEdit: (String) -> Unit = {}, - navigateMyExamEvaluationEdit: (String) -> Unit = {}, + navigateLectureEvaluationEditor: (String) -> Unit = {}, + navigateExamEvaluationEditor: (String) -> Unit = {}, handleException: (Throwable) -> Unit, ) { composable(route = MyEvaluationRoute.route) { navBackStackEntry -> MyEvaluationRoute( popBackStack = popBackStack, - navigateLectureEvaluationEditor = navigateMyLectureEvaluationEdit, - navigateExamEvaluationEditor = navigateMyExamEvaluationEdit, + navigateLectureEvaluationEditor = navigateLectureEvaluationEditor, + navigateExamEvaluationEditor = navigateExamEvaluationEditor, handleException = handleException, ) } diff --git a/feature/lectureevaluation/viewerreporter/build.gradle.kts b/feature/lectureevaluation/viewerreporter/build.gradle.kts index 9695cb297..197c51bdc 100644 --- a/feature/lectureevaluation/viewerreporter/build.gradle.kts +++ b/feature/lectureevaluation/viewerreporter/build.gradle.kts @@ -12,4 +12,5 @@ dependencies { implementation(projects.domain.lectureevaluation.viewerreporter) implementation(libs.compose.toolbar) + implementation(libs.kotlinx.serialization.json) } diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt index 8fdd36fd3..5903f5c03 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt +++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationScreen.kt @@ -117,7 +117,7 @@ fun LectureEvaluationRoute( onClickTermArrowIcon = viewModel::openTermWebSite, onClickPersonalCheckIcon = viewModel::togglePersonalPolicyChecked, onClickPersonalArrowIcon = viewModel::openPersonalPolicyWebSite, - onClickLectureEvaluationItem = viewModel::navigateLectureEvaluationDetail, + onClickLectureEvaluationItem = viewModel::navigateLectureEvaluationDetailIfLoggedIn, onClickAgreementButton = { viewModel.hideAgreementBottomSheet() viewModel.hideOnboardingBottomSheet() diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationViewModel.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationViewModel.kt index d8d0d3261..06b902097 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationViewModel.kt +++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/LectureEvaluationViewModel.kt @@ -139,7 +139,13 @@ class LectureEvaluationViewModel @Inject constructor( fun navigateOpenMajor(selectedOpenMajor: String) = intent { postSideEffect(LectureEvaluationSideEffect.NavigateOpenMajor(selectedOpenMajor)) } fun navigateLogin() = intent { postSideEffect(LectureEvaluationSideEffect.NavigateLogin) } fun navigateSignup() = intent { postSideEffect(LectureEvaluationSideEffect.NavigateSignUp) } - fun navigateLectureEvaluationDetail(id: String) = intent { postSideEffect(LectureEvaluationSideEffect.NavigateLectureEvaluationDetail(id)) } + fun navigateLectureEvaluationDetailIfLoggedIn(id: String) = intent { + if (isLoggedIn.not()) { + postSideEffect(LectureEvaluationSideEffect.NavigateLogin) + } else { + postSideEffect(LectureEvaluationSideEffect.NavigateLectureEvaluationDetail(id)) + } + } private fun showOnboardingBottomSheet() = intent { reduce { state.copy(showOnboardingBottomSheet = true) } } fun hideOnboardingBottomSheet() = intent { reduce { state.copy(showOnboardingBottomSheet = false) } } diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailContract.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailContract.kt index adf69eeed..eb5f4d664 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailContract.kt +++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailContract.kt @@ -15,9 +15,14 @@ data class LectureEvaluationDetailState( val examEvaluationList: PersistentList = persistentListOf(), val needBuyExam: Boolean = false, val isExamEvaluationWritten: Boolean = false, + val showLectureReportDialog: Boolean = false, + val showExamReportDialog: Boolean = false, ) sealed interface LectureEvaluationDetailSideEffect { data class ShowLackPointToast(val msg: String) : LectureEvaluationDetailSideEffect data object PopBackStack : LectureEvaluationDetailSideEffect data class HandleException(val throwable: Throwable) : LectureEvaluationDetailSideEffect + data class NavigateLectureEvaluationEditor(val argument: String) : LectureEvaluationDetailSideEffect + data class NavigateExamEvaluationEditor(val argument: String) : LectureEvaluationDetailSideEffect + data object ShowAlreadyWriteToast : LectureEvaluationDetailSideEffect } diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailScreen.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailScreen.kt index cef775903..184b1311f 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailScreen.kt +++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailScreen.kt @@ -29,6 +29,7 @@ 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.text.style.TextAlign @@ -39,6 +40,7 @@ import com.suwiki.core.designsystem.component.appbar.SuwikiAppBarWithTitle import com.suwiki.core.designsystem.component.button.SuwikiOutlinedButton import com.suwiki.core.designsystem.component.container.SuwikiExamReviewContainer import com.suwiki.core.designsystem.component.container.SuwikiUserReviewContainer +import com.suwiki.core.designsystem.component.dialog.SuwikiDialog import com.suwiki.core.designsystem.component.loading.LoadingScreen import com.suwiki.core.designsystem.component.tabbar.SuwikiTabBar import com.suwiki.core.designsystem.component.tabbar.TabTitle @@ -66,6 +68,8 @@ private val LECTURE_EVALUATION_PAGE_COUNT = LectureEvaluationTab.entries.size fun LectureEvaluationDetailRoute( viewModel: LectureEvaluationDetailViewModel = hiltViewModel(), popBackStack: () -> Unit = {}, + navigateLectureEvaluationEditor: (String) -> Unit = {}, + navigateExamEvaluationEditor: (String) -> Unit = {}, onShowToast: (String) -> Unit, handleException: (Throwable) -> Unit = {}, ) { @@ -74,11 +78,16 @@ fun LectureEvaluationDetailRoute( val lectureEvaluationListState = rememberLazyListState() val examEvaluationListState = rememberLazyListState() + val context = LocalContext.current + viewModel.collectSideEffect { sideEffect -> when (sideEffect) { is LectureEvaluationDetailSideEffect.PopBackStack -> popBackStack() is LectureEvaluationDetailSideEffect.HandleException -> handleException(sideEffect.throwable) is LectureEvaluationDetailSideEffect.ShowLackPointToast -> onShowToast(sideEffect.msg) + is LectureEvaluationDetailSideEffect.NavigateExamEvaluationEditor -> navigateExamEvaluationEditor(sideEffect.argument) + is LectureEvaluationDetailSideEffect.NavigateLectureEvaluationEditor -> navigateLectureEvaluationEditor(sideEffect.argument) + LectureEvaluationDetailSideEffect.ShowAlreadyWriteToast -> onShowToast(context.getString(R.string.toast_already_write)) } } val pagerState = rememberPagerState(pageCount = { LECTURE_EVALUATION_PAGE_COUNT }) @@ -111,6 +120,19 @@ fun LectureEvaluationDetailRoute( onClickBack = viewModel::popBackStack, onClickTab = viewModel::syncPager, onClickBuyExamButton = viewModel::buyExam, + onClickWriteButton = viewModel::navigateEvaluationEditor, + onClickLectureReportButton = viewModel::showLectureReportDialog, + onClickLectureReportConfirm = { + viewModel.hideLectureReportDialog() + viewModel.reportLecture() + }, + onDismissLectureReport = viewModel::hideLectureReportDialog, + onClickExamReportButton = viewModel::showExamReportDialog, + onClickExamReportConfirm = { + viewModel.hideExamReportDialog() + viewModel.reportExam() + }, + onDismissExamReport = viewModel::hideExamReportDialog, ) } @@ -124,6 +146,13 @@ fun LectureEvaluationDetailScreen( onClickBack: () -> Unit = {}, onClickTab: (Int) -> Unit = {}, onClickBuyExamButton: () -> Unit = {}, + onClickWriteButton: () -> Unit = {}, + onClickLectureReportButton: (Long) -> Unit = {}, + onClickLectureReportConfirm: () -> Unit = {}, + onDismissLectureReport: () -> Unit = {}, + onClickExamReportButton: (Long) -> Unit = {}, + onClickExamReportConfirm: () -> Unit = {}, + onDismissExamReport: () -> Unit = {}, ) { val state = rememberCollapsingToolbarScaffoldState() @@ -194,6 +223,7 @@ fun LectureEvaluationDetailScreen( semester = it.selectedSemester, content = it.content, rating = it.totalAvg, + onClickButton = { onClickLectureReportButton(it.id) }, ) } } @@ -240,7 +270,9 @@ fun LectureEvaluationDetailScreen( difficulty = it.examDifficulty, examType = it.examType, content = it.content, - onClickButton = {}, + semester = it.selectedSemester, + examInfo = it.examInfo, + onClickButton = { onClickExamReportButton(it.id) }, ) } } @@ -254,7 +286,7 @@ fun LectureEvaluationDetailScreen( modifier = Modifier .padding(12.dp) .align(Alignment.BottomCenter), - onClick = { /*TODO*/ }, + onClick = onClickWriteButton, ) } } @@ -266,6 +298,30 @@ fun LectureEvaluationDetailScreen( .background(Color.White), ) } + + if (uiState.showLectureReportDialog) { + SuwikiDialog( + headerText = "강의평가 신고", + bodyText = "허위 신고 시 서비스 이용에 제한을 받을 수 있습니다.", + confirmButtonText = "신고", + onDismissRequest = onDismissLectureReport, + onClickConfirm = onClickLectureReportConfirm, + dismissButtonText = "취소", + onClickDismiss = onDismissLectureReport, + ) + } + + if (uiState.showExamReportDialog) { + SuwikiDialog( + headerText = "시험정보 신고", + bodyText = "허위 신고 시 서비스 이용에 제한을 받을 수 있습니다.", + confirmButtonText = "신고", + onDismissRequest = onDismissExamReport, + onClickConfirm = onClickExamReportConfirm, + dismissButtonText = "취소", + onClickDismiss = onDismissExamReport, + ) + } } @Composable diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailViewModel.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailViewModel.kt index cc4710656..9ad345508 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailViewModel.kt +++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/detail/LectureEvaluationDetailViewModel.kt @@ -2,16 +2,23 @@ package com.suwiki.feature.lectureevaluation.viewerreporter.detail import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import com.suwiki.core.model.enums.LectureEvaluationTab import com.suwiki.core.model.exception.UserPointLackException +import com.suwiki.core.model.lectureevaluation.exam.MyExamEvaluation +import com.suwiki.core.model.lectureevaluation.lecture.MyLectureEvaluation +import com.suwiki.core.ui.extension.encodeToUri import com.suwiki.domain.lectureevaluation.viewerreporter.usecase.exam.BuyExamUseCase import com.suwiki.domain.lectureevaluation.viewerreporter.usecase.exam.GetExamEvaluationListUseCase +import com.suwiki.domain.lectureevaluation.viewerreporter.usecase.exam.ReportExamUseCase import com.suwiki.domain.lectureevaluation.viewerreporter.usecase.lecture.GetLectureEvaluationExtraAverageUseCase import com.suwiki.domain.lectureevaluation.viewerreporter.usecase.lecture.GetLectureEvaluationListUseCase +import com.suwiki.domain.lectureevaluation.viewerreporter.usecase.lecture.ReportLectureUseCase import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.LectureEvaluationRoute import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.joinAll +import kotlinx.serialization.json.Json import org.orbitmvi.orbit.Container import org.orbitmvi.orbit.ContainerHost import org.orbitmvi.orbit.syntax.simple.intent @@ -26,6 +33,8 @@ class LectureEvaluationDetailViewModel @Inject constructor( private val getLectureEvaluationExtraAverageUseCase: GetLectureEvaluationExtraAverageUseCase, private val getLectureEvaluationListUseCase: GetLectureEvaluationListUseCase, private val getExamEvaluationListUseCase: GetExamEvaluationListUseCase, + private val reportExamUseCase: ReportExamUseCase, + private val reportLectureUseCase: ReportLectureUseCase, private val buyExamUseCase: BuyExamUseCase, ) : ContainerHost, ViewModel() { override val container: Container = container( @@ -38,6 +47,53 @@ class LectureEvaluationDetailViewModel @Inject constructor( private var examEvaluationPage = 1 private var isLastExamEvaluation = false + private var lectureReportId: Long = 0 + private var examReportId: Long = 0 + + fun showLectureReportDialog(lectureReportId: Long) = intent { + this@LectureEvaluationDetailViewModel.lectureReportId = lectureReportId + reduce { + state.copy( + showLectureReportDialog = true, + ) + } + } + + fun hideLectureReportDialog() = intent { + reduce { + state.copy( + showLectureReportDialog = false, + ) + } + } + + fun showExamReportDialog(examReportId: Long) = intent { + this@LectureEvaluationDetailViewModel.examReportId = examReportId + reduce { + state.copy( + showExamReportDialog = true, + ) + } + } + + fun hideExamReportDialog() = intent { + reduce { + state.copy( + showExamReportDialog = false, + ) + } + } + + fun reportLecture() = intent { + reportLectureUseCase(lectureReportId) + .onFailure { postSideEffect(LectureEvaluationDetailSideEffect.HandleException(it)) } + } + + fun reportExam() = intent { + reportExamUseCase(examReportId) + .onFailure { postSideEffect(LectureEvaluationDetailSideEffect.HandleException(it)) } + } + fun syncPager(currentPage: Int) = intent { reduce { state.copy(currentTabPage = currentPage) } } fun initData() = intent { @@ -136,5 +192,44 @@ class LectureEvaluationDetailViewModel @Inject constructor( } } + fun navigateEvaluationEditor() = intent { + if (state.currentTabPage == LectureEvaluationTab.LECTURE_EVALUATION.position) { + if (state.isLectureEvaluationWritten) { + postSideEffect(LectureEvaluationDetailSideEffect.ShowAlreadyWriteToast) + return@intent + } + + postSideEffect( + LectureEvaluationDetailSideEffect.NavigateLectureEvaluationEditor( + Json.encodeToUri( + MyLectureEvaluation( + id = evaluationId, + lectureInfo = state.lectureEvaluationExtraAverage.info, + ), + ), + ), + ) + } else { + if (state.isExamEvaluationWritten) { + postSideEffect(LectureEvaluationDetailSideEffect.ShowAlreadyWriteToast) + return@intent + } + + postSideEffect( + LectureEvaluationDetailSideEffect.NavigateExamEvaluationEditor( + Json.encodeToUri( + MyExamEvaluation( + id = evaluationId, + lectureName = state.lectureEvaluationExtraAverage.info.lectureName, + professor = state.lectureEvaluationExtraAverage.info.professor, + majorType = state.lectureEvaluationExtraAverage.info.majorType, + semesterList = state.lectureEvaluationExtraAverage.info.semesterList, + ), + ), + ), + ) + } + } + fun popBackStack() = intent { postSideEffect(LectureEvaluationDetailSideEffect.PopBackStack) } } diff --git a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt index 50aff2c50..095a9feac 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt +++ b/feature/lectureevaluation/viewerreporter/src/main/java/com/suwiki/feature/lectureevaluation/viewerreporter/navigation/LectureEvaluationNavigation.kt @@ -26,6 +26,8 @@ fun NavGraphBuilder.lectureEvaluationNavGraph( navigateSignUp: () -> Unit, navigateOpenMajor: (String) -> Unit, navigateLectureEvaluationDetail: (String) -> Unit, + navigateLectureEvaluationEditor: (String) -> Unit, + navigateExamEvaluationEditor: (String) -> Unit, onShowToast: (String) -> Unit, handleException: (Throwable) -> Unit, ) { @@ -51,6 +53,8 @@ fun NavGraphBuilder.lectureEvaluationNavGraph( ), ) { LectureEvaluationDetailRoute( + navigateLectureEvaluationEditor = navigateLectureEvaluationEditor, + navigateExamEvaluationEditor = navigateExamEvaluationEditor, popBackStack = popBackStack, onShowToast = onShowToast, handleException = handleException, diff --git a/feature/lectureevaluation/viewerreporter/src/main/res/values/strings.xml b/feature/lectureevaluation/viewerreporter/src/main/res/values/strings.xml index 7566084b8..91bdac771 100644 --- a/feature/lectureevaluation/viewerreporter/src/main/res/values/strings.xml +++ b/feature/lectureevaluation/viewerreporter/src/main/res/values/strings.xml @@ -21,5 +21,6 @@ 등록된 평가가 없어요 시험 정보 열람 -20p 작성하기 + 이미 작성한 이력이 있어요 diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt index 522f6080d..a79cdebfe 100644 --- a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainNavigator.kt @@ -9,8 +9,8 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions -import com.suwiki.feature.lectureevaluation.editor.navigation.navigateMyExamEvaluation -import com.suwiki.feature.lectureevaluation.editor.navigation.navigateMyLectureEvaluation +import com.suwiki.feature.lectureevaluation.editor.navigation.navigateExamEvaluationEditor +import com.suwiki.feature.lectureevaluation.editor.navigation.navigateLectureEvaluationEditor import com.suwiki.feature.lectureevaluation.my.navigation.navigateMyEvaluation import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.navigateLectureEvaluation import com.suwiki.feature.lectureevaluation.viewerreporter.navigation.navigateLectureEvaluationDetail @@ -123,12 +123,12 @@ internal class MainNavigator( navController.navigateMyEvaluation() } - fun navigateMyLectureEvaluationEdit(lectureEvaluation: String) { - navController.navigateMyLectureEvaluation(lectureEvaluation) + fun navigateLectureEvaluationEditor(lectureEvaluation: String) { + navController.navigateLectureEvaluationEditor(lectureEvaluation) } - fun navigateMyExamEvaluationEdit(examEvaluation: String) { - navController.navigateMyExamEvaluation(examEvaluation) + fun navigateExamEvaluationEditor(examEvaluation: String) { + navController.navigateExamEvaluationEditor(examEvaluation) } fun navigateOpenMajor(selectedOpenMajor: String) { diff --git a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt index 774c025b0..ddf1ddb15 100644 --- a/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/suwiki/feature/navigator/MainScreen.kt @@ -109,6 +109,8 @@ internal fun MainScreen( popBackStack = navigator::popBackStackIfNotHome, navigateLogin = navigator::navigateLogin, navigateSignUp = navigator::navigateSignup, + navigateLectureEvaluationEditor = navigator::navigateLectureEvaluationEditor, + navigateExamEvaluationEditor = navigator::navigateExamEvaluationEditor, handleException = viewModel::handleException, navigateOpenMajor = navigator::navigateOpenMajor, onShowToast = viewModel::onShowToast, @@ -117,8 +119,8 @@ internal fun MainScreen( myEvaluationNavGraph( popBackStack = navigator::popBackStackIfNotHome, - navigateMyLectureEvaluationEdit = navigator::navigateMyLectureEvaluationEdit, - navigateMyExamEvaluationEdit = navigator::navigateMyExamEvaluationEdit, + navigateLectureEvaluationEditor = navigator::navigateLectureEvaluationEditor, + navigateExamEvaluationEditor = navigator::navigateExamEvaluationEditor, handleException = viewModel::handleException, ) diff --git a/feature/timetable/build.gradle.kts b/feature/timetable/build.gradle.kts index ac46fa51d..212ab9067 100644 --- a/feature/timetable/build.gradle.kts +++ b/feature/timetable/build.gradle.kts @@ -12,4 +12,5 @@ dependencies { implementation(projects.domain.timetable) implementation(libs.kotlinx.serialization.json) implementation(libs.bundles.glance) + implementation(libs.compose.toolbar) } diff --git a/feature/timetable/src/main/java/com/suwiki/feature/timetable/openlecture/OpenLectureScreen.kt b/feature/timetable/src/main/java/com/suwiki/feature/timetable/openlecture/OpenLectureScreen.kt index 9cc7136d1..d7a172fcd 100644 --- a/feature/timetable/src/main/java/com/suwiki/feature/timetable/openlecture/OpenLectureScreen.kt +++ b/feature/timetable/src/main/java/com/suwiki/feature/timetable/openlecture/OpenLectureScreen.kt @@ -10,6 +10,8 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio 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 @@ -31,6 +33,7 @@ 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.graphicsLayer import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -62,6 +65,9 @@ import com.suwiki.feature.timetable.openlecture.model.SchoolLevel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.launch +import me.onebone.toolbar.CollapsingToolbarScaffold +import me.onebone.toolbar.ScrollStrategy +import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState import org.orbitmvi.orbit.compose.collectAsState import org.orbitmvi.orbit.compose.collectSideEffect @@ -158,6 +164,8 @@ fun OpenLectureScreen( ) { val context = LocalContext.current + val state = rememberCollapsingToolbarScaffoldState() + Column( modifier = Modifier .fillMaxSize() @@ -169,62 +177,79 @@ fun OpenLectureScreen( onClickTextButton = onClickCustomAdd, ) - Spacer(modifier = Modifier.size(12.dp)) - - Row( - modifier = Modifier.padding(horizontal = 24.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - ) { - FilterContainer( - filterName = stringResource(R.string.word_open_major), - value = uiState.selectedOpenMajor, - onClick = { onClickOpenMajorFilterContainer(uiState.selectedOpenMajor) }, - ) - - FilterContainer( - filterName = stringResource(R.string.word_school_level), - value = stringResource(id = uiState.schoolLevel.stringResId), - onClick = onClickSchoolLevelFilterContainer, - ) - } - - SuwikiSearchBar( - modifier = Modifier.padding(top = 10.dp), - placeholder = stringResource(R.string.add_timetable_cell_search_bar_placeholder), - onClickSearchButton = onClickSearchButton, - value = uiState.searchValue, - onClickClearButton = onClickClearButton, - onValueChange = onValueChangeSearch, - ) + CollapsingToolbarScaffold( + modifier = Modifier + .weight(1f), + state = state, + scrollStrategy = ScrollStrategy.EnterAlways, + toolbar = { + Spacer( + modifier = Modifier + .fillMaxWidth() + .height(32.dp), + ) + Column( + modifier = Modifier.graphicsLayer { + alpha = state.toolbarState.progress + }, + ) { + Row( + modifier = Modifier.padding(horizontal = 24.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp), + ) { + FilterContainer( + filterName = stringResource(R.string.word_open_major), + value = uiState.selectedOpenMajor, + onClick = { onClickOpenMajorFilterContainer(uiState.selectedOpenMajor) }, + ) - if (uiState.openLectureList.isEmpty()) { - EmptyText( - stringResource(R.string.word_empty_result), - ) - } + FilterContainer( + filterName = stringResource(R.string.word_school_level), + value = stringResource(id = uiState.schoolLevel.stringResId), + onClick = onClickSchoolLevelFilterContainer, + ) + } - LazyColumn( - modifier = Modifier - .fillMaxSize(), - contentPadding = PaddingValues(bottom = 24.dp), - state = listState, - ) { - items( - items = uiState.openLectureList, - key = { it.id }, - ) { lectureEvaluation -> - with(lectureEvaluation) { - SuwikiClassInformationCard( - className = name, - professor = professorName, - cellInfo = originalCellList.toText(context), - grade = stringResource(id = R.string.word_num_school_level, grade), - classType = type, - openMajor = major, - onClick = { onClickClassInfoCard(this) }, - onClickAdd = { onClickCellAdd(this) }, + SuwikiSearchBar( + modifier = Modifier.padding(top = 10.dp), + placeholder = stringResource(R.string.add_timetable_cell_search_bar_placeholder), + onClickSearchButton = onClickSearchButton, + value = uiState.searchValue, + onClickClearButton = onClickClearButton, + onValueChange = onValueChangeSearch, ) } + }, + ) { + if (uiState.openLectureList.isEmpty()) { + EmptyText( + stringResource(R.string.word_empty_result), + ) + } + + LazyColumn( + modifier = Modifier + .fillMaxSize(), + contentPadding = PaddingValues(bottom = 24.dp), + state = listState, + ) { + items( + items = uiState.openLectureList, + key = { it.id }, + ) { lectureEvaluation -> + with(lectureEvaluation) { + SuwikiClassInformationCard( + className = name, + professor = professorName, + cellInfo = originalCellList.toText(context), + grade = stringResource(id = R.string.word_num_school_level, grade), + classType = type, + openMajor = major, + onClick = { onClickClassInfoCard(this) }, + onClickAdd = { onClickCellAdd(this) }, + ) + } + } } } } diff --git a/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/api/LectureEditorApi.kt b/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/api/LectureEditorApi.kt index 1a9f985f6..fe642ad79 100644 --- a/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/api/LectureEditorApi.kt +++ b/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/api/LectureEditorApi.kt @@ -14,11 +14,13 @@ interface LectureEditorApi { const val EVALUATE_POST = "/evaluate-posts" const val QUERY_EVALUATE_ID = "evaluateIdx" + const val QUERY_LECTURE_ID = "lectureId" } // 강의 평가 쓰기 @POST(EVALUATE_POST) suspend fun postLectureEvaluation( + @Query(QUERY_LECTURE_ID) lectureId: Long, @Body postLectureEvaluationRequest: PostLectureEvaluationRequest, ): ApiResult diff --git a/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/datasource/RemoteLectureEditorDataSourceImpl.kt b/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/datasource/RemoteLectureEditorDataSourceImpl.kt index 57106e560..83cd8657a 100644 --- a/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/datasource/RemoteLectureEditorDataSourceImpl.kt +++ b/remote/lectureevaluation/editor/src/main/java/com/suwiki/remote/lectureevaluation/editor/datasource/RemoteLectureEditorDataSourceImpl.kt @@ -11,6 +11,7 @@ class RemoteLectureEditorDataSourceImpl @Inject constructor( ) : RemoteLectureEditorDataSource { override suspend fun postLectureEvaluation( + lectureId: Long, lectureName: String, professor: String, selectedSemester: String, @@ -36,6 +37,7 @@ class RemoteLectureEditorDataSourceImpl @Inject constructor( ) return lectureApi.postLectureEvaluation( + lectureId, request, ).getOrThrow() } diff --git a/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSourceImpl.kt b/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSourceImpl.kt index 1a78ca041..bc57cf66e 100644 --- a/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSourceImpl.kt +++ b/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/datasource/RemoteExamReportDataSourceImpl.kt @@ -10,12 +10,12 @@ class RemoteExamReportDataSourceImpl @Inject constructor( ) : RemoteExamReportDataSource { override suspend fun reportExam( - evaluateIdx: Long, + examIdx: Long, content: String, ) { return examApi.reportExam( ReportExamRequest( - evaluateIdx = evaluateIdx, + examIdx = examIdx, content = content, ), ).getOrThrow() diff --git a/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/request/ReportExamRequest.kt b/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/request/ReportExamRequest.kt index 23f2280c6..60e6b5b0c 100644 --- a/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/request/ReportExamRequest.kt +++ b/remote/lectureevaluation/viewerreporter/src/main/java/com/suwiki/remote/lectureevaluation/viewerreporter/request/ReportExamRequest.kt @@ -4,6 +4,6 @@ import kotlinx.serialization.Serializable @Serializable data class ReportExamRequest( - val evaluateIdx: Long, + val examIdx: Long, val content: String = "", )