diff --git a/app/build.gradle b/app/build.gradle index 511113c..c59d17b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,6 +3,9 @@ plugins { id 'org.jetbrains.kotlin.android' id "kotlin-parcelize" id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.0' + id 'com.google.dagger.hilt.android' + id 'kotlin-android' + id 'com.google.devtools.ksp' } Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) @@ -66,4 +69,8 @@ dependencies { // define any required OkHttp artifacts without version implementation("com.squareup.okhttp3:okhttp") implementation("com.squareup.okhttp3:logging-interceptor") + + //hlit + implementation 'com.google.dagger:hilt-android:2.51' + ksp 'com.google.dagger:hilt-compiler:2.51.1' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 11c7435..3a58c0d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ create(): T = retrofit.create(T::class.java) -} - -object ServicePool { - val authService: AuthService by lazy { create() } - val infoService: InfoService by lazy { create() } -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/api/AuthService.kt b/app/src/main/java/com/sopt/now/data/api/AuthService.kt index 87b9dbe..6c341a3 100644 --- a/app/src/main/java/com/sopt/now/data/api/AuthService.kt +++ b/app/src/main/java/com/sopt/now/data/api/AuthService.kt @@ -1,24 +1,29 @@ package com.sopt.now.data.api -import com.sopt.now.data.datasouce.request.RequestLoginDto -import com.sopt.now.data.datasouce.request.RequestSignUpDto -import com.sopt.now.data.datasouce.response.BaseResponse -import com.sopt.now.data.datasouce.response.ResponseLoginDto -import com.sopt.now.data.datasouce.response.ResponseSignUpDto -import retrofit2.Call +import com.sopt.now.data.dto.request.RequestLoginDto +import com.sopt.now.data.dto.request.RequestSignUpDto +import com.sopt.now.data.dto.response.BaseResponse +import com.sopt.now.data.dto.response.ResponseInfoDto import retrofit2.Response import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header import retrofit2.http.POST interface AuthService { @POST("member/join") suspend fun signUp( @Body request: RequestSignUpDto, - ): Response> + ): BaseResponse @POST("member/login") - fun login( + suspend fun login( @Body request: RequestLoginDto, - ): Call> + ): Response> + + @GET("/member/info") + suspend fun getUserInfo( + @Header("memberid") userId: String, + ): Response } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/api/InfoService.kt b/app/src/main/java/com/sopt/now/data/api/InfoService.kt deleted file mode 100644 index 98bb2a8..0000000 --- a/app/src/main/java/com/sopt/now/data/api/InfoService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.sopt.now.data.api - -import com.sopt.now.data.datasouce.response.ResponseInfoDto -import retrofit2.Call -import retrofit2.http.GET -import retrofit2.http.Header - -interface InfoService { - @GET("/member/info") - fun getUserInfo( - @Header("memberid") userId: String, - ): Call -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseInfoDto.kt b/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseInfoDto.kt deleted file mode 100644 index bf9fd39..0000000 --- a/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseInfoDto.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.sopt.now.data.datasouce.response - -import com.sopt.now.data.model.User -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ResponseInfoDto( - @SerialName("code") - val code: Int, - @SerialName("message") - val message: String, - @SerialName("data") - val data: UserData -) - -@Serializable -data class UserData( - @SerialName("authenticationId") - val authenticationId: String, - @SerialName("nickname") - val nickname: String, - @SerialName("phone") - val phone: String, -) { - fun toUser() = User(id = authenticationId, password = "", nickname = nickname, phoneNumber = phone) -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseLoginDto.kt b/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseLoginDto.kt deleted file mode 100644 index 3eb105e..0000000 --- a/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseLoginDto.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.sopt.now.data.datasouce.response - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ResponseLoginDto( - @SerialName("code") - val code: Int, - @SerialName("message") - val message: String, -) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseSignUpDto.kt b/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseSignUpDto.kt deleted file mode 100644 index d3e15d8..0000000 --- a/app/src/main/java/com/sopt/now/data/datasouce/response/ResponseSignUpDto.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.sopt.now.data.datasouce.response - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ResponseSignUpDto( - @SerialName("code") - val code: Int, - @SerialName("message") - val message: String, -) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/di/ApiModule.kt b/app/src/main/java/com/sopt/now/data/di/ApiModule.kt new file mode 100644 index 0000000..3495f7e --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/di/ApiModule.kt @@ -0,0 +1,34 @@ +package com.sopt.now.data.di + +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import com.sopt.now.BuildConfig +import com.sopt.now.data.api.AuthService +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import retrofit2.Retrofit +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object ApiModule { + private const val CONTENT_TYPE = "application/json" + + @Singleton + @Provides + fun provideRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl(BuildConfig.AUTH_BASE_URL) + .addConverterFactory(Json.asConverterFactory(CONTENT_TYPE.toMediaType())) + .build() + } + + @Singleton + @Provides + fun provideAuthService(retrofit: Retrofit): AuthService { + return retrofit.create(AuthService::class.java) + } +} diff --git a/app/src/main/java/com/sopt/now/data/di/DataModule.kt b/app/src/main/java/com/sopt/now/data/di/DataModule.kt new file mode 100644 index 0000000..050f9af --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/di/DataModule.kt @@ -0,0 +1,21 @@ +package com.sopt.now.data.di + +import com.sopt.now.data.repositoryimpl.AuthRepositoryImpl +import com.sopt.now.domain.repository.AuthRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + + +@Module +@InstallIn(SingletonComponent::class) +abstract class DataModule { + + @Binds + @Singleton + abstract fun bindAuthRepository( + authRepositoryImpl: AuthRepositoryImpl + ): AuthRepository +} diff --git a/app/src/main/java/com/sopt/now/data/dto/Mapper.kt b/app/src/main/java/com/sopt/now/data/dto/Mapper.kt new file mode 100644 index 0000000..b122e5d --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/dto/Mapper.kt @@ -0,0 +1,35 @@ +package com.sopt.now.data.dto + +import com.sopt.now.data.dto.request.RequestLoginDto +import com.sopt.now.data.dto.request.RequestSignUpDto +import com.sopt.now.data.dto.response.BaseResponse +import com.sopt.now.data.dto.response.ResponseInfoDto +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.entity.BaseResponseEntity + +internal fun UserEntity.toRequestLoginDto(): RequestLoginDto = + RequestLoginDto( + authenticationId = authenticationId, + password = password + ) + +internal fun UserEntity.toRequestSignUpDto(): RequestSignUpDto = + RequestSignUpDto( + authenticationId = authenticationId, + password = password, + nickname = nickname, + phone = phone + ) + +internal fun BaseResponse.toBaseResponseEntity(): BaseResponseEntity = + BaseResponseEntity( + code = this.code, + message = this.message + ) + +internal fun ResponseInfoDto.UserData.toUserEntity(): UserEntity = UserEntity( + authenticationId = authenticationId, + password = "", + nickname = nickname, + phone = phone +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/datasouce/request/RequestLoginDto.kt b/app/src/main/java/com/sopt/now/data/dto/request/RequestLoginDto.kt similarity index 85% rename from app/src/main/java/com/sopt/now/data/datasouce/request/RequestLoginDto.kt rename to app/src/main/java/com/sopt/now/data/dto/request/RequestLoginDto.kt index 2923c1d..6366a15 100644 --- a/app/src/main/java/com/sopt/now/data/datasouce/request/RequestLoginDto.kt +++ b/app/src/main/java/com/sopt/now/data/dto/request/RequestLoginDto.kt @@ -1,4 +1,4 @@ -package com.sopt.now.data.datasouce.request +package com.sopt.now.data.dto.request import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/sopt/now/data/datasouce/request/RequestSignUpDto.kt b/app/src/main/java/com/sopt/now/data/dto/request/RequestSignUpDto.kt similarity index 58% rename from app/src/main/java/com/sopt/now/data/datasouce/request/RequestSignUpDto.kt rename to app/src/main/java/com/sopt/now/data/dto/request/RequestSignUpDto.kt index 1e66bf9..6610d27 100644 --- a/app/src/main/java/com/sopt/now/data/datasouce/request/RequestSignUpDto.kt +++ b/app/src/main/java/com/sopt/now/data/dto/request/RequestSignUpDto.kt @@ -1,6 +1,5 @@ -package com.sopt.now.data.datasouce.request +package com.sopt.now.data.dto.request -import com.sopt.now.data.model.User import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -14,7 +13,4 @@ data class RequestSignUpDto( val nickname: String, @SerialName("phone") val phone: String, -) { - fun toUserWithUserId(userid: String): User = - User(id = authenticationId, password = password, nickname = nickname, phoneNumber = phone, userId = userid) -} \ No newline at end of file +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/datasouce/response/BaseResponse.kt b/app/src/main/java/com/sopt/now/data/dto/response/BaseResponse.kt similarity index 85% rename from app/src/main/java/com/sopt/now/data/datasouce/response/BaseResponse.kt rename to app/src/main/java/com/sopt/now/data/dto/response/BaseResponse.kt index 4d12f8c..bf15681 100644 --- a/app/src/main/java/com/sopt/now/data/datasouce/response/BaseResponse.kt +++ b/app/src/main/java/com/sopt/now/data/dto/response/BaseResponse.kt @@ -1,4 +1,4 @@ -package com.sopt.now.data.datasouce.response +package com.sopt.now.data.dto.response import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/sopt/now/data/dto/response/ResponseInfoDto.kt b/app/src/main/java/com/sopt/now/data/dto/response/ResponseInfoDto.kt new file mode 100644 index 0000000..57c6c03 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/dto/response/ResponseInfoDto.kt @@ -0,0 +1,25 @@ +package com.sopt.now.data.dto.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ResponseInfoDto( + @SerialName("code") + val code: Int, + @SerialName("message") + val message: String, + @SerialName("data") + val data: UserData +){ + @Serializable + data class UserData( + @SerialName("authenticationId") + val authenticationId: String, + @SerialName("nickname") + val nickname: String, + @SerialName("phone") + val phone: String, + ) +} + diff --git a/app/src/main/java/com/sopt/now/data/repositoryimpl/AuthRepositoryImpl.kt b/app/src/main/java/com/sopt/now/data/repositoryimpl/AuthRepositoryImpl.kt new file mode 100644 index 0000000..ded6088 --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/repositoryimpl/AuthRepositoryImpl.kt @@ -0,0 +1,48 @@ +package com.sopt.now.data.repositoryimpl + +import com.sopt.now.data.api.AuthService +import com.sopt.now.data.dto.response.BaseResponse +import com.sopt.now.data.dto.toBaseResponseEntity +import com.sopt.now.data.dto.toRequestLoginDto +import com.sopt.now.data.dto.toRequestSignUpDto +import com.sopt.now.data.dto.toUserEntity +import com.sopt.now.data.repositoryimpl.extension.getResponseErrorMessage +import com.sopt.now.data.repositoryimpl.extension.handleThrowable +import com.sopt.now.domain.entity.ApiError +import com.sopt.now.domain.entity.BaseResponseEntity +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.repository.AuthRepository +import retrofit2.Response +import javax.inject.Inject + +class AuthRepositoryImpl @Inject constructor( + private val authService: AuthService +) : + AuthRepository { + override suspend fun login(authData: UserEntity): Result = + runCatching { + val response: Response> = + authService.login(authData.toRequestLoginDto()) + if (response.isSuccessful) { + response.headers()["location"]?.toInt() + } else { + throw ApiError(response.getResponseErrorMessage()) + } + } + + override suspend fun signUp(authData: UserEntity): Result { + return runCatching { + authService.signUp(authData.toRequestSignUpDto()).toBaseResponseEntity() + }.onFailure { throwable -> + return throwable.handleThrowable() + } + } + + override suspend fun getMemberInfo(userid: String): Result = + runCatching { + authService.getUserInfo(userid).body()?.data?.toUserEntity() + ?: throw Exception("data is null") + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/repositoryimpl/extension/getErrorMessage.kt b/app/src/main/java/com/sopt/now/data/repositoryimpl/extension/getErrorMessage.kt new file mode 100644 index 0000000..dc99fef --- /dev/null +++ b/app/src/main/java/com/sopt/now/data/repositoryimpl/extension/getErrorMessage.kt @@ -0,0 +1,35 @@ +package com.sopt.now.data.repositoryimpl.extension + +import com.sopt.now.data.dto.response.BaseResponse +import com.sopt.now.domain.entity.ApiError +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import retrofit2.HttpException +import retrofit2.Response + +fun Throwable.getErrorMessage(): String { + return when (this) { + is HttpException -> { + val errorBody = response()?.errorBody()?.string() ?: return "Unknown error" + val errorResponse = Json.decodeFromString>(errorBody) + errorResponse.message + } + + else -> "An unknown error occurred." + } +} + +fun Throwable.handleThrowable(): Result { + return Result.failure( + when (this) { + is HttpException -> ApiError(this.getErrorMessage()) + else -> this + } + ) +} + +fun Response<*>?.getResponseErrorMessage(): String { + val errorBody = this?.errorBody()?.string() ?: return "Unknown error" + val errorResponse = Json.decodeFromString>(errorBody) + return errorResponse.message +} diff --git a/app/src/main/java/com/sopt/now/domain/entity/ApiError.kt b/app/src/main/java/com/sopt/now/domain/entity/ApiError.kt new file mode 100644 index 0000000..89f2fc6 --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/entity/ApiError.kt @@ -0,0 +1,5 @@ +package com.sopt.now.domain.entity + +data class ApiError( + val errorMessage: String? +) : Exception(errorMessage) diff --git a/app/src/main/java/com/sopt/now/domain/entity/BaseResponseEntity.kt b/app/src/main/java/com/sopt/now/domain/entity/BaseResponseEntity.kt new file mode 100644 index 0000000..9c5d374 --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/entity/BaseResponseEntity.kt @@ -0,0 +1,6 @@ +package com.sopt.now.domain.entity + +data class BaseResponseEntity( + val code: Int, + val message: String +) diff --git a/app/src/main/java/com/sopt/now/domain/entity/UserEntity.kt b/app/src/main/java/com/sopt/now/domain/entity/UserEntity.kt new file mode 100644 index 0000000..9fd5287 --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/entity/UserEntity.kt @@ -0,0 +1,9 @@ +package com.sopt.now.domain.entity + + +data class UserEntity( + val authenticationId: String, + val password: String, + val nickname: String, + val phone: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/domain/repository/AuthRepository.kt b/app/src/main/java/com/sopt/now/domain/repository/AuthRepository.kt new file mode 100644 index 0000000..aff40dc --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/repository/AuthRepository.kt @@ -0,0 +1,10 @@ +package com.sopt.now.domain.repository + +import com.sopt.now.domain.entity.BaseResponseEntity +import com.sopt.now.domain.entity.UserEntity + +interface AuthRepository { + suspend fun login(authData: UserEntity): Result + suspend fun signUp(authData: UserEntity): Result + suspend fun getMemberInfo(userid:String): Result +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/domain/usecase/GetUserInfoUseCase.kt b/app/src/main/java/com/sopt/now/domain/usecase/GetUserInfoUseCase.kt new file mode 100644 index 0000000..d2cc6d9 --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/usecase/GetUserInfoUseCase.kt @@ -0,0 +1,12 @@ +package com.sopt.now.domain.usecase + +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.repository.AuthRepository +import javax.inject.Inject + +class GetUserInfoUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke(userid: String): Result = + authRepository.getMemberInfo(userid) +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/domain/usecase/LogInUseCase.kt b/app/src/main/java/com/sopt/now/domain/usecase/LogInUseCase.kt new file mode 100644 index 0000000..60844fd --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/usecase/LogInUseCase.kt @@ -0,0 +1,13 @@ +package com.sopt.now.domain.usecase + +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.repository.AuthRepository +import javax.inject.Inject + +class LogInUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + + suspend operator fun invoke(request: UserEntity): Result = + authRepository.login(request) +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/domain/usecase/SignUpUseCase.kt b/app/src/main/java/com/sopt/now/domain/usecase/SignUpUseCase.kt new file mode 100644 index 0000000..3189cb8 --- /dev/null +++ b/app/src/main/java/com/sopt/now/domain/usecase/SignUpUseCase.kt @@ -0,0 +1,14 @@ +package com.sopt.now.domain.usecase + +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.entity.BaseResponseEntity +import com.sopt.now.domain.repository.AuthRepository +import javax.inject.Inject + +class SignUpUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + + suspend operator fun invoke(request: UserEntity): Result = + authRepository.signUp(request) +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/ui/login/LoginActivity.kt b/app/src/main/java/com/sopt/now/ui/login/LoginActivity.kt index 94ebe10..1db6f3f 100644 --- a/app/src/main/java/com/sopt/now/ui/login/LoginActivity.kt +++ b/app/src/main/java/com/sopt/now/ui/login/LoginActivity.kt @@ -6,19 +6,21 @@ import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import com.sopt.now.R -import com.sopt.now.data.model.User -import com.sopt.now.data.datasouce.request.RequestLoginDto +import com.sopt.now.ui.model.User import com.sopt.now.databinding.ActivityLoginBinding +import com.sopt.now.domain.entity.UserEntity import com.sopt.now.ui.main.MainActivity import com.sopt.now.ui.signup.SignUpActivity import com.sopt.now.util.BindingActivity import com.sopt.now.util.UiState import com.sopt.now.util.getSafeParcelable import com.sopt.now.util.toast +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class LoginActivity : BindingActivity(R.layout.activity_login) { private lateinit var resultLauncher: ActivityResultLauncher - private val viewModel by viewModels() + private val viewModel: LoginViewModel by viewModels() private lateinit var user: User override fun onCreate(savedInstanceState: Bundle?) { @@ -79,14 +81,16 @@ class LoginActivity : BindingActivity(R.layout.activity_lo private fun initLoginBtnClickListener() { binding.btnLogin.setOnClickListener { - viewModel.login(getLoginRequestDto()) + viewModel.login(getLoginRequest()) } } - private fun getLoginRequestDto() = - RequestLoginDto( + private fun getLoginRequest() = + UserEntity( authenticationId = binding.etLoginId.text.toString(), - password = binding.etLoginPassword.text.toString() + password = binding.etLoginPassword.text.toString(), + nickname = "", + phone = "" ) companion object { diff --git a/app/src/main/java/com/sopt/now/ui/login/LoginViewModel.kt b/app/src/main/java/com/sopt/now/ui/login/LoginViewModel.kt index acb5e3c..070f498 100644 --- a/app/src/main/java/com/sopt/now/ui/login/LoginViewModel.kt +++ b/app/src/main/java/com/sopt/now/ui/login/LoginViewModel.kt @@ -1,58 +1,44 @@ package com.sopt.now.ui.login +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.sopt.now.data.api.ServicePool -import com.sopt.now.data.datasouce.request.RequestLoginDto -import com.sopt.now.data.datasouce.response.BaseResponse -import com.sopt.now.data.model.User -import com.sopt.now.util.StringNetworkError.FAIL_ERROR -import com.sopt.now.util.StringNetworkError.LOGIN -import com.sopt.now.util.StringNetworkError.SERVER_ERROR +import androidx.lifecycle.viewModelScope +import com.sopt.now.ui.model.User +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.usecase.LogInUseCase import com.sopt.now.util.UiState -import org.json.JSONObject -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject -class LoginViewModel : ViewModel() { - private val loginService by lazy { ServicePool.authService } +@HiltViewModel +class LoginViewModel @Inject constructor( + private val logInUseCase: LogInUseCase +) : ViewModel() { private val _loginState = MutableLiveData>() - val loginState = _loginState + val loginState: LiveData> = _loginState - fun login(request: RequestLoginDto) { + fun login(request: UserEntity) { _loginState.value = UiState.Loading - - loginService.login(request).enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - _loginState.value = UiState.Success( - User( - request.authenticationId, - request.password, - "", - "", - userId = response.headers()["location"].toString() + viewModelScope.launch { + logInUseCase(request) + .onSuccess { response -> + _loginState.value = + UiState.Success( + User( + request.authenticationId, + request.password, + "", + "", + userId = response.toString() + ) ) - ) - } else { - val error = response.errorBody()?.string() - try { - val errorJson = JSONObject(error) - val errorMessage = errorJson.getString("message") - _loginState.value = UiState.Error(errorMessage) - } catch (e: Exception) { - _loginState.value = UiState.Error(FAIL_ERROR.format(LOGIN)) - } } - } - - override fun onFailure(call: Call>, t: Throwable) { - _loginState.value = UiState.Error(SERVER_ERROR) - } - }) + .onFailure { e -> + _loginState.value = UiState.Error(e.message.toString()) + } + } } } + diff --git a/app/src/main/java/com/sopt/now/ui/main/MainActivity.kt b/app/src/main/java/com/sopt/now/ui/main/MainActivity.kt index 9a334cb..c0d601d 100644 --- a/app/src/main/java/com/sopt/now/ui/main/MainActivity.kt +++ b/app/src/main/java/com/sopt/now/ui/main/MainActivity.kt @@ -4,7 +4,7 @@ import android.os.Bundle import androidx.activity.viewModels import androidx.fragment.app.Fragment import com.sopt.now.R -import com.sopt.now.data.model.User +import com.sopt.now.ui.model.User import com.sopt.now.databinding.ActivityMainBinding import com.sopt.now.ui.login.LoginActivity.Companion.TAG_USER import com.sopt.now.ui.main.home.MainHomeFragment @@ -14,9 +14,11 @@ import com.sopt.now.util.BindingActivity import com.sopt.now.util.UiState import com.sopt.now.util.getSafeParcelable import com.sopt.now.util.toast +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class MainActivity : BindingActivity(R.layout.activity_main) { - private val viewModel by viewModels() + private val viewModel: MainViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -38,7 +40,6 @@ class MainActivity : BindingActivity(R.layout.activity_main viewModel.setMyProfile(state.data) viewModel.updateProfileWithMyProfile() } - is UiState.Error -> toast(state.errorMessage) } diff --git a/app/src/main/java/com/sopt/now/ui/main/MainViewModel.kt b/app/src/main/java/com/sopt/now/ui/main/MainViewModel.kt index 74051dc..492df15 100644 --- a/app/src/main/java/com/sopt/now/ui/main/MainViewModel.kt +++ b/app/src/main/java/com/sopt/now/ui/main/MainViewModel.kt @@ -1,29 +1,32 @@ package com.sopt.now.ui.main +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.sopt.now.data.api.ServicePool.infoService -import com.sopt.now.data.datasouce.response.ResponseInfoDto +import androidx.lifecycle.viewModelScope import com.sopt.now.data.model.Profile -import com.sopt.now.data.model.User +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.usecase.GetUserInfoUseCase import com.sopt.now.util.StringNetworkError.FAIL_ERROR import com.sopt.now.util.StringNetworkError.LOGIN -import com.sopt.now.util.StringNetworkError.SERVER_ERROR import com.sopt.now.util.UiState -import org.json.JSONObject -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import retrofit2.HttpException +import javax.inject.Inject -class MainViewModel : ViewModel() { - private val _userData = MutableLiveData>() - val userData = _userData +@HiltViewModel +class MainViewModel @Inject constructor( + private val getUserInfoUseCase: GetUserInfoUseCase +) : ViewModel() { + private val _userData: MutableLiveData> = MutableLiveData() + val userData: LiveData> = _userData - private val _myInfo = MutableLiveData>() - val myInfo = _myInfo + private val _myInfo: MutableLiveData> = MutableLiveData() + val myInfo: LiveData> = _myInfo - private val _myProfile = MutableLiveData() - val myProfile = _myProfile + private val _myProfile: MutableLiveData = MutableLiveData() + val myProfile: LiveData = _myProfile init { _userData.value = @@ -35,40 +38,27 @@ class MainViewModel : ViewModel() { fun getInfo(userid: String) { _myInfo.value = UiState.Loading - infoService.getUserInfo(userid).enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response, - ) { - if (response.isSuccessful) { - val user = response.body()?.data - _myInfo.value = UiState.Success(user?.toUser() ?: User("", "", "", "")) + viewModelScope.launch { + getUserInfoUseCase(userid).onSuccess { response -> + _myInfo.value = UiState.Success(response) + }.onFailure { e -> + if (e is HttpException) { + _myInfo.value = UiState.Error(e.message()) } else { - val error = response.errorBody()?.string() - try { - val errorJson = JSONObject(error) - val errorMessage = errorJson.getString("message") - _myInfo.value = UiState.Error(errorMessage) - } catch (e: Exception) { - _myInfo.value = UiState.Error(FAIL_ERROR.format(LOGIN)) - } + _myInfo.value = UiState.Error(FAIL_ERROR.format(LOGIN)) } } - - override fun onFailure(call: Call, t: Throwable) { - _myInfo.value = UiState.Error(SERVER_ERROR) - } - }) + } } - fun setMyProfile(data: User) { + fun setMyProfile(data: UserEntity) { _myProfile.value = data } fun updateProfileWithMyProfile() { _userData.value = listOf( - Profile(_myProfile.value!!.nickname, _myProfile.value!!.phoneNumber), + Profile(_myProfile.value!!.nickname, _myProfile.value!!.phone), Profile("주효은", "INFP"), Profile("이유빈", "ENFP"), Profile("김민우", "ISTP"), diff --git a/app/src/main/java/com/sopt/now/ui/main/profile/MainProfileFragment.kt b/app/src/main/java/com/sopt/now/ui/main/profile/MainProfileFragment.kt index c6a7268..a31564a 100644 --- a/app/src/main/java/com/sopt/now/ui/main/profile/MainProfileFragment.kt +++ b/app/src/main/java/com/sopt/now/ui/main/profile/MainProfileFragment.kt @@ -19,10 +19,10 @@ class MainProfileFragment : private fun initLayout() { with(binding) { - tvMainIdContent.text = viewModel.myProfile.value?.id + tvMainIdContent.text = viewModel.myProfile.value?.authenticationId tvMainPasswordContent.text = viewModel.myProfile.value?.password tvMainNickname.text = getString(R.string.main_welcome).format(viewModel.myProfile.value?.nickname) - tvMainNumberContent.text = viewModel.myProfile.value?.phoneNumber + tvMainNumberContent.text = viewModel.myProfile.value?.phone } } } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/data/model/User.kt b/app/src/main/java/com/sopt/now/ui/model/User.kt similarity index 88% rename from app/src/main/java/com/sopt/now/data/model/User.kt rename to app/src/main/java/com/sopt/now/ui/model/User.kt index 7f5c2c0..67cdcf7 100644 --- a/app/src/main/java/com/sopt/now/data/model/User.kt +++ b/app/src/main/java/com/sopt/now/ui/model/User.kt @@ -1,4 +1,4 @@ -package com.sopt.now.data.model +package com.sopt.now.ui.model import android.os.Parcelable import kotlinx.android.parcel.Parcelize diff --git a/app/src/main/java/com/sopt/now/ui/signup/SignUpActivity.kt b/app/src/main/java/com/sopt/now/ui/signup/SignUpActivity.kt index c4bae2d..05468fa 100644 --- a/app/src/main/java/com/sopt/now/ui/signup/SignUpActivity.kt +++ b/app/src/main/java/com/sopt/now/ui/signup/SignUpActivity.kt @@ -1,21 +1,22 @@ package com.sopt.now.ui.signup -import SignUpViewModel import android.content.Intent import android.os.Bundle import androidx.activity.viewModels import com.sopt.now.R -import com.sopt.now.data.model.User -import com.sopt.now.data.datasouce.request.RequestSignUpDto +import com.sopt.now.ui.model.User import com.sopt.now.databinding.ActivitySignUpBinding +import com.sopt.now.domain.entity.UserEntity import com.sopt.now.ui.login.LoginActivity import com.sopt.now.ui.login.LoginActivity.Companion.TAG_USER import com.sopt.now.util.BindingActivity import com.sopt.now.util.UiState import com.sopt.now.util.toast +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class SignUpActivity : BindingActivity(R.layout.activity_sign_up) { - private val viewModel by viewModels() + private val viewModel: SignUpViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,10 +31,7 @@ class SignUpActivity : BindingActivity(R.layout.activity_ private fun initObserver() { viewModel.signUpState.observe(this) { state -> when (state) { - is UiState.Loading -> { - - } - + is UiState.Loading -> Unit is UiState.Success -> { toast("회원가입 성공 userid = ${state.data.userId} 입니다!") navToLogin(state.data) @@ -63,7 +61,7 @@ class SignUpActivity : BindingActivity(R.layout.activity_ finish() } - private fun getSignUpRequestDto() = RequestSignUpDto( + private fun getSignUpRequestDto() = UserEntity( authenticationId = binding.etSignupId.text.toString(), password = binding.etSignupPassword.text.toString(), nickname = binding.etSignupNickname.text.toString(), diff --git a/app/src/main/java/com/sopt/now/ui/signup/SignUpViewModel.kt b/app/src/main/java/com/sopt/now/ui/signup/SignUpViewModel.kt index 8fc14ea..dba22c3 100644 --- a/app/src/main/java/com/sopt/now/ui/signup/SignUpViewModel.kt +++ b/app/src/main/java/com/sopt/now/ui/signup/SignUpViewModel.kt @@ -1,45 +1,42 @@ +package com.sopt.now.ui.signup + +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.sopt.now.data.api.ServicePool -import com.sopt.now.data.datasouce.request.RequestSignUpDto -import com.sopt.now.data.datasouce.response.BaseResponse -import com.sopt.now.data.model.User -import com.sopt.now.util.StringNetworkError.FAIL_ERROR -import com.sopt.now.util.StringNetworkError.SERVER_ERROR -import com.sopt.now.util.StringNetworkError.SIGNUP +import com.sopt.now.domain.entity.UserEntity +import com.sopt.now.domain.usecase.SignUpUseCase +import com.sopt.now.ui.model.User import com.sopt.now.util.UiState +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch -import org.json.JSONObject -import retrofit2.Call -import retrofit2.Callback -import retrofit2.HttpException -import retrofit2.Response - -class SignUpViewModel : ViewModel() { - private val authService by lazy { ServicePool.authService } +import javax.inject.Inject +@HiltViewModel +class SignUpViewModel @Inject constructor( + private val signUpUseCase: SignUpUseCase +) : ViewModel() { private val _signUpState = MutableLiveData>() - val signUpState = _signUpState + val signUpState: LiveData> = _signUpState - fun signUp(request: RequestSignUpDto) { + fun signUp(request: UserEntity) { _signUpState.value = UiState.Loading viewModelScope.launch { - runCatching { - authService.signUp(request) - }.onSuccess { - _signUpState.value = - UiState.Success(request.toUserWithUserId(it.headers()["userid"].toString())) - }.onFailure { e -> - if (e is HttpException) { - val errorMessage = - JSONObject(e.response()?.errorBody()?.string()).getString("message") - _signUpState.value = UiState.Error(errorMessage) - } else { - _signUpState.value = UiState.Error("코드 똑바로 짜라.. ") + signUpUseCase(request) + .onSuccess { + _signUpState.value = + UiState.Success( + User( + request.authenticationId, + request.password, + request.nickname, + request.phone, + ) + ) + } + .onFailure { e -> + _signUpState.value = UiState.Error(e.message.toString()) } - - } } } } diff --git a/build.gradle b/build.gradle index be6601c..e62ab31 100644 --- a/build.gradle +++ b/build.gradle @@ -3,4 +3,6 @@ plugins { id 'com.android.application' version '8.3.1' apply false id 'com.android.library' version '8.3.1' apply false id 'org.jetbrains.kotlin.android' version '1.9.0' apply false + id 'com.google.dagger.hilt.android' version '2.51' apply false + id 'com.google.devtools.ksp' version '1.9.0-1.0.12' apply false } \ No newline at end of file