From d689df094b300e19fad2a799abf1e0d35fdb1d8a Mon Sep 17 00:00:00 2001 From: arinming Date: Fri, 24 May 2024 17:03:34 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[Refactor]=20=EB=B7=B0=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?Side=20Effect=20Loading=20=EC=B6=94=EA=B0=80=20(#11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 8 ++++---- .../java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt | 4 ++++ .../com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 96f1576..f0ea816 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,8 +54,8 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.13.0' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.0' implementation 'androidx.activity:activity-compose:1.9.0' implementation platform('androidx.compose:compose-bom:2024.05.00') implementation 'androidx.compose.ui:ui' @@ -73,10 +73,10 @@ dependencies { implementation 'androidx.compose.material:material:1.6.7' // Lifecycle Viewmodel - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0' // Fragment && Activity - implementation 'androidx.fragment:fragment-ktx:1.6.2' + implementation 'androidx.fragment:fragment-ktx:1.7.1' implementation 'androidx.activity:activity-ktx:1.9.0' // Retrofit diff --git a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt index 5596261..8fc48dd 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt @@ -59,6 +59,10 @@ fun SignUpScreen( onNavigateToSignIn.navigate(context.getString(R.string.route_sign_in)) } + is SignUpSideEffect.Loading -> { + Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show() + } + is SignUpSideEffect.Error -> { Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt index 6d2bbd4..cd1cba6 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt @@ -2,5 +2,6 @@ package com.sopt.now.compose.ui.signUp sealed class SignUpSideEffect { data class Success(val message: String) : SignUpSideEffect() + data class Loading(val message: String) : SignUpSideEffect() data class Error(val message: String) : SignUpSideEffect() } \ No newline at end of file From 51db35c71cfc783441710ef745e3bc28b4204392 Mon Sep 17 00:00:00 2001 From: arinming Date: Fri, 7 Jun 2024 21:38:08 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[Feat]=20follower=20repository=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compose/repository/FollowerRepository.kt | 17 +++++ .../sopt/now/compose/ui/home/HomeViewModel.kt | 64 +++++++++++-------- 2 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt diff --git a/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt b/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt new file mode 100644 index 0000000..99ede21 --- /dev/null +++ b/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt @@ -0,0 +1,17 @@ +package com.sopt.now.compose.repository + +import com.sopt.now.compose.data.model.ResponseUserDto +import com.sopt.now.compose.data.module.ServicePool +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import retrofit2.Response + +class FollowerRepository { + private val followerService = ServicePool.followerService + + suspend fun getUserList(page: Int): Response { + return withContext(Dispatchers.IO) { + followerService.getUserList(page).execute() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt index a79e0bb..409ddf5 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt @@ -1,23 +1,30 @@ package com.sopt.now.compose.ui.home import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.sopt.now.compose.data.model.Profile -import com.sopt.now.compose.data.model.ResponseUserDto import com.sopt.now.compose.data.model.UserDataDto -import com.sopt.now.compose.data.module.ServicePool +import com.sopt.now.compose.repository.FollowerRepository import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import kotlinx.coroutines.launch +import java.io.IOException class HomeViewModel : ViewModel() { - private val followerService by lazy { ServicePool.followerService } + private val followerRepository = FollowerRepository() private val _followerState = MutableStateFlow>(emptyList()) val followerState = _followerState.asStateFlow() + private var _eventNetworkError = MutableLiveData(false) + val eventNetworkError: LiveData + get() = _eventNetworkError + + private var _isNetworkErrorShown = MutableLiveData(false) + val friendList = mutableListOf() init { @@ -25,35 +32,38 @@ class HomeViewModel : ViewModel() { } private fun fetchFollowerList() { - followerService.getUserList(page = 0).enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response, - ) { + viewModelScope.launch { + try { + val response = followerRepository.getUserList(0) if (response.isSuccessful) { - val data = response.body()?.data - if (data != null) { + response.body()?.data?.let { data -> _followerState.value = data mapFollowersToFriendList(data) } + _eventNetworkError.value = false + _isNetworkErrorShown.value = false + } else { + _eventNetworkError.value = true } + } catch (networkError: IOException) { + _eventNetworkError.value = true + Log.e("HomeError", "${networkError.message}") } + } + } - override fun onFailure(call: Call, t: Throwable) { - Log.e("HomeError", "${t.message}") - } - }) + fun onNetworkErrorShown() { + _isNetworkErrorShown.value = true } - fun mapFollowersToFriendList(followers: List) { - for (follower in followers) { - friendList.add( - Profile( - profileImage = follower.avatar, - name = "${follower.firstName} ${follower.lastName}", - description = follower.email - ) + private fun mapFollowersToFriendList(followers: List) { + friendList.clear() + friendList.addAll(followers.map { follower -> + Profile( + profileImage = follower.avatar, + name = "${follower.firstName} ${follower.lastName}", + description = follower.email ) - } + }) } -} \ No newline at end of file +} From 2dc3df5c86aa6e51466c22dca0e7b4f018576954 Mon Sep 17 00:00:00 2001 From: arinming Date: Wed, 26 Jun 2024 00:25:39 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[Feat]=20=EC=A2=85=EC=86=8D=EC=84=B1?= =?UTF-8?q?=EC=97=90=20Hilt=20=EC=B6=94=EA=B0=80=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 7 +++++++ app/src/main/java/com/sopt/now/compose/MainActivity.kt | 2 ++ build.gradle | 1 + 3 files changed, 10 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index f0ea816..0cb82cc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,9 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.plugin.serialization' + id 'com.google.dagger.hilt.android' + id 'kotlin-android' + id 'kotlin-kapt' } Properties properties = new Properties() @@ -91,4 +94,8 @@ dependencies { // Coil implementation 'io.coil-kt:coil-compose:2.6.0' + + // Hilt + implementation 'com.google.dagger:hilt-android:2.51' + kapt 'com.google.dagger:hilt-compiler:2.51.1' } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/compose/MainActivity.kt b/app/src/main/java/com/sopt/now/compose/MainActivity.kt index 47e8acd..d2074ab 100644 --- a/app/src/main/java/com/sopt/now/compose/MainActivity.kt +++ b/app/src/main/java/com/sopt/now/compose/MainActivity.kt @@ -9,7 +9,9 @@ import androidx.compose.material3.Surface import androidx.compose.ui.Modifier import com.sopt.now.compose.ui.SoptApp import com.sopt.now.compose.ui.theme.NOWSOPTAndroidTheme +import dagger.hilt.android.HiltAndroidApp +@HiltAndroidApp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/build.gradle b/build.gradle index 4c76592..dbcc2e3 100644 --- a/build.gradle +++ b/build.gradle @@ -4,4 +4,5 @@ plugins { id 'com.android.library' version '8.3.1' apply false id 'org.jetbrains.kotlin.android' version '1.9.0' apply false id("org.jetbrains.kotlin.plugin.serialization") version "1.9.20" apply false + id 'com.google.dagger.hilt.android' version '2.51' apply false } \ No newline at end of file From abcc490165ccaa3e94040fa767a41bf74c29f8e4 Mon Sep 17 00:00:00 2001 From: arinming Date: Fri, 28 Jun 2024 02:01:24 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[refactor]=20=EC=B5=9C=EC=83=81=EB=8B=A8=20?= =?UTF-8?q?=EC=95=B1=EC=97=90=20Hilt=20=EC=A0=81=EC=9A=A9=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 3 ++- app/src/main/java/com/sopt/now/compose/App.kt | 11 +++++++++++ .../main/java/com/sopt/now/compose/MainActivity.kt | 4 ++-- 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/sopt/now/compose/App.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f73f094..a846894 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,8 +5,8 @@ Date: Fri, 28 Jun 2024 20:30:17 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[refactor]=20ApiFactory=20=ED=9E=90?= =?UTF-8?q?=ED=8A=B8=20=EC=A0=81=EC=9A=A9=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../now/compose/data/module/ApiFactory.kt | 43 ++++++++----------- .../compose/repository/FollowerRepository.kt | 11 +++-- .../now/compose/ui/base/SoptAppNavHost.kt | 2 +- .../sopt/now/compose/ui/home/HomeViewModel.kt | 15 +++---- .../now/compose/ui/myPage/MyPageViewModel.kt | 38 ---------------- .../now/compose/ui/signIn/SignInScreen.kt | 15 +------ .../now/compose/ui/signIn/SignInViewModel.kt | 43 ------------------- .../now/compose/ui/signUp/SignUpScreen.kt | 17 +------- .../now/compose/ui/signUp/SignUpViewModel.kt | 32 -------------- 9 files changed, 34 insertions(+), 182 deletions(-) diff --git a/app/src/main/java/com/sopt/now/compose/data/module/ApiFactory.kt b/app/src/main/java/com/sopt/now/compose/data/module/ApiFactory.kt index b874bde..808397c 100644 --- a/app/src/main/java/com/sopt/now/compose/data/module/ApiFactory.kt +++ b/app/src/main/java/com/sopt/now/compose/data/module/ApiFactory.kt @@ -2,42 +2,35 @@ package com.sopt.now.compose.data.module import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import com.sopt.now.compose.BuildConfig -import com.sopt.now.compose.data.network.AuthService import com.sopt.now.compose.data.network.FollowerService +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 okhttp3.OkHttpClient import retrofit2.Retrofit -import retrofit2.create - +import javax.inject.Singleton +@InstallIn(SingletonComponent::class) +@Module object ApiFactory { - private const val BASE_URL: String = BuildConfig.AUTH_BASE_URL private const val FOLLOWER_URL: String = BuildConfig.FOLLOWER_URL + private val jsonConverterFactory = Json.asConverterFactory("application/json".toMediaType()) - private val interceptorClient = OkHttpClient().newBuilder() - .addInterceptor(AuthInterceptor()).build() - - val baseRetrofit: Retrofit by lazy { - Retrofit.Builder() - .baseUrl(BASE_URL) - .client(interceptorClient) - .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) - .build() - } - val followerRetrofit: Retrofit by lazy { - Retrofit.Builder() + @Provides + @Singleton + fun followerRetrofit(): Retrofit { + return Retrofit.Builder() .baseUrl(FOLLOWER_URL) - .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) + .addConverterFactory(jsonConverterFactory) .build() } - inline fun createBaseRetrofit(): T = baseRetrofit.create() - inline fun createFollowerRetrofit(): T = followerRetrofit.create() -} - -object ServicePool { - val authService = ApiFactory.createBaseRetrofit() - val followerService = ApiFactory.createFollowerRetrofit() + @Provides + @Singleton + fun provideFollowerService(followerRetrofit: Retrofit): FollowerService { + return followerRetrofit.create(FollowerService::class.java) + } } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt b/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt index 99ede21..c0a811e 100644 --- a/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt +++ b/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt @@ -1,14 +1,17 @@ package com.sopt.now.compose.repository import com.sopt.now.compose.data.model.ResponseUserDto -import com.sopt.now.compose.data.module.ServicePool +import com.sopt.now.compose.data.network.FollowerService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import retrofit2.Response +import javax.inject.Inject +import javax.inject.Singleton -class FollowerRepository { - private val followerService = ServicePool.followerService - +@Singleton +class FollowerRepository @Inject constructor( + private val followerService: FollowerService, +) { suspend fun getUserList(page: Int): Response { return withContext(Dispatchers.IO) { followerService.getUserList(page).execute() diff --git a/app/src/main/java/com/sopt/now/compose/ui/base/SoptAppNavHost.kt b/app/src/main/java/com/sopt/now/compose/ui/base/SoptAppNavHost.kt index 58ebb65..51d231e 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/base/SoptAppNavHost.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/base/SoptAppNavHost.kt @@ -13,7 +13,7 @@ import com.sopt.now.compose.ui.signUp.SignUpScreen fun SoptAppNavHost() { val navController: NavHostController = rememberNavController() - NavHost(navController = navController, startDestination = "sign_in") { + NavHost(navController = navController, startDestination = "main") { composable("sign_in") { SignInScreen( onNavigateToHome = navController, diff --git a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt index 409ddf5..76456b8 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt @@ -1,27 +1,28 @@ package com.sopt.now.compose.ui.home import android.util.Log -import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.sopt.now.compose.data.model.Profile import com.sopt.now.compose.data.model.UserDataDto import com.sopt.now.compose.repository.FollowerRepository +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import java.io.IOException +import javax.inject.Inject -class HomeViewModel : ViewModel() { - private val followerRepository = FollowerRepository() +@HiltViewModel +class HomeViewModel @Inject constructor( + private val followerRepository: FollowerRepository, +) : ViewModel() { private val _followerState = MutableStateFlow>(emptyList()) val followerState = _followerState.asStateFlow() private var _eventNetworkError = MutableLiveData(false) - val eventNetworkError: LiveData - get() = _eventNetworkError private var _isNetworkErrorShown = MutableLiveData(false) @@ -52,10 +53,6 @@ class HomeViewModel : ViewModel() { } } - fun onNetworkErrorShown() { - _isNetworkErrorShown.value = true - } - private fun mapFollowersToFriendList(followers: List) { friendList.clear() friendList.addAll(followers.map { follower -> diff --git a/app/src/main/java/com/sopt/now/compose/ui/myPage/MyPageViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/myPage/MyPageViewModel.kt index 4a773bc..a1b077c 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/myPage/MyPageViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/myPage/MyPageViewModel.kt @@ -3,16 +3,10 @@ package com.sopt.now.compose.ui.myPage import androidx.lifecycle.ViewModel import com.sopt.now.compose.data.model.ResponseInfoDto import com.sopt.now.compose.data.model.UserInfoDto -import com.sopt.now.compose.data.module.ServicePool import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response class MyPageViewModel : ViewModel() { - private val authService by lazy { ServicePool.authService } private val _infoState = MutableStateFlow( @@ -23,36 +17,4 @@ class MyPageViewModel : ViewModel() { ) ) val infoState = _infoState.asStateFlow() - - init { - fetchInfo() - } - - private fun fetchInfo() { - authService.memberInfo().enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response, - ) { - if (response.isSuccessful) { - val data = response.body() - if (data != null) { - _infoState.update { - data - } - } - } - } - - override fun onFailure(call: Call, t: Throwable) { - _infoState.update { - ResponseInfoDto( - code = -1, - message = "${t.message}", - data = UserInfoDto(authenticationId = "", nickname = "", phone = "") - ) - } - } - }) - } } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInScreen.kt b/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInScreen.kt index 1fd0b28..bce922c 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInScreen.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInScreen.kt @@ -82,20 +82,7 @@ fun SignInScreen( SoptOutlinedButton( text = R.string.btn_sign_in, onClick = { - if (isSignInButtonEnabled) { - signInViewModel.signIn( - RequestSignInDto( - authenticationId = id, - password = password, - ) - ) - } else { - Toast.makeText( - context, - R.string.sign_up_fail, - Toast.LENGTH_SHORT - ).show() - } + }, enabled = true ) diff --git a/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInViewModel.kt index 42f9c72..a39d5b6 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signIn/SignInViewModel.kt @@ -1,19 +1,11 @@ package com.sopt.now.compose.ui.signIn import androidx.lifecycle.ViewModel -import com.sopt.now.compose.data.model.RequestSignInDto -import com.sopt.now.compose.data.model.ResponseSignInDto import com.sopt.now.compose.data.model.SignInState -import com.sopt.now.compose.data.module.ServicePool import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response class SignInViewModel : ViewModel() { - private val authService by lazy { ServicePool.authService } private val _signInState = MutableStateFlow(SignInState(isSuccess = false, message = "")) val signInState = _signInState.asStateFlow() @@ -31,39 +23,4 @@ class SignInViewModel : ViewModel() { fun updatePassword(newPassword: String) { _password.value = newPassword } - - - fun signIn(request: RequestSignInDto) { - authService.signIn(request).enqueue( - object : Callback { - override fun onResponse( - call: Call, - response: Response, - ) { - if (response.isSuccessful) { - val userId = response.headers()["location"] - - _signInState.update { - SignInState( - isSuccess = true, - message = "유저 아이디는 $userId" - ) - } - } else { - val error = response.code() - _signInState.update { - SignInState( - isSuccess = false, - message = "로그인 실패 : $error" - ) - } - } - } - - override fun onFailure(call: Call, t: Throwable) { - _signInState.update { SignInState(isSuccess = false, message = "서버 에러") } - } - } - ) - } } diff --git a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt index 8fc48dd..989263c 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt @@ -124,22 +124,7 @@ fun SignUpScreen( } } SoptOutlinedButton(text = R.string.btn_sign_up, onClick = { - if (isSignUpButtonEnabled) { - signUpViewModel.signUp( - RequestSignUpDto( - authenticationId = id, - password = password, - nickname = nickname, - phone = phoneNumber - ) - ) - } else { - Toast.makeText( - context, - R.string.sign_up_fail_message, - Toast.LENGTH_SHORT - ).show() - } + }, enabled = true) } } diff --git a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpViewModel.kt index f8c0020..dad7fbc 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpViewModel.kt @@ -1,19 +1,11 @@ package com.sopt.now.compose.ui.signUp import androidx.lifecycle.ViewModel -import com.sopt.now.compose.data.model.RequestSignUpDto -import com.sopt.now.compose.data.model.ResponseSignUpDto -import com.sopt.now.compose.data.module.ServicePool import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response class SignUpViewModel : ViewModel() { - private val authService by lazy { ServicePool.authService } - private val _signUpEvent = MutableStateFlow(null) val signUpEvent = _signUpEvent.asStateFlow() @@ -45,30 +37,6 @@ class SignUpViewModel : ViewModel() { _phoneNumber.value = phoneNumber } - - fun signUp(request: RequestSignUpDto) { - authService.signUp(request).enqueue( - object : Callback { - override fun onResponse( - call: Call, - response: Response, - ) { - if (response.isSuccessful) { - val userId = response.headers()["location"] - _signUpEvent.value = SignUpSideEffect.Success("가입된 유저 아이디는 $userId") - } else { - val error = response.code() - _signUpEvent.value = SignUpSideEffect.Error("회원가입 실패 : $error") - } - } - - override fun onFailure(call: Call, t: Throwable) { - _signUpEvent.value = SignUpSideEffect.Error("서버 에러: ${t.message}") - } - }, - ) - } - companion object { const val MIN_LENGTH_LOGIN = 6 const val MAX_LENGTH_LOGIN = 10 From aae57dfecb3472ba5375e39fe8e560d308986ca5 Mon Sep 17 00:00:00 2001 From: arinming Date: Fri, 28 Jun 2024 20:48:36 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[refactor]=20hiltViewModel=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 5 +++++ .../java/com/sopt/now/compose/MainActivity.kt | 18 +++--------------- .../java/com/sopt/now/compose/ui/SoptApp.kt | 9 --------- .../com/sopt/now/compose/ui/home/HomeScreen.kt | 5 +++-- .../sopt/now/compose/ui/home/HomeViewModel.kt | 7 +++++++ 5 files changed, 18 insertions(+), 26 deletions(-) delete mode 100644 app/src/main/java/com/sopt/now/compose/ui/SoptApp.kt diff --git a/app/build.gradle b/app/build.gradle index 0cb82cc..5bb15d6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -98,4 +98,9 @@ dependencies { // Hilt implementation 'com.google.dagger:hilt-android:2.51' kapt 'com.google.dagger:hilt-compiler:2.51.1' + implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' +} + +kapt { + correctErrorTypes true } \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/compose/MainActivity.kt b/app/src/main/java/com/sopt/now/compose/MainActivity.kt index 8fb5f7e..3fcda93 100644 --- a/app/src/main/java/com/sopt/now/compose/MainActivity.kt +++ b/app/src/main/java/com/sopt/now/compose/MainActivity.kt @@ -3,12 +3,7 @@ package com.sopt.now.compose import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.ui.Modifier -import com.sopt.now.compose.ui.SoptApp -import com.sopt.now.compose.ui.theme.NOWSOPTAndroidTheme +import com.sopt.now.compose.ui.base.SoptAppNavHost import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -16,14 +11,7 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - NOWSOPTAndroidTheme { - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background - ) { - SoptApp() - } - } + SoptAppNavHost() } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/sopt/now/compose/ui/SoptApp.kt b/app/src/main/java/com/sopt/now/compose/ui/SoptApp.kt deleted file mode 100644 index aedf704..0000000 --- a/app/src/main/java/com/sopt/now/compose/ui/SoptApp.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.sopt.now.compose.ui - -import androidx.compose.runtime.Composable -import com.sopt.now.compose.ui.base.SoptAppNavHost - -@Composable -fun SoptApp() { - SoptAppNavHost() -} \ No newline at end of file diff --git a/app/src/main/java/com/sopt/now/compose/ui/home/HomeScreen.kt b/app/src/main/java/com/sopt/now/compose/ui/home/HomeScreen.kt index ec787af..dc0dded 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/home/HomeScreen.kt @@ -8,11 +8,12 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.hilt.navigation.compose.hiltViewModel import com.sopt.now.compose.R + @Composable -fun HomeScreen(homeViewModel: HomeViewModel = viewModel()) { +fun HomeScreen(homeViewModel: HomeViewModel = hiltViewModel()) { val followerState by homeViewModel.followerState.collectAsState() LazyColumn(modifier = Modifier.fillMaxSize()) { diff --git a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt index 76456b8..ef1e6e2 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt @@ -1,6 +1,7 @@ package com.sopt.now.compose.ui.home import android.util.Log +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -23,6 +24,8 @@ class HomeViewModel @Inject constructor( val followerState = _followerState.asStateFlow() private var _eventNetworkError = MutableLiveData(false) + val eventNetworkError: LiveData + get() = _eventNetworkError private var _isNetworkErrorShown = MutableLiveData(false) @@ -53,6 +56,10 @@ class HomeViewModel @Inject constructor( } } + fun onNetworkErrorShown() { + _isNetworkErrorShown.value = true + } + private fun mapFollowersToFriendList(followers: List) { friendList.clear() friendList.addAll(followers.map { follower -> From 1638b2c924b1c85be961b599858498d9b365a629 Mon Sep 17 00:00:00 2001 From: arinming Date: Mon, 1 Jul 2024 22:12:54 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[refactor]=207=EC=A3=BC=EC=B0=A8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81=20->?= =?UTF-8?q?=20loading=20=EA=B4=80=EB=A6=AC=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/sopt/now/compose/ui/home/HomeViewModel.kt | 4 +--- .../com/sopt/now/compose/ui/signUp/SignUpScreen.kt | 13 +------------ .../sopt/now/compose/ui/signUp/SignUpSideEffect.kt | 4 ++-- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt index ef1e6e2..b578881 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt @@ -24,12 +24,10 @@ class HomeViewModel @Inject constructor( val followerState = _followerState.asStateFlow() private var _eventNetworkError = MutableLiveData(false) - val eventNetworkError: LiveData - get() = _eventNetworkError private var _isNetworkErrorShown = MutableLiveData(false) - val friendList = mutableListOf() + private val friendList = mutableListOf() init { fetchFollowerList() diff --git a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt index 989263c..8a2c19e 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import com.sopt.now.compose.R -import com.sopt.now.compose.data.model.RequestSignUpDto import com.sopt.now.compose.ui.base.SoptInputTextField import com.sopt.now.compose.ui.base.SoptOutlinedButton import com.sopt.now.compose.ui.base.SoptPasswordTextField @@ -60,7 +59,7 @@ fun SignUpScreen( } is SignUpSideEffect.Loading -> { - Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show() + } is SignUpSideEffect.Error -> { @@ -87,16 +86,6 @@ fun SignUpScreen( } } - val isSignUpButtonEnabled by remember(id, password, nickname, phoneNumber) { - mutableStateOf( - id.length in MIN_LENGTH_LOGIN..MAX_LENGTH_LOGIN - && password.length in MIN_LENGTH_PASSWORD..MAX_LENGTH_PASSWORD - && nickname.isNotEmpty() && !nickname.contains( - " " - ) && phoneNumber.matches(Regex("^010-\\d{4}-\\d{4}\$")) - ) - } - Text( text = stringResource(id = R.string.sign_up_title), fontWeight = FontWeight.Bold, diff --git a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt index cd1cba6..47176ad 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/signUp/SignUpSideEffect.kt @@ -2,6 +2,6 @@ package com.sopt.now.compose.ui.signUp sealed class SignUpSideEffect { data class Success(val message: String) : SignUpSideEffect() - data class Loading(val message: String) : SignUpSideEffect() + object Loading : SignUpSideEffect() data class Error(val message: String) : SignUpSideEffect() -} \ No newline at end of file +} From e55297f50d708f8081ebf4be5c1443f0e3b37e6a Mon Sep 17 00:00:00 2001 From: arinming Date: Tue, 2 Jul 2024 18:42:02 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[refactor]=20Repository=EC=97=90=EC=84=9C?= =?UTF-8?q?=20runCatching=EC=9C=BC=EB=A1=9C=20=EC=9E=91=EC=84=B1=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compose/repository/FollowerRepository.kt | 8 ++++--- .../sopt/now/compose/ui/home/HomeViewModel.kt | 21 +++++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt b/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt index c0a811e..91a0139 100644 --- a/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt +++ b/app/src/main/java/com/sopt/now/compose/repository/FollowerRepository.kt @@ -12,9 +12,11 @@ import javax.inject.Singleton class FollowerRepository @Inject constructor( private val followerService: FollowerService, ) { - suspend fun getUserList(page: Int): Response { + suspend fun getUserList(page: Int): Result> { return withContext(Dispatchers.IO) { - followerService.getUserList(page).execute() + runCatching { + followerService.getUserList(page).execute() + } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt index b578881..8bd5773 100644 --- a/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/sopt/now/compose/ui/home/HomeViewModel.kt @@ -1,7 +1,5 @@ package com.sopt.now.compose.ui.home -import android.util.Log -import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -12,7 +10,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import java.io.IOException import javax.inject.Inject @HiltViewModel @@ -35,22 +32,20 @@ class HomeViewModel @Inject constructor( private fun fetchFollowerList() { viewModelScope.launch { - try { - val response = followerRepository.getUserList(0) - if (response.isSuccessful) { + followerRepository.getUserList(0) + .onSuccess { response -> response.body()?.data?.let { data -> _followerState.value = data mapFollowersToFriendList(data) + _eventNetworkError.value = false + _isNetworkErrorShown.value = false + } ?: run { + _eventNetworkError.value = true } - _eventNetworkError.value = false - _isNetworkErrorShown.value = false - } else { + } + .onFailure { exception -> _eventNetworkError.value = true } - } catch (networkError: IOException) { - _eventNetworkError.value = true - Log.e("HomeError", "${networkError.message}") - } } }