diff --git a/app/src/main/java/org/sopt/and/MainActivity.kt b/app/src/main/java/org/sopt/and/MainActivity.kt index 6894bb9..4f74d5d 100644 --- a/app/src/main/java/org/sopt/and/MainActivity.kt +++ b/app/src/main/java/org/sopt/and/MainActivity.kt @@ -3,8 +3,8 @@ package org.sopt.and import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import org.sopt.and.data.service.AppContext import org.sopt.and.presentation.navigation.Navigation -import org.sopt.and.services.AppContext import org.sopt.and.ui.theme.ANDANDROIDTheme class MainActivity : ComponentActivity() { diff --git a/app/src/main/java/org/sopt/and/data/datasource/GetMyHobbyDataSource.kt b/app/src/main/java/org/sopt/and/data/datasource/GetMyHobbyDataSource.kt new file mode 100644 index 0000000..21c4d07 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/datasource/GetMyHobbyDataSource.kt @@ -0,0 +1,10 @@ +package org.sopt.and.data.datasource + +import org.sopt.and.data.model.response.GetMyHobbyResponseDto +import org.sopt.and.data.service.UserService + +class GetMyHobbyDataSource( + private val userService: UserService +) { + suspend fun getMyHobby(): GetMyHobbyResponseDto = userService.getMyHobby() +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/mapper/Mapper.kt b/app/src/main/java/org/sopt/and/data/mapper/Mapper.kt new file mode 100644 index 0000000..a99bb09 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/mapper/Mapper.kt @@ -0,0 +1,9 @@ +package org.sopt.and.data.mapper + +import org.sopt.and.data.model.response.GetMyHobbyResponseResultDto +import org.sopt.and.domain.model.MyHobbyEntity + +object Mapper { + fun toMyHobbyEntity(getHobbyResponseResultDto: GetMyHobbyResponseResultDto) = + MyHobbyEntity(myHobby = getHobbyResponseResultDto.myHobby) +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/model/response/GetHobbyResponseDto.kt b/app/src/main/java/org/sopt/and/data/model/response/GetHobbyResponseDto.kt deleted file mode 100644 index f0d3139..0000000 --- a/app/src/main/java/org/sopt/and/data/model/response/GetHobbyResponseDto.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.sopt.and.data.model.response - -import kotlinx.serialization.Serializable - -@Serializable -data class GetHobbyResponseDto( - val result: GetHobbyResponseResultDto? = null, - val code: String? = null -) - -@Serializable -data class GetHobbyResponseResultDto( - val hobby: String -) \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/model/response/GetMyHobbyResponseDto.kt b/app/src/main/java/org/sopt/and/data/model/response/GetMyHobbyResponseDto.kt new file mode 100644 index 0000000..9feee1d --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/model/response/GetMyHobbyResponseDto.kt @@ -0,0 +1,16 @@ +package org.sopt.and.data.model.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GetMyHobbyResponseDto( + val result: GetMyHobbyResponseResultDto? = null, + val code: String? = null +) + +@Serializable +data class GetMyHobbyResponseResultDto( + @SerialName("hobby") + val myHobby: String +) \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/data/repositoryimpl/GetMyHobbyRepositoryImpl.kt b/app/src/main/java/org/sopt/and/data/repositoryimpl/GetMyHobbyRepositoryImpl.kt new file mode 100644 index 0000000..1ed0152 --- /dev/null +++ b/app/src/main/java/org/sopt/and/data/repositoryimpl/GetMyHobbyRepositoryImpl.kt @@ -0,0 +1,15 @@ +package org.sopt.and.data.repositoryimpl + +import org.sopt.and.data.datasource.GetMyHobbyDataSource +import org.sopt.and.data.mapper.Mapper +import org.sopt.and.domain.model.MyHobbyEntity +import org.sopt.and.domain.repository.GetMyHobbyRepository + +class GetMyHobbyRepositoryImpl( + private val getMyHobbyDataSource: GetMyHobbyDataSource +) : GetMyHobbyRepository { + override suspend fun getMyHobby(): Result = + runCatching { + getMyHobbyDataSource.getMyHobby().result?.let { Mapper.toMyHobbyEntity(it) }!! + } +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/services/ApiFactory.kt b/app/src/main/java/org/sopt/and/data/service/ApiFactory.kt similarity index 97% rename from app/src/main/java/org/sopt/and/services/ApiFactory.kt rename to app/src/main/java/org/sopt/and/data/service/ApiFactory.kt index 773d28e..a4a1b68 100644 --- a/app/src/main/java/org/sopt/and/services/ApiFactory.kt +++ b/app/src/main/java/org/sopt/and/data/service/ApiFactory.kt @@ -1,4 +1,4 @@ -package org.sopt.and.services +package org.sopt.and.data.service import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json diff --git a/app/src/main/java/org/sopt/and/services/AppContext.kt b/app/src/main/java/org/sopt/and/data/service/AppContext.kt similarity index 87% rename from app/src/main/java/org/sopt/and/services/AppContext.kt rename to app/src/main/java/org/sopt/and/data/service/AppContext.kt index 41c76f5..29eb7ae 100644 --- a/app/src/main/java/org/sopt/and/services/AppContext.kt +++ b/app/src/main/java/org/sopt/and/data/service/AppContext.kt @@ -1,4 +1,4 @@ -package org.sopt.and.services +package org.sopt.and.data.service import android.content.Context diff --git a/app/src/main/java/org/sopt/and/services/AuthInterceptor.kt b/app/src/main/java/org/sopt/and/data/service/AuthInterceptor.kt similarity index 95% rename from app/src/main/java/org/sopt/and/services/AuthInterceptor.kt rename to app/src/main/java/org/sopt/and/data/service/AuthInterceptor.kt index 5e8ae14..c9f89e4 100644 --- a/app/src/main/java/org/sopt/and/services/AuthInterceptor.kt +++ b/app/src/main/java/org/sopt/and/data/service/AuthInterceptor.kt @@ -1,4 +1,4 @@ -package org.sopt.and.services +package org.sopt.and.data.service import android.content.Context import kotlinx.coroutines.flow.first diff --git a/app/src/main/java/org/sopt/and/services/TokenManager.kt b/app/src/main/java/org/sopt/and/data/service/TokenManager.kt similarity index 89% rename from app/src/main/java/org/sopt/and/services/TokenManager.kt rename to app/src/main/java/org/sopt/and/data/service/TokenManager.kt index 910b143..6f8407b 100644 --- a/app/src/main/java/org/sopt/and/services/TokenManager.kt +++ b/app/src/main/java/org/sopt/and/data/service/TokenManager.kt @@ -1,4 +1,4 @@ -package org.sopt.and.services +package org.sopt.and.data.service import android.content.Context import androidx.datastore.preferences.core.edit @@ -6,7 +6,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import org.sopt.and.services.TokenManager.Companion.DATASTORE_NAME +import org.sopt.and.data.service.TokenManager.Companion.DATASTORE_NAME val Context.dataStore by preferencesDataStore(DATASTORE_NAME) diff --git a/app/src/main/java/org/sopt/and/services/UserService.kt b/app/src/main/java/org/sopt/and/data/service/UserService.kt similarity index 80% rename from app/src/main/java/org/sopt/and/services/UserService.kt rename to app/src/main/java/org/sopt/and/data/service/UserService.kt index 0af0a40..efa2126 100644 --- a/app/src/main/java/org/sopt/and/services/UserService.kt +++ b/app/src/main/java/org/sopt/and/data/service/UserService.kt @@ -1,8 +1,8 @@ -package org.sopt.and.services +package org.sopt.and.data.service import org.sopt.and.data.model.request.SignInRequestDto import org.sopt.and.data.model.request.SignUpRequestDto -import org.sopt.and.data.model.response.GetHobbyResponseDto +import org.sopt.and.data.model.response.GetMyHobbyResponseDto import org.sopt.and.data.model.response.SignInResponseDto import org.sopt.and.data.model.response.SignUpResponseDto import retrofit2.Response @@ -18,5 +18,5 @@ interface UserService { suspend fun signIn(@Body request: SignInRequestDto): Response @GET("/user/my-hobby") - suspend fun getMyHobby(): GetHobbyResponseDto + suspend fun getMyHobby(): GetMyHobbyResponseDto } \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/domain/repository/GetMyHobbyRepository.kt b/app/src/main/java/org/sopt/and/domain/repository/GetMyHobbyRepository.kt index 8ff3f6a..449c5aa 100644 --- a/app/src/main/java/org/sopt/and/domain/repository/GetMyHobbyRepository.kt +++ b/app/src/main/java/org/sopt/and/domain/repository/GetMyHobbyRepository.kt @@ -1,7 +1,20 @@ package org.sopt.and.domain.repository +import org.sopt.and.data.datasource.GetMyHobbyDataSource +import org.sopt.and.data.repositoryimpl.GetMyHobbyRepositoryImpl +import org.sopt.and.data.service.ServicePool import org.sopt.and.domain.model.MyHobbyEntity interface GetMyHobbyRepository { suspend fun getMyHobby(): Result + + companion object { + fun create(): GetMyHobbyRepositoryImpl { + return GetMyHobbyRepositoryImpl( + GetMyHobbyDataSource( + ServicePool.userService + ) + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/domain/usecase/GetMyHobbyUseCase.kt b/app/src/main/java/org/sopt/and/domain/usecase/GetMyHobbyUseCase.kt new file mode 100644 index 0000000..f11852c --- /dev/null +++ b/app/src/main/java/org/sopt/and/domain/usecase/GetMyHobbyUseCase.kt @@ -0,0 +1,11 @@ +package org.sopt.and.domain.usecase + +import org.sopt.and.domain.model.MyHobbyEntity +import org.sopt.and.domain.repository.GetMyHobbyRepository + +class GetMyHobbyUseCase( + private val getMyHobbyRepository: GetMyHobbyRepository +) { + suspend operator fun invoke(): Result = + getMyHobbyRepository.getMyHobby() +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/and/presentation/components/LinkWithSNSBox.kt b/app/src/main/java/org/sopt/and/presentation/components/LinkWithSNSBox.kt index ebc5f42..0c97ebf 100644 --- a/app/src/main/java/org/sopt/and/presentation/components/LinkWithSNSBox.kt +++ b/app/src/main/java/org/sopt/and/presentation/components/LinkWithSNSBox.kt @@ -23,7 +23,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import org.sopt.and.R -import org.sopt.and.WavveUtils +import org.sopt.and.presentation.util.WavveUtils import org.sopt.and.ui.theme.ANDANDROIDTheme import org.sopt.and.ui.theme.Grey200 diff --git a/app/src/main/java/org/sopt/and/presentation/myinfo/MyInfoViewModel.kt b/app/src/main/java/org/sopt/and/presentation/myinfo/MyInfoViewModel.kt index 514511a..b75f8d9 100644 --- a/app/src/main/java/org/sopt/and/presentation/myinfo/MyInfoViewModel.kt +++ b/app/src/main/java/org/sopt/and/presentation/myinfo/MyInfoViewModel.kt @@ -6,12 +6,13 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import org.sopt.and.data.model.response.GetHobbyResponseDto -import org.sopt.and.services.ServicePool - -class MyInfoViewModel : ViewModel() { - private val userService by lazy { ServicePool.userService } +import org.sopt.and.domain.model.MyHobbyEntity +import org.sopt.and.domain.usecase.GetMyHobbyUseCase +class MyInfoViewModel( + private val getMyHobbyUseCase: GetMyHobbyUseCase +) : ViewModel() { + private val _uiState = MutableStateFlow(MyInfoUiState()) val uiState: StateFlow = _uiState.asStateFlow() @@ -21,10 +22,8 @@ class MyInfoViewModel : ViewModel() { fun getMyHobby() { viewModelScope.launch { - runCatching { - userService.getMyHobby() - }.onSuccess { response: GetHobbyResponseDto -> - response.result?.let { setMyHobby(it.hobby) } + getMyHobbyUseCase().onSuccess { myHobbyEntity: MyHobbyEntity -> + setMyHobby(myHobbyEntity.myHobby) }.onFailure { } } } diff --git a/app/src/main/java/org/sopt/and/presentation/navigation/Navigation.kt b/app/src/main/java/org/sopt/and/presentation/navigation/Navigation.kt index 88ee50a..9f88157 100644 --- a/app/src/main/java/org/sopt/and/presentation/navigation/Navigation.kt +++ b/app/src/main/java/org/sopt/and/presentation/navigation/Navigation.kt @@ -17,6 +17,7 @@ import org.sopt.and.presentation.myinfo.MyInfoViewModel import org.sopt.and.presentation.search.SearchScreen import org.sopt.and.presentation.signin.SignInScreen import org.sopt.and.presentation.signup.SignUpScreen +import org.sopt.and.presentation.viewmodelfactory.MyInfoViewModelFactory @Composable fun Navigation( @@ -25,7 +26,9 @@ fun Navigation( val navigationUiState by navigationViewModel.uiState.collectAsStateWithLifecycle() val navController = rememberNavController() - val myInfoViewModel = viewModel() + val myInfoViewModel: MyInfoViewModel = viewModel( + factory = MyInfoViewModelFactory() + ) val myInfoUiState by myInfoViewModel.uiState.collectAsStateWithLifecycle() Scaffold( diff --git a/app/src/main/java/org/sopt/and/presentation/navigation/NavigationUiState.kt b/app/src/main/java/org/sopt/and/presentation/navigation/NavigationUiState.kt index 49dc4cc..9d889e4 100644 --- a/app/src/main/java/org/sopt/and/presentation/navigation/NavigationUiState.kt +++ b/app/src/main/java/org/sopt/and/presentation/navigation/NavigationUiState.kt @@ -5,7 +5,7 @@ import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Search import org.sopt.and.R -import org.sopt.and.WavveUtils +import org.sopt.and.presentation.util.WavveUtils data class NavigationUiState( val isBottomNavigationVisible: Boolean = false, diff --git a/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt b/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt index a6812fc..f81041f 100644 --- a/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt +++ b/app/src/main/java/org/sopt/and/presentation/signin/SignInViewModel.kt @@ -11,12 +11,12 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import org.sopt.and.R -import org.sopt.and.WavveUtils.showSnackbar import org.sopt.and.data.model.request.SignInRequestDto import org.sopt.and.data.model.response.SignInResponseDto -import org.sopt.and.services.AppContext -import org.sopt.and.services.ServicePool -import org.sopt.and.services.TokenManager +import org.sopt.and.data.service.AppContext +import org.sopt.and.data.service.ServicePool +import org.sopt.and.data.service.TokenManager +import org.sopt.and.presentation.util.WavveUtils.showSnackbar import retrofit2.Response class SignInViewModel : ViewModel() { diff --git a/app/src/main/java/org/sopt/and/presentation/signin/components/SignInPasswordField.kt b/app/src/main/java/org/sopt/and/presentation/signin/components/SignInPasswordField.kt index f405f49..e9b408a 100644 --- a/app/src/main/java/org/sopt/and/presentation/signin/components/SignInPasswordField.kt +++ b/app/src/main/java/org/sopt/and/presentation/signin/components/SignInPasswordField.kt @@ -2,9 +2,9 @@ package org.sopt.and.presentation.signin.components import androidx.compose.runtime.Composable import org.sopt.and.R -import org.sopt.and.WavveUtils.transformationPasswordVisual import org.sopt.and.presentation.components.ShowOrHideToggle import org.sopt.and.presentation.components.SignInOrSignUpTextField +import org.sopt.and.presentation.util.WavveUtils.transformationPasswordVisual @Composable fun SignInPasswordField( diff --git a/app/src/main/java/org/sopt/and/presentation/signup/SignUpViewModel.kt b/app/src/main/java/org/sopt/and/presentation/signup/SignUpViewModel.kt index aef8170..ffd26bd 100644 --- a/app/src/main/java/org/sopt/and/presentation/signup/SignUpViewModel.kt +++ b/app/src/main/java/org/sopt/and/presentation/signup/SignUpViewModel.kt @@ -9,10 +9,10 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import org.sopt.and.R -import org.sopt.and.WavveUtils.showToast import org.sopt.and.data.model.request.SignUpRequestDto import org.sopt.and.data.model.response.SignUpResponseDto -import org.sopt.and.services.ServicePool +import org.sopt.and.data.service.ServicePool +import org.sopt.and.presentation.util.WavveUtils.showToast class SignUpViewModel : ViewModel() { diff --git a/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpGreetingText.kt b/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpGreetingText.kt index 1ddc3a1..e0c72f6 100644 --- a/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpGreetingText.kt +++ b/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpGreetingText.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.text.style.LineHeightStyle import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp import org.sopt.and.R -import org.sopt.and.WavveUtils +import org.sopt.and.presentation.util.WavveUtils import org.sopt.and.ui.theme.Grey200 import org.sopt.and.ui.theme.White100 diff --git a/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpPasswordField.kt b/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpPasswordField.kt index bb343ce..a930ca8 100644 --- a/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpPasswordField.kt +++ b/app/src/main/java/org/sopt/and/presentation/signup/components/SignUpPasswordField.kt @@ -7,10 +7,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import org.sopt.and.R -import org.sopt.and.WavveUtils.transformationPasswordVisual import org.sopt.and.presentation.components.CautionBox import org.sopt.and.presentation.components.ShowOrHideToggle import org.sopt.and.presentation.components.SignInOrSignUpTextField +import org.sopt.and.presentation.util.WavveUtils.transformationPasswordVisual @Composable fun SignUpPasswordField( diff --git a/app/src/main/java/org/sopt/and/WavveUtils.kt b/app/src/main/java/org/sopt/and/presentation/util/WavveUtils.kt similarity index 96% rename from app/src/main/java/org/sopt/and/WavveUtils.kt rename to app/src/main/java/org/sopt/and/presentation/util/WavveUtils.kt index 6f5645e..3c437a8 100644 --- a/app/src/main/java/org/sopt/and/WavveUtils.kt +++ b/app/src/main/java/org/sopt/and/presentation/util/WavveUtils.kt @@ -1,4 +1,4 @@ -package org.sopt.and +package org.sopt.and.presentation.util import android.content.Context import android.widget.Toast @@ -8,6 +8,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import org.sopt.and.R object WavveUtils { const val MIN_PASSWORD_LENGTH = 8 diff --git a/app/src/main/java/org/sopt/and/presentation/viewmodelfactory/ViewModelFactory.kt b/app/src/main/java/org/sopt/and/presentation/viewmodelfactory/ViewModelFactory.kt new file mode 100644 index 0000000..bbbaef3 --- /dev/null +++ b/app/src/main/java/org/sopt/and/presentation/viewmodelfactory/ViewModelFactory.kt @@ -0,0 +1,24 @@ +package org.sopt.and.presentation.viewmodelfactory + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import org.sopt.and.domain.repository.GetMyHobbyRepository +import org.sopt.and.domain.usecase.GetMyHobbyUseCase +import org.sopt.and.presentation.myinfo.MyInfoViewModel + +class MyInfoViewModelFactory() : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return when (modelClass) { + + MyInfoViewModel::class.java -> { + MyInfoViewModel( + GetMyHobbyUseCase( + getMyHobbyRepository = GetMyHobbyRepository.create() + ) + ) as T + } + + else -> throw IllegalArgumentException("Unknown ViewModel Class") + } + } +} \ No newline at end of file