Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT/#77] 초대 코드 검증 API #82

Merged
merged 13 commits into from
Jan 12, 2024
Merged
3 changes: 1 addition & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
android:exported="false"
android:screenOrientation="portrait" />


<activity
android:name="com.going.presentation.tendencytest.TendencyTestSplashActivity"
android:exported="false"
Expand Down Expand Up @@ -130,7 +129,7 @@
android:screenOrientation="portrait" />

<activity
android:name="com.going.presentation.profile.ProfileActivity"
android:name="com.going.presentation.tripdashboard.profile.ProfileActivity"
android:exported="false"
android:screenOrientation="portrait" />

Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/going/doorip/di/DataSourceModule.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.going.doorip.di

import com.going.data.datasource.AuthDataSource
import com.going.data.datasource.EnterTripDataSource
import com.going.data.datasource.MockDataSource
import com.going.data.datasource.SettingDataSource
import com.going.data.datasource.TodoDataSource
import com.going.data.datasourceImpl.AuthDataSourceImpl
import com.going.data.datasourceImpl.EnterTripDataSourceImpl
import com.going.data.datasourceImpl.MockDataSourceImpl
import com.going.data.datasourceImpl.SettingDataSourceImpl
import com.going.data.datasourceImpl.TodoDataSourceImpl
Expand Down Expand Up @@ -38,4 +40,9 @@ object DataSourceModule {
fun provideTodoDataSource(todoDataSourceImpl: TodoDataSourceImpl): TodoDataSource =
todoDataSourceImpl

@Provides
@Singleton
fun provideEnterTripDataSource(entertripDataSourceImpl: EnterTripDataSourceImpl): EnterTripDataSource =
entertripDataSourceImpl

}
7 changes: 7 additions & 0 deletions app/src/main/java/com/going/doorip/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.going.doorip.di

import com.going.data.repositoryImpl.AuthRepositoryImpl
import com.going.data.repositoryImpl.EnterTripRepositoryImpl
import com.going.data.repositoryImpl.MockRepositoryImpl
import com.going.data.repositoryImpl.SettingRepositoryImpl
import com.going.data.repositoryImpl.TodoRepositoryImpl
import com.going.data.repositoryImpl.TokenRepositoryImpl
import com.going.domain.repository.AuthRepository
import com.going.domain.repository.EnterTripRepository
import com.going.domain.repository.MockRepository
import com.going.domain.repository.SettingRepository
import com.going.domain.repository.TodoRepository
Expand Down Expand Up @@ -45,4 +47,9 @@ object RepositoryModule {
fun provideTodoRepository(todoRepositoryImpl: TodoRepositoryImpl): TodoRepository =
todoRepositoryImpl

@Provides
@Singleton
fun provideEnterTripRepository(entertripRepositoryImpl: EnterTripRepositoryImpl): EnterTripRepository =
entertripRepositoryImpl

}
6 changes: 6 additions & 0 deletions app/src/main/java/com/going/doorip/di/ServiceModule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.going.doorip.di

