Skip to content

Commit

Permalink
Merge pull request #304 from 6QuizOnTheBlock/and/feat#293-student_rel…
Browse files Browse the repository at this point in the history
…ay_create

And/feat#293 학생 이어 달리기 생성
  • Loading branch information
ghddbwns9808 authored May 12, 2024
2 parents 586ea62 + a6a2eb4 commit f1658dc
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.sixkids.data.api

import com.sixkids.data.model.request.RelayCreateRequest
import com.sixkids.data.model.response.RelayDetailResponse
import com.sixkids.data.model.response.RelayHistoryResponse
import com.sixkids.data.model.response.RunningRelayResponse
import com.sixkids.data.network.ApiResponse
import com.sixkids.data.network.ApiResult
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query

interface RelayService {
Expand All @@ -28,4 +31,9 @@ interface RelayService {
@Query("id") relayId: Long
): ApiResult<ApiResponse<RelayDetailResponse>>

@POST("relays")
suspend fun createRelay(
@Body relayCreateRequest: RelayCreateRequest
): ApiResult<ApiResponse<Long>>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.sixkids.data.model.request

data class RelayCreateRequest(
val organizationId: Int,
val question: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ class RelayRepositoryImpl @Inject constructor(
override suspend fun getRelayDetail(relayId: Long): RelayDetail {
return relayRemoteDataSource.getRelayDetail(relayId)
}

override suspend fun createRelay(organizationId: Int, question: String): Long {
return relayRemoteDataSource.createRelay(organizationId, question)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ interface RelayRemoteDataSource {
suspend fun getRunningRelay(organizationId: Long) : RunningRelay

suspend fun getRelayDetail(relayId: Long) : RelayDetail

suspend fun createRelay(organizationId: Int, question: String) : Long
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.sixkids.data.repository.relay.remote

import com.sixkids.data.api.RelayService
import com.sixkids.data.model.request.RelayCreateRequest
import com.sixkids.data.model.response.toModel
import com.sixkids.model.RelayDetail
import com.sixkids.model.RunningRelay
Expand All @@ -16,4 +17,8 @@ class RelayRemoteDataSourceImpl @Inject constructor(
return relayService.getRelayDetail(relayId).getOrThrow().data.toModel()
}

override suspend fun createRelay(organizationId: Int, question: String): Long {
return relayService.createRelay(RelayCreateRequest(organizationId, question)).getOrThrow().data
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ interface RelayRepository {
suspend fun getRunningRelay(organizationId: Long): RunningRelay

suspend fun getRelayDetail(relayId: Long): RelayDetail

suspend fun createRelay(organizationId: Int, question: String): Long
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sixkids.domain.usecase.relay

import com.sixkids.domain.repository.RelayRepository
import javax.inject.Inject

class CreateRelayUseCase @Inject constructor(
private val relayRepository: RelayRepository
){
suspend operator fun invoke(organizationId: Int, question: String) = runCatching {
relayRepository.createRelay(organizationId, question)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.sixkids.student.navigation.navigateStudentChallengeHistory
import com.sixkids.student.navigation.navigateStudentGroupCreate
import com.sixkids.student.navigation.navigateStudentGroupJoin
import com.sixkids.student.relay.navigation.navigateStudentRelayCreate
import com.sixkids.student.relay.navigation.navigateStudentRelayCreateResult
import com.sixkids.student.relay.navigation.navigateStudentRelayDetail
import com.sixkids.student.relay.navigation.navigateStudentRelayHistory
import com.sixkids.student.relay.navigation.navigateStudentRelayJoin
Expand Down Expand Up @@ -257,6 +258,10 @@ class MainNavigator(
navController.navigateStudentRelayJoin()
}

fun navigateStudentRelayCreateResult(newRelayId: Long) {
navController.navigateStudentRelayCreateResult(newRelayId)
}

/**
* Challenge Navigation
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,10 @@ fun MainScreen(
studentRelayNavGraph(
navigateRelayDetail = navigator::navigateStudentRelayDetail,
navigateCreateRelay = navigator::navigateStudentRelayCreate,
navigateCreateRelayResult = navigator::navigateStudentRelayCreateResult,
navigateJoinRelay = navigator::navigateStudentRelayJoin,
onShowSnackBar = viewModel::onShowSnackbar,
onBackClick = navigator::popBackStack,
handleException = viewModel::handleException
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sixkids.student.relay.create

import com.sixkids.ui.SnackbarToken
import com.sixkids.ui.base.SideEffect
import com.sixkids.ui.base.UiState

data class RelayCreateState(
val isLoading: Boolean = false,
val question: String = "",
val orgId: Int = -1
) : UiState

sealed interface RelayCreateEffect: SideEffect {
data class NavigateToRelayResult(val newRelayId: Long) : RelayCreateEffect
data class OnShowSnackBar(val tkn : SnackbarToken) : RelayCreateEffect
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.sixkids.student.relay.create

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sixkids.designsystem.component.button.UlbanFilledButton
import com.sixkids.designsystem.component.screen.UlbanTopSection
import com.sixkids.designsystem.component.textfield.UlbanUnderLineTextField
import com.sixkids.designsystem.theme.UlbanTheme
import com.sixkids.designsystem.theme.UlbanTypography
import com.sixkids.student.relay.R
import com.sixkids.ui.SnackbarToken
import com.sixkids.ui.extension.collectWithLifecycle

@Composable
fun RelayCreateRoute(
viewModel: RelayCreateViewModel = hiltViewModel(),
navigateToRelayResult: (Long) -> Unit,
onBackClick: () -> Unit,
onShowSnackBar: (SnackbarToken) -> Unit
) {
val uiState = viewModel.uiState.collectAsStateWithLifecycle().value

viewModel.sideEffect.collectWithLifecycle { sideEffect ->
when (sideEffect) {
is RelayCreateEffect.NavigateToRelayResult -> navigateToRelayResult(sideEffect.newRelayId)
is RelayCreateEffect.OnShowSnackBar -> onShowSnackBar(sideEffect.tkn)
}
}

LaunchedEffect(key1 = Unit) {
viewModel.init()
}

RelayCreateScreen(
uiState = uiState,
onNewRelayClick = viewModel::newRelayClick,
onBackClick = onBackClick,
onUpdateQuestion = viewModel::updateQuestion,
)

}

@Composable
fun RelayCreateScreen(
paddingValues: PaddingValues = PaddingValues(20.dp),
uiState: RelayCreateState = RelayCreateState(),
onNewRelayClick: () -> Unit = {},
onBackClick: () -> Unit = {},
onUpdateQuestion: (String) -> Unit = {}
) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.Start,
) {
UlbanTopSection(stringResource(id = R.string.relay_create_topsection), onBackClick)

Spacer(modifier = Modifier.height(36.dp))

Text(
text = stringResource(R.string.relay_create_question),
style = UlbanTypography.bodyLarge,
modifier = Modifier.padding(top = 10.dp, bottom = 10.dp)
)
UlbanUnderLineTextField(
text = uiState.question,
hint = stringResource(R.string.relay_create_question_hint),
onTextChange = onUpdateQuestion,
onIconClick = {
onUpdateQuestion("")
}
)

Spacer(modifier = Modifier.weight(1f))

UlbanFilledButton(
text = stringResource(R.string.relay_create_create),
onClick = { onNewRelayClick() },
modifier = Modifier.fillMaxWidth())
}
}
}

@Composable
@Preview(showBackground = true)
fun RelayCreateScreenPreview() {
UlbanTheme {
RelayCreateScreen()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.sixkids.student.relay.create

import android.util.Log
import androidx.lifecycle.viewModelScope
import com.sixkids.domain.usecase.organization.GetSelectedOrganizationIdUseCase
import com.sixkids.domain.usecase.relay.CreateRelayUseCase
import com.sixkids.ui.SnackbarToken
import com.sixkids.ui.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

private const val TAG = "D107"
@HiltViewModel
class RelayCreateViewModel @Inject constructor(
private val getSelectedOrganizationIdUseCase: GetSelectedOrganizationIdUseCase,
private val createRelayUseCase: CreateRelayUseCase
) : BaseViewModel<RelayCreateState, RelayCreateEffect>(RelayCreateState()) {

fun init() {
viewModelScope.launch {
getSelectedOrganizationIdUseCase()
.onSuccess {
intent { copy(orgId = it) }
}.onFailure {
postSideEffect(RelayCreateEffect.OnShowSnackBar(SnackbarToken("학급 정보를 불러오는데 실패했습니다")))
}
}
}

fun newRelayClick() {
viewModelScope.launch {
intent { copy(isLoading = true) }
if (uiState.value.orgId == -1){
init()
}else{
Log.d(TAG, "newRelayClick: ${uiState.value.question} ${uiState.value.orgId}")
createRelayUseCase(uiState.value.orgId, uiState.value.question)
.onSuccess {
postSideEffect(RelayCreateEffect.NavigateToRelayResult(it))
}.onFailure {
postSideEffect(RelayCreateEffect.OnShowSnackBar(SnackbarToken("이어 달리기 생성에 실패했습니다")))
}
}
}
}

fun updateQuestion(question: String) {
intent { copy(question = question) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ data class RelayHistoryState(
) : UiState

sealed interface RelayHistoryEffect : SideEffect {
data class NavigateToRelayDetail(val relayId: Long, val groupId: Long? = null) : RelayHistoryEffect
data class NavigateToRelayDetail(val relayId: Long) : RelayHistoryEffect
data object NavigateToCreateRelay : RelayHistoryEffect
data object NavigateToJoinRelay : RelayHistoryEffect
data class HandleException(val throwable: Throwable, val retry: () -> Unit) : RelayHistoryEffect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ package com.sixkids.student.relay.navigation
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.NavType
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.sixkids.student.relay.create.RelayCreateRoute
import com.sixkids.student.relay.detail.RelayDetailRoute
import com.sixkids.student.relay.history.RelayRoute
import com.sixkids.student.relay.navigation.RelayRoute.RELAY_ID_NAME
import com.sixkids.ui.SnackbarToken

fun NavController.navigateStudentRelayHistory(navOptions: NavOptions) {
navigate(RelayRoute.defaultRoute, navOptions)
Expand All @@ -19,6 +24,10 @@ fun NavController.navigateStudentRelayCreate() {
navigate(RelayRoute.createRoute)
}

fun NavController.navigateStudentRelayCreateResult(newRelayId: Long) {
navigate(RelayRoute.createResultRoute(newRelayId))
}

fun NavController.navigateStudentRelayJoin() {
navigate(RelayRoute.joinRoute)
}
Expand All @@ -27,6 +36,9 @@ fun NavGraphBuilder.studentRelayNavGraph(
navigateRelayDetail: (Long) -> Unit,
navigateCreateRelay: () -> Unit,
navigateJoinRelay: () -> Unit,
navigateCreateRelayResult: (Long) -> Unit,
onBackClick: () -> Unit,
onShowSnackBar: (SnackbarToken) -> Unit,
handleException: (Throwable, () -> Unit) -> Unit
) {
composable(route = RelayRoute.defaultRoute)
Expand All @@ -41,21 +53,38 @@ fun NavGraphBuilder.studentRelayNavGraph(
)
}

composable(route = RelayRoute.detailRoute)
composable(route = RelayRoute.detailRoute,
arguments = listOf(
navArgument(RELAY_ID_NAME) { type = NavType.LongType },

))
{

RelayDetailRoute(
handleException = handleException
)
}

composable(route = RelayRoute.createRoute)
{
RelayCreateRoute(
navigateToRelayResult = navigateCreateRelayResult,
onBackClick = onBackClick,
onShowSnackBar = onShowSnackBar
)
}
}

object RelayRoute {
const val RELAY_ID_NAME = "relayId"
const val NEW_RELAY_ID_NAME = "newRelayId"

const val defaultRoute = "relay-history"
const val createRoute = "relay-create"
const val detailRoute = "relay-detail?relayId={$RELAY_ID_NAME}"
const val createResultRoute = "relay-create-result?newRelayId={$NEW_RELAY_ID_NAME}"
const val joinRoute = "relay-join"

fun detailRoute(relayId: Long) = "relay-detail?relayId=$relayId"
fun createResultRoute(newRelayId: Long) = "relay-create-result?newRelayId=$newRelayId"
}
Loading

0 comments on commit f1658dc

Please sign in to comment.