diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 09a8ea8..50ec747 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,11 +20,6 @@ android:label="@string/app_name" android:theme="@style/Theme.Meongmory"> - - - - - -} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/datasource/FoodDataSourceImpl.kt b/data/src/main/java/com/meongmoryteam/data/datasource/FoodDataSourceImpl.kt deleted file mode 100644 index e29a4ff..0000000 --- a/data/src/main/java/com/meongmoryteam/data/datasource/FoodDataSourceImpl.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.meongmoryteam.data.datasource - -import com.meongmoryteam.data.model.WeekFoodResponse -import com.meongmoryteam.data.service.ExampleApi -import javax.inject.Inject - -class FoodDataSourceImpl @Inject constructor( - private val exampleApi: ExampleApi -) : FoodDataSource { - override suspend fun weekGetFoodArea(s: String): Result { - return runCatching { exampleApi.weekGetFoodArea(s) } - } -} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/datasource/login/LoginDataSource.kt b/data/src/main/java/com/meongmoryteam/data/datasource/login/LoginDataSource.kt new file mode 100644 index 0000000..63fa73e --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/datasource/login/LoginDataSource.kt @@ -0,0 +1,11 @@ +package com.meongmoryteam.data.datasource.login + +import com.meongmoryteam.data.model.response.login.GetSmsSendResponse +import com.meongmoryteam.data.model.request.login.SmsSendRequest +import com.meongmoryteam.data.model.request.login.SmsValidateRequest +import com.meongmoryteam.data.model.response.login.PostSmsValidateResponse + +interface LoginDataSource { + suspend fun getSmsSend(smsSendRequest: SmsSendRequest): Result + suspend fun postSmsValidate(smsValidateRequest: SmsValidateRequest): Result +} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/datasource/login/LoginDataSourceImpl.kt b/data/src/main/java/com/meongmoryteam/data/datasource/login/LoginDataSourceImpl.kt new file mode 100644 index 0000000..cdba355 --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/datasource/login/LoginDataSourceImpl.kt @@ -0,0 +1,21 @@ +package com.meongmoryteam.data.datasource.login + +import com.meongmoryteam.data.model.response.login.GetSmsSendResponse +import com.meongmoryteam.data.model.request.login.SmsSendRequest +import com.meongmoryteam.data.model.request.login.SmsValidateRequest +import com.meongmoryteam.data.model.response.login.PostSmsValidateResponse +import com.meongmoryteam.data.service.login.LoginApi +import javax.inject.Inject + +class LoginDataSourceImpl @Inject constructor( + private val loginApi: LoginApi +): LoginDataSource { + + override suspend fun getSmsSend(smsSendRequest: SmsSendRequest): Result { + return runCatching { loginApi.getSmsSend(smsSendRequest) } + } + + override suspend fun postSmsValidate(smsValidateRequest: SmsValidateRequest): Result { + return runCatching { loginApi.postSmsValidate(smsValidateRequest) } + } +} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/model/GetWeekFood.kt b/data/src/main/java/com/meongmoryteam/data/model/GetWeekFood.kt deleted file mode 100644 index 9550d5d..0000000 --- a/data/src/main/java/com/meongmoryteam/data/model/GetWeekFood.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.meongmoryteam.data.model - -import com.meongmoryteam.domain.model.ResponseWeekFoodEntity -import kotlinx.serialization.Serializable - -@Serializable -data class WeekFoodResponse( - val success : Boolean, - val message : String, - val localDateTime : String, - val httpStatus : String, - val httpCode : Int, - val data : List, -) { - @Serializable - data class WeekFoodResult( - val mealId: Int, - val toDay: String, - val mealType : String, - val statusType : String, - val meals : List - ) -} - -fun WeekFoodResponse.toWeekFoodEntity(): ResponseWeekFoodEntity { - val weekFoodResultEntityList = this.data.map { result -> - ResponseWeekFoodEntity.WeekFoodResultEntity( - mealId = result.mealId, - toDay = result.toDay, - mealType = result.mealType, - statusType = result.statusType, - meals = result.meals - ) - } - - return ResponseWeekFoodEntity( - success = this.success, - message = this.message, - localDateTime = this.localDateTime, - httpStatus = this.httpStatus, - httpCode = this.httpCode, - data = weekFoodResultEntityList - ) -} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/model/request/login/SmsSendRequest.kt b/data/src/main/java/com/meongmoryteam/data/model/request/login/SmsSendRequest.kt new file mode 100644 index 0000000..419f3d1 --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/model/request/login/SmsSendRequest.kt @@ -0,0 +1,15 @@ +package com.meongmoryteam.data.model.request.login + +import com.meongmoryteam.domain.model.reqeust.login.SmsSendRequestEntity +import kotlinx.serialization.Serializable + +@Serializable +data class SmsSendRequest( + val phone: String +) + +fun SmsSendRequestEntity.toSmsSendRequest(): SmsSendRequest { + return SmsSendRequest( + phone = this.phone + ) +} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/model/request/login/SmsValidateRequest.kt b/data/src/main/java/com/meongmoryteam/data/model/request/login/SmsValidateRequest.kt new file mode 100644 index 0000000..d614d5c --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/model/request/login/SmsValidateRequest.kt @@ -0,0 +1,17 @@ +package com.meongmoryteam.data.model.request.login + +import com.meongmoryteam.domain.model.reqeust.login.SmsValidateRequestEntity +import kotlinx.serialization.Serializable + +@Serializable +data class SmsValidateRequest( + val code: String, + val phone: String +) + +fun SmsValidateRequestEntity.toSmsValidateRequest(): SmsValidateRequest { + return SmsValidateRequest( + code = this.code, + phone = this.phone + ) +} diff --git a/data/src/main/java/com/meongmoryteam/data/model/response/login/GetSmsSendResponse.kt b/data/src/main/java/com/meongmoryteam/data/model/response/login/GetSmsSendResponse.kt new file mode 100644 index 0000000..9a29098 --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/model/response/login/GetSmsSendResponse.kt @@ -0,0 +1,31 @@ +package com.meongmoryteam.data.model.response.login + +import com.meongmoryteam.domain.model.response.login.GetSmsSendData +import com.meongmoryteam.domain.model.response.login.GetSmsSendEntity +import kotlinx.serialization.Serializable + +@Serializable +data class GetSmsSendResponse( + val status: Int, + val code: String, + val message: String, + val data: Data, +) + +@Serializable +data class Data( + val value: String, + val message: String? +) + +fun GetSmsSendResponse.toGetSmsSendEntity(): GetSmsSendEntity { + return GetSmsSendEntity( + status = this.status, + code = this.code, + message = this.message, + getSmsSendData = GetSmsSendData( + value = this.data.value, + message = this.data.message + ) + ) +} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/model/response/login/PostSmsValidateResponse.kt b/data/src/main/java/com/meongmoryteam/data/model/response/login/PostSmsValidateResponse.kt new file mode 100644 index 0000000..4cd688f --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/model/response/login/PostSmsValidateResponse.kt @@ -0,0 +1,21 @@ +package com.meongmoryteam.data.model.response.login + +import com.meongmoryteam.domain.model.response.login.PostSmsValidateEntity +import kotlinx.serialization.Serializable + +@Serializable +data class PostSmsValidateResponse( + val status: Int, + val code: String, + val message: String, + val data: Boolean +) + +fun PostSmsValidateResponse.toPostSmsValidateEntity(): PostSmsValidateEntity { + return PostSmsValidateEntity( + status = this.status, + code = this.code, + message = this.message, + data = this.data + ) +} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/repository/FoodRepositoryImpl.kt b/data/src/main/java/com/meongmoryteam/data/repository/FoodRepositoryImpl.kt deleted file mode 100644 index c00ed79..0000000 --- a/data/src/main/java/com/meongmoryteam/data/repository/FoodRepositoryImpl.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.meongmoryteam.data.repository - -import com.meongmoryteam.data.datasource.FoodDataSource -import com.meongmoryteam.data.model.toWeekFoodEntity -import com.meongmoryteam.domain.model.ResponseWeekFoodEntity -import com.meongmoryteam.domain.repository.FoodRepository -import javax.inject.Inject - -class FoodRepositoryImpl @Inject constructor( - private val foodDataSource: FoodDataSource -) : FoodRepository { - - override suspend fun weekFood(area: String): Result { - return foodDataSource.weekGetFoodArea(area).map { it.toWeekFoodEntity() } - } -} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/repository/login/LoginRepositoryImpl.kt b/data/src/main/java/com/meongmoryteam/data/repository/login/LoginRepositoryImpl.kt new file mode 100644 index 0000000..9d180fb --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/repository/login/LoginRepositoryImpl.kt @@ -0,0 +1,26 @@ +package com.meongmoryteam.data.repository.login + +import com.meongmoryteam.data.datasource.login.LoginDataSource +import com.meongmoryteam.data.model.response.login.toGetSmsSendEntity +import com.meongmoryteam.data.model.request.login.toSmsSendRequest +import com.meongmoryteam.data.model.request.login.toSmsValidateRequest +import com.meongmoryteam.data.model.response.login.toPostSmsValidateEntity +import com.meongmoryteam.domain.model.response.login.GetSmsSendEntity +import com.meongmoryteam.domain.model.reqeust.login.SmsSendRequestEntity +import com.meongmoryteam.domain.model.reqeust.login.SmsValidateRequestEntity +import com.meongmoryteam.domain.model.response.login.PostSmsValidateEntity +import com.meongmoryteam.domain.repository.login.LoginRepository +import javax.inject.Inject + +class LoginRepositoryImpl @Inject constructor( + private val loginDataSource: LoginDataSource +) : LoginRepository { + + override suspend fun getSmsSend(smsSendRequestEntity: SmsSendRequestEntity): Result { + return loginDataSource.getSmsSend(smsSendRequestEntity.toSmsSendRequest()).map { it.toGetSmsSendEntity() } + } + + override suspend fun postSmsValidate(smsValidateRequestEntity: SmsValidateRequestEntity): Result { + return loginDataSource.postSmsValidate(smsValidateRequestEntity.toSmsValidateRequest()).map { it.toPostSmsValidateEntity() } + } +} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/service/ExampleApi.kt b/data/src/main/java/com/meongmoryteam/data/service/ExampleApi.kt deleted file mode 100644 index 198ea75..0000000 --- a/data/src/main/java/com/meongmoryteam/data/service/ExampleApi.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.meongmoryteam.data.service - -import com.meongmoryteam.data.model.WeekFoodResponse -import retrofit2.http.GET -import retrofit2.http.Path - -interface ExampleApi { - - @GET("/api/v2/meals/week/{area}") - suspend fun weekGetFoodArea( - @Path("area") area: String - ): WeekFoodResponse -} \ No newline at end of file diff --git a/data/src/main/java/com/meongmoryteam/data/service/login/LoginApi.kt b/data/src/main/java/com/meongmoryteam/data/service/login/LoginApi.kt new file mode 100644 index 0000000..3da3c79 --- /dev/null +++ b/data/src/main/java/com/meongmoryteam/data/service/login/LoginApi.kt @@ -0,0 +1,21 @@ +package com.meongmoryteam.data.service.login + +import com.meongmoryteam.data.model.response.login.GetSmsSendResponse +import com.meongmoryteam.data.model.request.login.SmsSendRequest +import com.meongmoryteam.data.model.request.login.SmsValidateRequest +import com.meongmoryteam.data.model.response.login.PostSmsValidateResponse +import retrofit2.http.Body +import retrofit2.http.POST + +interface LoginApi { + + @POST("sms/send") + suspend fun getSmsSend( + @Body smsSendRequest: SmsSendRequest + ): GetSmsSendResponse + + @POST("sms/validate") + suspend fun postSmsValidate( + @Body smsValidateRequest: SmsValidateRequest + ): PostSmsValidateResponse +} \ No newline at end of file diff --git a/domain/src/main/java/com/meongmoryteam/domain/model/ResponseWeekFoodEntity.kt b/domain/src/main/java/com/meongmoryteam/domain/model/ResponseWeekFoodEntity.kt deleted file mode 100644 index 1001d5a..0000000 --- a/domain/src/main/java/com/meongmoryteam/domain/model/ResponseWeekFoodEntity.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.meongmoryteam.domain.model - -data class ResponseWeekFoodEntity( - val success : Boolean, - val message : String, - val localDateTime : String, - val httpStatus : String, - val httpCode : Int, - val data : List, -){ - data class WeekFoodResultEntity( - val mealId: Int, - val toDay: String, - val mealType : String, - val statusType : String, - val meals : List - ) -} diff --git a/domain/src/main/java/com/meongmoryteam/domain/model/reqeust/login/SmsSendRequestEntity.kt b/domain/src/main/java/com/meongmoryteam/domain/model/reqeust/login/SmsSendRequestEntity.kt new file mode 100644 index 0000000..0c56f78 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/model/reqeust/login/SmsSendRequestEntity.kt @@ -0,0 +1,5 @@ +package com.meongmoryteam.domain.model.reqeust.login + +data class SmsSendRequestEntity( + val phone: String +) diff --git a/domain/src/main/java/com/meongmoryteam/domain/model/reqeust/login/SmsValidateRequestEntity.kt b/domain/src/main/java/com/meongmoryteam/domain/model/reqeust/login/SmsValidateRequestEntity.kt new file mode 100644 index 0000000..0a6b7e8 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/model/reqeust/login/SmsValidateRequestEntity.kt @@ -0,0 +1,6 @@ +package com.meongmoryteam.domain.model.reqeust.login + +data class SmsValidateRequestEntity( + val code: String, + val phone: String +) diff --git a/domain/src/main/java/com/meongmoryteam/domain/model/response/login/GetSmsSendEntity.kt b/domain/src/main/java/com/meongmoryteam/domain/model/response/login/GetSmsSendEntity.kt new file mode 100644 index 0000000..0d493e5 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/model/response/login/GetSmsSendEntity.kt @@ -0,0 +1,14 @@ +package com.meongmoryteam.domain.model.response.login + +data class GetSmsSendEntity( + val status: Int, + val code: String, + val message: String, + val getSmsSendData: GetSmsSendData, +) + +data class GetSmsSendData( + val value: String, + val message: String? +) + diff --git a/domain/src/main/java/com/meongmoryteam/domain/model/response/login/PostSmsValidateEntity.kt b/domain/src/main/java/com/meongmoryteam/domain/model/response/login/PostSmsValidateEntity.kt new file mode 100644 index 0000000..8a964c0 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/model/response/login/PostSmsValidateEntity.kt @@ -0,0 +1,8 @@ +package com.meongmoryteam.domain.model.response.login + +data class PostSmsValidateEntity( + val status: Int, + val code: String, + val message: String, + val data: Boolean, +) diff --git a/domain/src/main/java/com/meongmoryteam/domain/repository/FoodRepository.kt b/domain/src/main/java/com/meongmoryteam/domain/repository/FoodRepository.kt deleted file mode 100644 index 4f7627b..0000000 --- a/domain/src/main/java/com/meongmoryteam/domain/repository/FoodRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.meongmoryteam.domain.repository - -import com.meongmoryteam.domain.model.ResponseWeekFoodEntity - -interface FoodRepository { - suspend fun weekFood(area: String): Result -} \ No newline at end of file diff --git a/domain/src/main/java/com/meongmoryteam/domain/repository/login/LoginRepository.kt b/domain/src/main/java/com/meongmoryteam/domain/repository/login/LoginRepository.kt new file mode 100644 index 0000000..8cdfcc3 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/repository/login/LoginRepository.kt @@ -0,0 +1,11 @@ +package com.meongmoryteam.domain.repository.login + +import com.meongmoryteam.domain.model.response.login.GetSmsSendEntity +import com.meongmoryteam.domain.model.reqeust.login.SmsSendRequestEntity +import com.meongmoryteam.domain.model.reqeust.login.SmsValidateRequestEntity +import com.meongmoryteam.domain.model.response.login.PostSmsValidateEntity + +interface LoginRepository { + suspend fun getSmsSend(smsSendRequestEntity: SmsSendRequestEntity): Result + suspend fun postSmsValidate(smsValidateRequestEntity: SmsValidateRequestEntity): Result +} \ No newline at end of file diff --git a/domain/src/main/java/com/meongmoryteam/domain/usecase/GetWeekFoodUseCase.kt b/domain/src/main/java/com/meongmoryteam/domain/usecase/GetWeekFoodUseCase.kt deleted file mode 100644 index 346b03b..0000000 --- a/domain/src/main/java/com/meongmoryteam/domain/usecase/GetWeekFoodUseCase.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.meongmoryteam.domain.usecase - -import com.meongmoryteam.domain.repository.FoodRepository -import javax.inject.Inject - -class GetWeekFoodUseCase @Inject constructor( - private val foodRepository: FoodRepository -) { - suspend operator fun invoke(s : String) = foodRepository.weekFood(s) -} \ No newline at end of file diff --git a/domain/src/main/java/com/meongmoryteam/domain/usecase/login/GetSmsSendUseCase.kt b/domain/src/main/java/com/meongmoryteam/domain/usecase/login/GetSmsSendUseCase.kt new file mode 100644 index 0000000..f95e691 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/usecase/login/GetSmsSendUseCase.kt @@ -0,0 +1,11 @@ +package com.meongmoryteam.domain.usecase.login + +import com.meongmoryteam.domain.model.reqeust.login.SmsSendRequestEntity +import com.meongmoryteam.domain.repository.login.LoginRepository +import javax.inject.Inject + +class GetSmsSendUseCase @Inject constructor( + private val loginRepository: LoginRepository +) { + suspend operator fun invoke(smsSendRequestEntity: SmsSendRequestEntity) = loginRepository.getSmsSend(smsSendRequestEntity) +} \ No newline at end of file diff --git a/domain/src/main/java/com/meongmoryteam/domain/usecase/login/PostSmsValidateUseCase.kt b/domain/src/main/java/com/meongmoryteam/domain/usecase/login/PostSmsValidateUseCase.kt new file mode 100644 index 0000000..606a3a1 --- /dev/null +++ b/domain/src/main/java/com/meongmoryteam/domain/usecase/login/PostSmsValidateUseCase.kt @@ -0,0 +1,12 @@ +package com.meongmoryteam.domain.usecase.login + +import com.meongmoryteam.domain.model.reqeust.login.SmsValidateRequestEntity +import com.meongmoryteam.domain.repository.login.LoginRepository +import javax.inject.Inject + +class PostSmsValidateUseCase @Inject constructor( + private val loginRepository: LoginRepository +) { + suspend operator fun invoke(smsValidateRequestEntity: SmsValidateRequestEntity) + = loginRepository.postSmsValidate(smsValidateRequestEntity) +} \ No newline at end of file diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/ExampleFoodState.kt b/presentation/src/main/java/com/meongmoryteam/presentation/ExampleFoodState.kt deleted file mode 100644 index 02f34fa..0000000 --- a/presentation/src/main/java/com/meongmoryteam/presentation/ExampleFoodState.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.meongmoryteam.presentation - -import com.meongmoryteam.domain.model.ResponseWeekFoodEntity - -sealed class ExampleFoodState { - object UnInitialized : ExampleFoodState() - - object Loading : ExampleFoodState() - - data class SuccessWeekFoodGetData(val getWeekFoodData: ResponseWeekFoodEntity) : ExampleFoodState() - - data class Error(val errorCode: Throwable) : ExampleFoodState() -} \ No newline at end of file diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/MainViewModel.kt b/presentation/src/main/java/com/meongmoryteam/presentation/MainViewModel.kt deleted file mode 100644 index 1fc7896..0000000 --- a/presentation/src/main/java/com/meongmoryteam/presentation/MainViewModel.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.meongmoryteam.presentation - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.meongmoryteam.domain.usecase.GetWeekFoodUseCase -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch -import javax.inject.Inject - -@HiltViewModel -class ExampleViewModel @Inject constructor( - private val getWeekFoodUseCase: GetWeekFoodUseCase -) : ViewModel() { - - private val _weekGetFoodArea = MutableStateFlow(ExampleFoodState.UnInitialized) - val weekGetFoodArea: StateFlow = _weekGetFoodArea.asStateFlow() - - fun getWeekFood(area: String) { - viewModelScope.launch { - getWeekFoodUseCase(area).onSuccess { - _weekGetFoodArea.emit(ExampleFoodState.SuccessWeekFoodGetData(it)) - }.onFailure { - _weekGetFoodArea.emit(ExampleFoodState.Error(it)) - } - } - } -} \ No newline at end of file diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/base/CommonText.kt b/presentation/src/main/java/com/meongmoryteam/presentation/base/CommonText.kt index 005fecd..4629355 100644 --- a/presentation/src/main/java/com/meongmoryteam/presentation/base/CommonText.kt +++ b/presentation/src/main/java/com/meongmoryteam/presentation/base/CommonText.kt @@ -53,7 +53,8 @@ fun TextButtonComponent( style: TextStyle, width: Float = 1f, modifier: Modifier = Modifier, - onClick: () -> Unit + enabled: Boolean = true, + onClick: () -> Unit, ) { TextButton( onClick = onClick, @@ -63,6 +64,7 @@ fun TextButtonComponent( .height(50.dp) .padding(vertical = 5.dp), colors = colors, + enabled = enabled ) { Text( diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginActivity.kt b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginActivity.kt index ae5ba92..83357f7 100644 --- a/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginActivity.kt +++ b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginActivity.kt @@ -19,7 +19,7 @@ class LoginActivity : ComponentActivity() { private fun setUnivSelectScreen() { setContent { MeongmoryTheme { - + LoginScreen() } } } diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginContract.kt b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginContract.kt new file mode 100644 index 0000000..c8c0c8a --- /dev/null +++ b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginContract.kt @@ -0,0 +1,31 @@ +package com.meongmoryteam.presentation.ui.login + +import com.meongmoryteam.presentation.base.LoadState +import com.meongmoryteam.presentation.base.ViewEvent +import com.meongmoryteam.presentation.base.ViewSideEffect +import com.meongmoryteam.presentation.base.ViewState +import com.meongmoryteam.presentation.ui.register_dog.RegisterDogContract + +class LoginContract { + data class LoginState( + val getSmsSendLoadState: LoadState = LoadState.SUCCESS, + val phoneNumber: String = "", + val certificationNumber: String = "", + val getCertificationNumber: String = "", + val isCertification: Boolean = false, + ): ViewState + + sealed class LoginEvent : ViewEvent { + object GetCertificationButtonClicked : LoginEvent() + object PostCertificationButtonClicked : LoginEvent() + object ToTermScreenButtonClicked : LoginEvent() + data class OnPhoneChanged(val phoneNumber: String) : LoginEvent() + data class OnCertificationNumberChanged(val certificationNumber: String) : LoginEvent() + } + + sealed class LoginEffect : ViewSideEffect { + object MoveToTerm: LoginEffect() + object SuccessCertification: LoginEffect() + object FailCertification: LoginEffect() + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginScreen.kt b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginScreen.kt new file mode 100644 index 0000000..58de1f6 --- /dev/null +++ b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginScreen.kt @@ -0,0 +1,221 @@ +package com.meongmoryteam.presentation.ui.login + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.Snackbar +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import com.meongmoryteam.presentation.R +import com.meongmoryteam.presentation.base.TextButtonComponent +import com.meongmoryteam.presentation.base.TextFieldComponent +import com.meongmoryteam.presentation.ui.theme.ButtonContent +import com.meongmoryteam.presentation.ui.theme.DarkGrey +import com.meongmoryteam.presentation.ui.theme.LightGrey +import com.meongmoryteam.presentation.ui.theme.NotoSansKR +import com.meongmoryteam.presentation.ui.theme.Orange +import com.meongmoryteam.presentation.ui.theme.Typography +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +@Composable +fun LoginScreen( + loginViewModel: LoginViewModel = hiltViewModel(), +) { + val loginViewState by loginViewModel.viewState.collectAsState() + + Column( + modifier = Modifier + .fillMaxSize() + .background(Color.White) + ) { + LoginPhoneCertTitle() + LoginPhoneTextField() + Spacer(modifier = Modifier.weight(1f)) + TextButtonComponent( + text = stringResource(R.string.login_phone_login_next_button), + colors = if (!loginViewState.isCertification) { + ButtonDefaults.textButtonColors(LightGrey) + } else { + ButtonDefaults.textButtonColors(Orange) + }, + style = TextStyle( + fontFamily = NotoSansKR, + fontWeight = FontWeight.W500, + fontSize = 15.sp, + lineHeight = 20.sp, + color = ButtonContent, + platformStyle = PlatformTextStyle(includeFontPadding = false) + ), + enabled = loginViewState.isCertification, + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + .padding(horizontal = 16.dp), + ) { + + } + } + + LaunchedEffect(key1 = loginViewModel.effect) { + loginViewModel.effect.collect { effect -> + when (effect) { + is LoginContract.LoginEffect.MoveToTerm -> { + + } + is LoginContract.LoginEffect.FailCertification -> { + /* + 인증 실패 스낵바 기획 논의 + */ + } + is LoginContract.LoginEffect.SuccessCertification -> { + /* + 인증 성공 스낵바 기획 논의 + */ + } + } + } + } +} + +@Composable +fun LoginPhoneCertTitle() { + Icon( + modifier = Modifier.padding(12.dp), + painter = painterResource(R.drawable.ic_left_btn), + contentDescription = stringResource(R.string.login_back_button), + ) + Spacer(modifier = Modifier.padding(30.dp)) + + Text( + modifier = Modifier.padding(start = 16.dp), + text = stringResource(R.string.login_phone_screen_title), + fontSize = 20.sp, + color = Color.Black, + fontWeight = FontWeight.SemiBold + ) + Spacer(modifier = Modifier.padding(6.dp)) + + Text( + modifier = Modifier.padding(start = 16.dp), + text = stringResource(R.string.login_phone_screen_sub_title), + color = DarkGrey, + style = Typography.titleSmall + ) + Spacer(modifier = Modifier.padding(32.dp)) +} + +@Composable +fun LoginPhoneTextField( + loginViewModel: LoginViewModel = hiltViewModel(), +) { + val loginViewState by loginViewModel.viewState.collectAsState() + + Text( + modifier = Modifier.padding(start = 16.dp), + text = stringResource(R.string.login_phone), + color = DarkGrey, + style = Typography.titleSmall + ) + Spacer(modifier = Modifier.padding(10.dp)) + + TextFieldComponent( + name = loginViewState.phoneNumber, + placeholder = stringResource(R.string.login_phone_text_field_hint), + modifier = Modifier + .fillMaxWidth() + .height(37.dp) + .padding(horizontal = 16.dp), + onValueChange = { loginViewModel.setEvent(LoginContract.LoginEvent.OnPhoneChanged(it.trim())) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) + ) + Spacer(modifier = Modifier.padding(6.dp)) + + TextButtonComponent( + text = stringResource(R.string.login_phone_get_certification_button), + colors = if (loginViewState.phoneNumber.length != 11) { + ButtonDefaults.textButtonColors(LightGrey) + } else { + ButtonDefaults.textButtonColors(Orange) + }, + style = TextStyle( + fontFamily = NotoSansKR, + fontWeight = FontWeight.W500, + fontSize = 15.sp, + lineHeight = 20.sp, + color = ButtonContent, + platformStyle = PlatformTextStyle(includeFontPadding = false) + ), + enabled = loginViewState.phoneNumber.length == 11, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) { + loginViewModel.setEvent(LoginContract.LoginEvent.GetCertificationButtonClicked) + } + Spacer(modifier = Modifier.padding(20.dp)) + + TextFieldComponent( + name = loginViewState.certificationNumber, + placeholder = stringResource(R.string.login_certification_text_field_hint), + modifier = Modifier + .fillMaxWidth() + .height(37.dp) + .padding(horizontal = 16.dp), + onValueChange = { loginViewModel.setEvent(LoginContract.LoginEvent.OnCertificationNumberChanged(it)) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) + ) + Spacer(modifier = Modifier.padding(6.dp)) + + TextButtonComponent( + text = stringResource(R.string.login_phone_post_certification_button), + colors = if (loginViewState.certificationNumber.length != 5) { + ButtonDefaults.textButtonColors(LightGrey) + } else { + ButtonDefaults.textButtonColors(Orange) + }, + style = TextStyle( + fontFamily = NotoSansKR, + fontWeight = FontWeight.W500, + fontSize = 15.sp, + lineHeight = 20.sp, + color = ButtonContent, + platformStyle = PlatformTextStyle(includeFontPadding = false) + ), + enabled = loginViewState.certificationNumber.length == 5, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) { + loginViewModel.setEvent(LoginContract.LoginEvent.PostCertificationButtonClicked) + } +} + +@Preview +@Composable +fun LoginScreenPreview() { + LoginScreen() +} \ No newline at end of file diff --git a/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginViewModel.kt b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginViewModel.kt new file mode 100644 index 0000000..218b5f2 --- /dev/null +++ b/presentation/src/main/java/com/meongmoryteam/presentation/ui/login/LoginViewModel.kt @@ -0,0 +1,93 @@ +package com.meongmoryteam.presentation.ui.login + +import androidx.lifecycle.viewModelScope +import com.meongmoryteam.domain.model.reqeust.login.SmsSendRequestEntity +import com.meongmoryteam.domain.model.reqeust.login.SmsValidateRequestEntity +import com.meongmoryteam.domain.usecase.login.GetSmsSendUseCase +import com.meongmoryteam.domain.usecase.login.PostSmsValidateUseCase +import com.meongmoryteam.presentation.base.BaseViewModel +import com.meongmoryteam.presentation.base.LoadState +import com.meongmoryteam.presentation.ui.login.LoginContract.LoginEffect +import com.meongmoryteam.presentation.ui.login.LoginContract.LoginEvent +import com.meongmoryteam.presentation.ui.login.LoginContract.LoginState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class LoginViewModel @Inject constructor( + private val getSmsSendUseCase: GetSmsSendUseCase, + private val postSmsSendUseCase: PostSmsValidateUseCase +): BaseViewModel( + LoginState() +) { + override fun handleEvents(event: LoginEvent) { + when(event) { + is LoginEvent.GetCertificationButtonClicked -> { + updateState { copy(getSmsSendLoadState = LoadState.LOADING) } + getSmsSend() + } + is LoginEvent.PostCertificationButtonClicked -> { + postSmsSend() + } + is LoginEvent.ToTermScreenButtonClicked -> { + sendEffect({ LoginEffect.MoveToTerm }) + } + is LoginEvent.OnPhoneChanged -> reflectUpdateState(phoneNumber = event.phoneNumber) + is LoginEvent.OnCertificationNumberChanged -> reflectUpdateState(certificationNumber = event.certificationNumber) + } + } + + private fun getSmsSend() { + val smsSendRequest = SmsSendRequestEntity( + viewState.value.phoneNumber + ) + viewModelScope.launch { + getSmsSendUseCase(smsSendRequest).onSuccess { + updateState { + copy( + getSmsSendLoadState = LoadState.SUCCESS, + getCertificationNumber = it.getSmsSendData.value + ) + } + }.onFailure { + updateState { + copy( + getSmsSendLoadState = LoadState.ERROR, + ) + } + } + } + } + + private fun postSmsSend() { + val smsValidRequest = SmsValidateRequestEntity( + viewState.value.certificationNumber, + viewState.value.phoneNumber + ) + viewModelScope.launch { + postSmsSendUseCase(smsValidRequest).onSuccess { + updateState { + copy( + isCertification = true + ) + } + sendEffect({ LoginEffect.SuccessCertification }) + }.onFailure { + sendEffect({ LoginEffect.FailCertification }) + } + } + } + + private fun reflectUpdateState( + phoneNumber: String = viewState.value.phoneNumber, + certificationNumber: String = viewState.value.certificationNumber + ) { + updateState { + copy( + phoneNumber = phoneNumber, + certificationNumber = certificationNumber + ) + } + } +} \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 04b8e52..b2d5d21 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -102,5 +102,16 @@ 휴대폰 번호로 시작하기 펫다이어리 로고 전화 + 로그인 화면 닫기 버튼 + 안녕하세요!\n휴대폰 번호로 로그인 해주세요! + 휴대폰 번호는 안전하게 보관되어\n이웃에게 공개되지 않아요. + 휴대폰 번호 + -없이 숫자만 입력 + 인증번호 받기 + 인증번호 입력 + 인증 요청 + 다음 + + 네트워크 에러가 발생하였습니다. \ No newline at end of file