Skip to content

Commit

Permalink
#10 [feat] : api 연결 세팅
Browse files Browse the repository at this point in the history
  • Loading branch information
gitsuhyun committed Dec 4, 2024
1 parent b02e0f9 commit b808a91
Show file tree
Hide file tree
Showing 21 changed files with 178 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sopt.and.data.remote.model
package org.sopt.and.data.local

data class TodayTopData(
val painterId: Int,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.sopt.and.data.mapper.todata

import org.sopt.and.data.remote.model.request.UserLoginRequestDto
import org.sopt.and.domain.model.request.UserLoginModel

fun UserLoginModel.toData() : UserLoginRequestDto = UserLoginRequestDto(

username = this.username,
password = this.password
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.sopt.and.data.mapper.todata

import org.sopt.and.data.remote.model.request.UserSignUpRequestDto
import org.sopt.and.domain.model.request.UserSignUpModel

fun UserSignUpModel.toData() : UserSignUpRequestDto = UserSignUpRequestDto(

username = this.username,
password = this.password,
hobby = this.hobby
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sopt.and.data.mapper.todomain

import org.sopt.and.data.remote.model.response.UserHobbyResponseDto
import org.sopt.and.domain.model.response.Hobby

fun UserHobbyResponseDto.toDomain(): Hobby = Hobby(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.data.mapper.todomain

import org.sopt.and.data.remote.model.response.UserSignUpResponseDto
import org.sopt.and.domain.model.response.UserNumber

fun UserSignUpResponseDto.toDomain(): UserNumber = UserNumber(
no = this.no
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.and.data.mapper.todomain

import org.sopt.and.data.remote.model.response.UserTokenResponseDto
import org.sopt.and.domain.model.response.Token

fun UserTokenResponseDto.toDomain(): Token = Token(
token = this.token
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sopt.and.data.remote.datasource

import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.UserLoginRequestDto
import org.sopt.and.data.remote.model.request.UserSignUpRequestDto
import org.sopt.and.data.remote.model.response.UserHobbyResponseDto
import org.sopt.and.data.remote.model.response.UserSignUpResponseDto
import org.sopt.and.data.remote.model.response.UserTokenResponseDto

interface UserDataRemoteSource {
suspend fun postUserSignUp(userSignUpRequestDto: UserSignUpRequestDto): ApiResponse<UserSignUpResponseDto>
suspend fun postUserLogin(userLoginRequestDto: UserLoginRequestDto): ApiResponse<UserTokenResponseDto>
suspend fun getUserHobby(token: String): ApiResponse<UserHobbyResponseDto>
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.sopt.and.data.remote.datasourceimpl

import org.sopt.and.data.remote.datasource.UserDataRemoteSource
import org.sopt.and.data.remote.model.base.ApiResponse
import org.sopt.and.data.remote.model.request.UserLoginRequestDto
import org.sopt.and.data.remote.model.request.UserSignUpRequestDto
import org.sopt.and.data.remote.model.response.UserHobbyResponseDto
import org.sopt.and.data.remote.model.response.UserSignUpResponseDto
import org.sopt.and.data.remote.model.response.UserTokenResponseDto
import org.sopt.and.data.remote.service.UserService
import org.sopt.and.di.ServicePool

class UserDataRemoteSourceImpl(
private val userService: UserService
) : UserDataRemoteSource {

override suspend fun postUserSignUp(userSignUpRequestDto: UserSignUpRequestDto): ApiResponse<UserSignUpResponseDto> =
userService.postUserSignUp(body = userSignUpRequestDto)

override suspend fun postUserLogin(userLoginRequestDto: UserLoginRequestDto): ApiResponse<UserTokenResponseDto> =
userService.postUserLogin(body = userLoginRequestDto)


override suspend fun getUserHobby(token: String): ApiResponse<UserHobbyResponseDto> =
userService.getUserHobby(token = token)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.sopt.and.data.remote.utils

import org.sopt.and.data.remote.model.base.ApiResponse

fun <T> ApiResponse<T>.handleApiResponse(): Result<T> {
return try {
Result.success(this.result)
} catch (e: Exception) {
Result.failure(e)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.sopt.and.data.repositoryimpl

import org.sopt.and.data.mapper.todata.toData
import org.sopt.and.data.mapper.todomain.toDomain
import org.sopt.and.data.remote.datasource.UserDataRemoteSource
import org.sopt.and.data.remote.utils.handleApiResponse
import org.sopt.and.domain.model.request.UserLoginModel
import org.sopt.and.domain.model.request.UserSignUpModel
import org.sopt.and.domain.model.response.Hobby
import org.sopt.and.domain.model.response.Token
import org.sopt.and.domain.model.response.UserNumber
import org.sopt.and.domain.repository.UserRepository

class UserRepositoryImpl (
private val userDataRemoteSource: UserDataRemoteSource
) : UserRepository {

override suspend fun postUserSignUp(userSignUpModel: UserSignUpModel): Result<UserNumber> {
return runCatching {
userDataRemoteSource.postUserSignUp(userSignUpModel.toData()).handleApiResponse().getOrThrow().toDomain()
}
}

override suspend fun postUserLogin(userLoginModel: UserLoginModel): Result<Token> {
return runCatching {
userDataRemoteSource.postUserLogin(userLoginModel.toData()).handleApiResponse().getOrThrow().toDomain()
}
}

override suspend fun getUserHobby(token: String): Result<Hobby> {
return runCatching {
userDataRemoteSource.getUserHobby(token = token).handleApiResponse().getOrThrow().toDomain()
}
}
}

This file was deleted.

13 changes: 13 additions & 0 deletions app/src/main/java/org/sopt/and/domain/repository/UserRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sopt.and.domain.repository

import org.sopt.and.domain.model.request.UserLoginModel
import org.sopt.and.domain.model.request.UserSignUpModel
import org.sopt.and.domain.model.response.Hobby
import org.sopt.and.domain.model.response.Token
import org.sopt.and.domain.model.response.UserNumber

interface UserRepository {
suspend fun postUserSignUp(userSignUpModel: UserSignUpModel): Result<UserNumber>
suspend fun postUserLogin(userLoginModel: UserLoginModel): Result<Token>
suspend fun getUserHobby(token: String): Result<Hobby>
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.sopt.and.R
import org.sopt.and.data.remote.model.TodayTopData
import org.sopt.and.data.local.TodayTopData
import org.sopt.and.ui.theme.WavveTheme

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.ViewModel
import org.sopt.and.R
import org.sopt.and.data.remote.model.TodayTopData
import org.sopt.and.data.local.TodayTopData

class HomeViewModel : ViewModel() {
private val _homeTabText = listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
Expand All @@ -50,10 +51,15 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import org.sopt.and.R
import org.sopt.and.data.remote.datasourceimpl.UserDataRemoteSourceImpl
import org.sopt.and.presentation.core.component.AuthTextField
import org.sopt.and.presentation.core.component.SocialLoginButtonGroup
import org.sopt.and.presentation.core.component.WavveLoginButton
import org.sopt.and.data.remote.model.request.UserLoginRequestDto
import org.sopt.and.data.repositoryimpl.UserRepositoryImpl
import org.sopt.and.di.ServicePool
import org.sopt.and.domain.model.request.UserLoginModel
import org.sopt.and.domain.repository.UserRepository
import org.sopt.and.presentation.main.Routes
import org.sopt.and.ui.theme.WavveTheme
import org.sopt.and.utils.noRippleClickable
Expand All @@ -72,6 +78,7 @@ fun LoginScreen(
val editor = sharedPreferences.edit()


val loginState by viewModel.loginState.collectAsState()
val token by viewModel.token.observeAsState("")
val userName by viewModel.userName.observeAsState("")
val password by viewModel.password.observeAsState("")
Expand Down Expand Up @@ -178,7 +185,7 @@ fun LoginScreen(
onClick = {
viewModel.postUserLogin(
context = context,
body = UserLoginRequestDto(
body = UserLoginModel(
username = userName,
password = password
),
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/org/sopt/and/presentation/login/LoginState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.sopt.and.presentation.login

import org.sopt.and.domain.model.response.Token

sealed class LoginState {
data object Idle: LoginState()
data object Loading: LoginState()
data class Success(val result: Token): LoginState()
data class Failure(val message: String): LoginState()
}
56 changes: 34 additions & 22 deletions app/src/main/java/org/sopt/and/presentation/login/LoginViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,60 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import okio.IOException
import org.sopt.and.R
import org.sopt.and.di.ServicePool
import org.sopt.and.data.remote.model.request.UserLoginRequestDto
import org.sopt.and.domain.model.request.UserLoginModel
import org.sopt.and.domain.repository.UserRepository
import org.sopt.and.utils.toast
import retrofit2.HttpException

class LoginViewModel : ViewModel() {
private val userService by lazy { ServicePool.userService }
class LoginViewModel(
private val userRepository: UserRepository
) : ViewModel() {
private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)
val loginState: StateFlow<LoginState> = _loginState

private val _token = MutableLiveData<String>(null)
val token: LiveData<String> get() = _token

fun postUserLogin(
context: Context,
body: UserLoginRequestDto,
body: UserLoginModel,
) {
_loginState.value = LoginState.Loading
viewModelScope.launch {
runCatching {
userService.postUserLogin(body = body)
}.onSuccess { response ->
_token.value = response.result.token
}.onFailure { error ->
when (error) {
is HttpException -> {
when (error.code()) {
400 -> context.toast(context.getString(R.string.fail_to_login))
403 -> context.toast(context.getString(R.string.fail_to_login_invalid_password))
val result = userRepository.postUserLogin(
userLoginModel = body
)
_loginState.value = result.fold(
onSuccess = { response ->
_token.value = response.token
LoginState.Success(response)
},
onFailure = { error ->
when (error) {
is HttpException -> {
when (error.code()) {
400 -> context.toast(context.getString(R.string.fail_to_login))
403 -> context.toast(context.getString(R.string.fail_to_login_invalid_password))
}
}
}

is IOException -> {
context.toast(context.getString(R.string.fail_to_network))
}
is IOException -> {
context.toast(context.getString(R.string.fail_to_network))
}

else -> {
context.toast(context.getString(R.string.fail_to_login))
else -> {
context.toast(context.getString(R.string.fail_to_login))
}
}
LoginState.Failure(error.message.orEmpty())
}
Log.e("postUserLoginError", error.toString())
}
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ fun NavGraph(
popUpTo(Routes.Home.screen) { inclusive = true }
}
},
viewModel = LoginViewModel()
)
}
composable(Routes.SignUp.screen) {
Expand Down

0 comments on commit b808a91

Please sign in to comment.