import com.going.data.service.AuthService
import com.going.data.service.EnterTripService
import com.going.data.service.MockService
import com.going.data.service.SettingService
import com.going.data.service.TodoService
Expand Down Expand Up @@ -35,4 +36,9 @@ object ServiceModule {
fun provideTodoService(retrofit: Retrofit): TodoService =
retrofit.create(TodoService::class.java)

@Provides
@Singleton
fun provideEnterTripService(retrofit: Retrofit): EnterTripService =
retrofit.create(EnterTripService::class.java)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.going.data.datasource;

import com.going.data.dto.BaseResponse
import com.going.data.dto.request.EnterTripRequestDto
import com.going.data.dto.response.EnterTripResponseDto

interface EnterTripDataSource {
suspend fun postEnterTrip(
code: EnterTripRequestDto,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code 라고 값만 작성하시면, 서비스에서 서버통신을 진행할 때 requestDto가 아니라 Path나 Query같은 파라미터 값으로 혼동될 수 있기 때문에 파라미터 값을 이왕이면 request로 작성하는 것이 더 좋을 듯 합니다

): BaseResponse<EnterTripResponseDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.going.data.datasourceImpl

import com.going.data.datasource.EnterTripDataSource
import com.going.data.dto.BaseResponse
import com.going.data.dto.request.EnterTripRequestDto
import com.going.data.dto.response.EnterTripResponseDto
import com.going.data.service.EnterTripService
import javax.inject.Inject

class EnterTripDataSourceImpl @Inject constructor(
private val enterTripService: EnterTripService,
) : EnterTripDataSource {
override suspend fun postEnterTrip(
code: EnterTripRequestDto
): BaseResponse<EnterTripResponseDto> =
enterTripService.postEnterTrip(code)


}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공백...ㅎㅎㅎ

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.going.data.dto.request

import com.going.domain.entity.request.RequestEnterTripModel
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class EnterTripRequestDto(
@SerialName("code")
val code: String,
)

fun RequestEnterTripModel.toEnterTripRequestDto(): EnterTripRequestDto =
EnterTripRequestDto(code)

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.going.data.dto.response

import com.going.domain.entity.response.EnterTripModel
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class EnterTripResponseDto(
@SerialName("tripId")
val tripId: Long,
@SerialName("title")
val title: String,
@SerialName("startDate")
val startDate: String,
@SerialName("endDate")
val endDate: String,
@SerialName("day")
val day: Int,
) {
fun toEnterTripModel() =
EnterTripModel(tripId, title, startDate, endDate, day)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class AuthInterceptor @Inject constructor(
originalRequest
}


val response = chain.proceed(authRequest)

when (response.code) {
Expand Down Expand Up @@ -84,8 +85,8 @@ class AuthInterceptor @Inject constructor(
return response
}

private fun Request.newAuthBuilder() =
this.newBuilder().addHeader(AUTHORIZATION, "$BEARER ${dataStore.accessToken}")
private fun Request.newAuthBuilder() =
this.newBuilder().addHeader(AUTHORIZATION, "$BEARER ${dataStore.accessToken}")

companion object {
private const val CODE_TOKEN_EXPIRED = 401
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.going.data.repositoryImpl

import com.going.data.datasource.EnterTripDataSource
import com.going.data.dto.request.toEnterTripRequestDto
import com.going.domain.entity.request.RequestEnterTripModel
import com.going.domain.entity.response.EnterTripModel
import com.going.domain.repository.EnterTripRepository
import javax.inject.Inject

class EnterTripRepositoryImpl @Inject constructor(
private val enterTripDataSource: EnterTripDataSource,
) : EnterTripRepository {

override suspend fun postEnterTrip(
requestEnterTripModel: RequestEnterTripModel
): Result<EnterTripModel> =
runCatching {
enterTripDataSource.postEnterTrip(
requestEnterTripModel.toEnterTripRequestDto(),
).data.toEnterTripModel()
}
}
14 changes: 14 additions & 0 deletions data/src/main/java/com/going/data/service/EnterTripService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.going.data.service

import com.going.data.dto.BaseResponse
import com.going.data.dto.request.EnterTripRequestDto
import com.going.data.dto.response.EnterTripResponseDto
import retrofit2.http.Body
import retrofit2.http.POST

interface EnterTripService {
@POST("/api/trips/verify")
suspend fun postEnterTrip(
@Body body: EnterTripRequestDto,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 통일성을 위해서 request로 갑시당 ~

): BaseResponse<EnterTripResponseDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.going.domain.entity.request

data class RequestEnterTripModel(
val code: String
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

진짜 사소할 수 있는 네이밍 통일인데, ~RequestModel, ~Model, ~RequestDto, ~ResponseDto 로 갑시다 !

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.going.domain.entity.response

data class EnterTripModel(
val tripId: Long,
val title: String,
val startDate: String,
val endDate: String,
val day: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.going.domain.repository

import com.going.domain.entity.request.RequestEnterTripModel
import com.going.domain.entity.response.EnterTripModel

interface EnterTripRepository {

suspend fun postEnterTrip(
requestEnterTripModel: RequestEnterTripModel
): Result<EnterTripModel?>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 같이 ? 빼주세요 ~

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,37 @@ package com.going.presentation.enter.entertrip

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.activity.viewModels
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.going.domain.entity.CodeState
import com.going.presentation.R
import com.going.presentation.databinding.ActivityEnterTripBinding
import com.going.presentation.enter.invitefinish.InviteFinishActivity
import com.going.presentation.starttrip.StartTripSplashActivity
import com.going.ui.base.BaseActivity
import com.going.ui.extension.UiState
import com.going.ui.extension.setOnSingleClickListener
import com.going.ui.extension.toast
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

@AndroidEntryPoint
class EnterTripActivity : BaseActivity<ActivityEnterTripBinding>(R.layout.activity_enter_trip) {
private val viewModel by viewModels<EnterTripViewModel>()


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initBackBtnClickListener()
initBindingViewModel()
observeIsCodeAvailable()
initNextBtnClickListener()
observeEnterTripState()


}
Expand Down Expand Up @@ -76,9 +86,36 @@ class EnterTripActivity : BaseActivity<ActivityEnterTripBinding>(R.layout.activi
counter.setTextColor(getColor(color))
}


private fun observeEnterTripState() {
viewModel.tripState.flowWithLifecycle(lifecycle).onEach { state ->
when (state) {
is UiState.Success -> {

Intent(this, InviteFinishActivity::class.java).apply {
putExtra("title", state.data.title)
putExtra("start", state.data.startDate)
putExtra("end", state.data.endDate)
putExtra("day", state.data.day)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엑스트라를 인텐트로 옮기는 과정에서는 키값을 한 곳에서 보관해주시는 것이 좋습니다!
이럴 때는 받는 곳이나 보내는 곳중에 엑스트라를 더 많이 사용할 것 같은 뷰에서 const val로 따로 텍스트를 지정해주시는 것이 좋습니다

예시 :

companion object {
    const val EXTRA_TODO_ID = "EXTRA_TODO_ID"
}

Log.d("day1", state.data.day.toString())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로그 !

startActivity(this)
}
}

is UiState.Failure -> {
toast(getString(R.string.server_error))
}

is UiState.Loading -> return@onEach

is UiState.Empty -> return@onEach
}
}.launchIn(lifecycleScope)
}

private fun initNextBtnClickListener() {
binding.btnEnterTripNext.setOnSingleClickListener {
//다음 뷰로 이동
viewModel.checkInviteCodeFromServer()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,25 @@ package com.going.presentation.enter.entertrip

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.going.domain.entity.CodeState
import com.going.domain.entity.request.RequestEnterTripModel
import com.going.domain.entity.response.EnterTripModel
import com.going.domain.repository.EnterTripRepository
import com.going.ui.extension.UiState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import java.util.regex.Pattern
import javax.inject.Inject

class EnterTripViewModel : ViewModel() {
@HiltViewModel
class EnterTripViewModel @Inject constructor(
private val enterTripRepository: EnterTripRepository
) : ViewModel() {
private val _tripState = MutableStateFlow<UiState<EnterTripModel>>(UiState.Empty)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

줄바꿈하면 예쁠듯 ㅋㅋ

val tripState: StateFlow<UiState<EnterTripModel>> = _tripState

val inviteCode = MutableLiveData<String>()
var codeLength = MutableLiveData(0)
Expand All @@ -31,6 +46,18 @@ class EnterTripViewModel : ViewModel() {
isCheckEnterAvailable.value = isCodeAvailable.value == CodeState.Success
}

fun checkInviteCodeFromServer() {
_tripState.value = UiState.Loading
viewModelScope.launch {
enterTripRepository.postEnterTrip(
RequestEnterTripModel(inviteCode.value ?: "")
).onSuccess { result ->
_tripState.value = result?.let { UiState.Success(it) } ?: UiState.Failure("no")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앞에 애들에서 ?를 제외해서 보내게 된다면, 뷰모델에서 null값에 대해서 예외처리를 진행하지 않고도 편하게 사용 가능합니다~

}.onFailure {
_tripState.value = UiState.Failure(it.message.orEmpty())
}
}
}

companion object {
private const val ENG_NUM_PATTERN = "^[a-z0-9]*$"
Expand Down
Loading