diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index b589d56e..9987779a 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,8 @@
-
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 0897082f..639c779c 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -4,6 +4,7 @@
-
diff --git a/app/src/main/java/com/toyou/toyouandroid/data/emotion/service/EmotionService.kt b/app/src/main/java/com/toyou/toyouandroid/data/emotion/service/EmotionService.kt
index 487c5e67..5c4b8d5a 100644
--- a/app/src/main/java/com/toyou/toyouandroid/data/emotion/service/EmotionService.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/data/emotion/service/EmotionService.kt
@@ -5,6 +5,7 @@ import com.toyou.toyouandroid.data.emotion.dto.EmotionRequest
import com.toyou.toyouandroid.data.emotion.dto.EmotionResponse
import com.toyou.toyouandroid.data.emotion.dto.YesterdayFriendsResponse
import retrofit2.Call
+import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
@@ -17,6 +18,11 @@ interface EmotionService {
@Body emotion: EmotionRequest
): Call
+ @POST("users/emotions")
+ suspend fun patchEmotionSuspend(
+ @Body emotion: EmotionRequest
+ ): Response
+
@GET("diarycards/yesterday")
fun getYesterdayFriendCard(): Call
diff --git a/app/src/main/java/com/toyou/toyouandroid/data/mypage/service/MypageService.kt b/app/src/main/java/com/toyou/toyouandroid/data/mypage/service/MypageService.kt
index 12e8bf85..620e2920 100644
--- a/app/src/main/java/com/toyou/toyouandroid/data/mypage/service/MypageService.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/data/mypage/service/MypageService.kt
@@ -2,10 +2,14 @@ package com.toyou.toyouandroid.data.mypage.service
import com.toyou.toyouandroid.data.mypage.dto.MypageResponse
import retrofit2.Call
+import retrofit2.Response
import retrofit2.http.GET
interface MypageService {
@GET("/users/mypage")
fun getMypage(): Call
+
+ @GET("/users/mypage")
+ suspend fun getMypageSuspend(): Response
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/AuthService.kt b/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/AuthService.kt
index 4a9623b0..3b837f89 100644
--- a/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/AuthService.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/AuthService.kt
@@ -3,6 +3,7 @@ package com.toyou.toyouandroid.data.onboarding.service
import com.toyou.toyouandroid.data.onboarding.dto.request.SignUpRequest
import com.toyou.toyouandroid.data.onboarding.dto.response.SignUpResponse
import retrofit2.Call
+import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.Header
@@ -25,6 +26,11 @@ interface AuthService {
@Header("refreshToken") refreshToken: String
): Call
+ @POST("auth/logout")
+ suspend fun logoutSuspend(
+ @Header("refreshToken") refreshToken: String
+ ): Response
+
@POST("auth/kakao")
fun kakaoLogin(
@Header("oauthAccessToken") accessToken: String
@@ -34,4 +40,9 @@ interface AuthService {
fun signOut(
@Header("refreshToken") refreshToken: String
): Call
+
+ @DELETE("auth/unlink")
+ suspend fun signOutSuspend(
+ @Header("refreshToken") refreshToken: String
+ ): Response
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/OnboardingService.kt b/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/OnboardingService.kt
index b6424daa..7e2c704c 100644
--- a/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/OnboardingService.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/data/onboarding/service/OnboardingService.kt
@@ -5,6 +5,7 @@ import com.toyou.toyouandroid.data.onboarding.dto.PatchNicknameRequest
import com.toyou.toyouandroid.data.onboarding.dto.PatchNicknameResponse
import com.toyou.toyouandroid.data.onboarding.dto.PatchStatusRequest
import retrofit2.Call
+import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
@@ -18,13 +19,29 @@ interface OnboardingService {
@Query("userId") userId: Int
): Call
+ @GET("users/nickname/check")
+ suspend fun getNicknameCheckSuspend(
+ @Query("nickname") nickname: String,
+ @Query("userId") userId: Int
+ ): Response
+
@PATCH("users/nickname")
fun patchNickname(
@Body request: PatchNicknameRequest
): Call
+ @PATCH("users/nickname")
+ suspend fun patchNicknameSuspend(
+ @Body request: PatchNicknameRequest
+ ): Response
+
@PATCH("users/status")
fun patchStatus(
@Body request: PatchStatusRequest
): Call
+
+ @PATCH("users/status")
+ suspend fun patchStatusSuspend(
+ @Body request: PatchStatusRequest
+ ): Response
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/di/AppModule.kt b/app/src/main/java/com/toyou/toyouandroid/di/AppModule.kt
new file mode 100644
index 00000000..85d31a67
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/di/AppModule.kt
@@ -0,0 +1,32 @@
+package com.toyou.toyouandroid.di
+
+import android.content.Context
+import com.toyou.toyouandroid.data.onboarding.service.AuthService
+import com.toyou.toyouandroid.utils.TokenManager
+import com.toyou.toyouandroid.utils.TokenStorage
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object AppModule {
+
+ @Provides
+ @Singleton
+ fun provideTokenStorage(@ApplicationContext context: Context): TokenStorage {
+ return TokenStorage(context)
+ }
+
+ @Provides
+ @Singleton
+ fun provideTokenManager(
+ authService: AuthService,
+ tokenStorage: TokenStorage
+ ): TokenManager {
+ return TokenManager(authService, tokenStorage)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/di/NetworkModule.kt b/app/src/main/java/com/toyou/toyouandroid/di/NetworkModule.kt
new file mode 100644
index 00000000..7764cb38
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/di/NetworkModule.kt
@@ -0,0 +1,64 @@
+package com.toyou.toyouandroid.di
+
+import com.toyou.toyouandroid.data.onboarding.service.AuthService
+import com.toyou.toyouandroid.data.onboarding.service.OnboardingService
+import com.toyou.toyouandroid.data.emotion.service.EmotionService
+import com.toyou.toyouandroid.data.mypage.service.MypageService
+import com.toyou.toyouandroid.data.home.service.HomeService
+import com.toyou.toyouandroid.network.AuthNetworkModule
+import com.toyou.toyouandroid.network.NetworkModule
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import retrofit2.Retrofit
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object NetworkModule {
+
+ @Provides
+ @Singleton
+ @AuthRetrofit
+ fun provideRetrofit(): Retrofit {
+ return AuthNetworkModule.getClient()
+ }
+
+ @Provides
+ @Singleton
+ @NonAuthRetrofit
+ fun provideNonAuthRetrofit(): Retrofit {
+ return NetworkModule.getClient()
+ }
+
+ @Provides
+ @Singleton
+ fun provideOnboardingService(@NonAuthRetrofit retrofit: Retrofit): OnboardingService {
+ return retrofit.create(OnboardingService::class.java)
+ }
+
+ @Provides
+ @Singleton
+ fun provideAuthService(@AuthRetrofit retrofit: Retrofit): AuthService {
+ return retrofit.create(AuthService::class.java)
+ }
+
+ @Provides
+ @Singleton
+ fun provideEmotionService(@AuthRetrofit retrofit: Retrofit): EmotionService {
+ return retrofit.create(EmotionService::class.java)
+ }
+
+ @Provides
+ @Singleton
+ fun provideMypageService(@AuthRetrofit retrofit: Retrofit): MypageService {
+ return retrofit.create(MypageService::class.java)
+ }
+
+ @Provides
+ @Singleton
+ fun provideHomeService(@AuthRetrofit retrofit: Retrofit): HomeService {
+ return retrofit.create(HomeService::class.java)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/di/Qualifiers.kt b/app/src/main/java/com/toyou/toyouandroid/di/Qualifiers.kt
new file mode 100644
index 00000000..7346e51d
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/di/Qualifiers.kt
@@ -0,0 +1,11 @@
+package com.toyou.toyouandroid.di
+
+import javax.inject.Qualifier
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class AuthRetrofit
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class NonAuthRetrofit
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/di/RepositoryModule.kt b/app/src/main/java/com/toyou/toyouandroid/di/RepositoryModule.kt
new file mode 100644
index 00000000..934e14fe
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/di/RepositoryModule.kt
@@ -0,0 +1,22 @@
+package com.toyou.toyouandroid.di
+
+import com.toyou.toyouandroid.data.onboarding.service.OnboardingService
+import com.toyou.toyouandroid.domain.profile.repository.ProfileRepository
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object RepositoryModule {
+
+ @Provides
+ @Singleton
+ fun provideProfileRepository(
+ onboardingService: OnboardingService
+ ): ProfileRepository {
+ return ProfileRepository(onboardingService)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/domain/home/repository/HomeRepository.kt b/app/src/main/java/com/toyou/toyouandroid/domain/home/repository/HomeRepository.kt
index bb2367a3..102ceb3a 100644
--- a/app/src/main/java/com/toyou/toyouandroid/domain/home/repository/HomeRepository.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/domain/home/repository/HomeRepository.kt
@@ -1,14 +1,14 @@
package com.toyou.toyouandroid.domain.home.repository
-import com.toyou.toyouandroid.data.home.dto.response.YesterdayCardResponse
import com.toyou.toyouandroid.data.home.service.HomeService
-import com.toyou.toyouandroid.network.AuthNetworkModule
-import com.toyou.toyouandroid.network.BaseResponse
+import javax.inject.Inject
+import javax.inject.Singleton
-class HomeRepository {
- private val client = AuthNetworkModule.getClient().create(HomeService::class.java)
+@Singleton
+class HomeRepository @Inject constructor(
+ private val homeService: HomeService
+) {
+ suspend fun getCardDetail(id: Long) = homeService.getCardDetail(id)
- suspend fun getCardDetail(id : Long)=client.getCardDetail(id)
-
- suspend fun getYesterdayCard() = client.getCardYesterday()
+ suspend fun getYesterdayCard() = homeService.getCardYesterday()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/domain/profile/repository/ProfileRepository.kt b/app/src/main/java/com/toyou/toyouandroid/domain/profile/repository/ProfileRepository.kt
new file mode 100644
index 00000000..e72d9ad5
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/domain/profile/repository/ProfileRepository.kt
@@ -0,0 +1,24 @@
+package com.toyou.toyouandroid.domain.profile.repository
+
+import com.toyou.toyouandroid.data.onboarding.dto.NicknameCheckResponse
+import com.toyou.toyouandroid.data.onboarding.dto.PatchNicknameRequest
+import com.toyou.toyouandroid.data.onboarding.dto.PatchNicknameResponse
+import com.toyou.toyouandroid.data.onboarding.dto.PatchStatusRequest
+import com.toyou.toyouandroid.data.onboarding.service.OnboardingService
+import retrofit2.Response
+
+class ProfileRepository(
+ private val onboardingService: OnboardingService
+) {
+ suspend fun checkNickname(nickname: String, userId: Int): Response {
+ return onboardingService.getNicknameCheckSuspend(nickname, userId)
+ }
+
+ suspend fun updateNickname(nickname: String): Response {
+ return onboardingService.patchNicknameSuspend(PatchNicknameRequest(nickname))
+ }
+
+ suspend fun updateStatus(status: String): Response {
+ return onboardingService.patchStatusSuspend(PatchStatusRequest(status))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt
index 667ec100..f1af097b 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt
@@ -16,8 +16,10 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.toyou.toyouandroid.R
import com.toyou.toyouandroid.databinding.ActivityMainBinding
+import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
+@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt
index 88303f70..0bcb43ff 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt
@@ -7,6 +7,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.Navigation
@@ -25,12 +26,14 @@ import com.toyou.toyouandroid.network.NetworkModule
import com.toyou.toyouandroid.presentation.fragment.notice.NoticeDialog
import com.toyou.toyouandroid.presentation.fragment.notice.NoticeDialogViewModel
import com.toyou.toyouandroid.presentation.fragment.home.HomeViewModel
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
+import dagger.hilt.android.AndroidEntryPoint
+import androidx.navigation.findNavController
+@AndroidEntryPoint
class HomeOptionFragment : Fragment() {
lateinit var navController: NavController
@@ -42,13 +45,13 @@ class HomeOptionFragment : Fragment() {
private var noticeDialog: NoticeDialog? = null
private lateinit var userViewModel: UserViewModel
- private lateinit var homeOptionViewModel: HomeOptionViewModel
- private lateinit var homeViewModel: HomeViewModel
+ private val homeOptionViewModel: HomeOptionViewModel by viewModels()
+ private val homeViewModel: HomeViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
+ savedInstanceState: Bundle?,
): View {
_binding = FragmentHomeOptionBinding.inflate(layoutInflater, container, false)
@@ -58,21 +61,8 @@ class HomeOptionFragment : Fragment() {
val createService = AuthNetworkModule.getClient().create(CreateService::class.java)
val createRepository = CreateRepository(createService)
- val homeRepository = HomeRepository()
- homeOptionViewModel = ViewModelProvider(
- this,
- HomeViewModelFactory(
- tokenManager, homeRepository
- )
- )[HomeOptionViewModel::class.java]
-
- homeViewModel = ViewModelProvider(
- this,
- HomeViewModelFactory(
- tokenManager, homeRepository
- )
- )[HomeViewModel::class.java]
+ // HomeOptionViewModel과 HomeViewModel은 Hilt로 주입됨
userViewModel = ViewModelProvider(
requireActivity(),
@@ -84,7 +74,7 @@ class HomeOptionFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- navController = Navigation.findNavController(view)
+ navController = view.findNavController()
(requireActivity() as MainActivity).hideBottomNavigation(true)
@@ -207,10 +197,10 @@ class HomeOptionFragment : Fragment() {
}
homeViewModel.updateHomeEmotion(
- emotionData.homeEmotionDrawable,
- emotionData.homeEmotionTitle,
- emotionData.homeColorRes,
- emotionData.backgroundDrawable
+ emotionData.homeEmotionDrawable.toString(),
+// emotionData.homeEmotionTitle,
+// emotionData.homeColorRes,
+// emotionData.backgroundDrawable
)
// 감정 우표 선택 API 호출
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionViewModel.kt
index 7d7e70eb..c62f153c 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionViewModel.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionViewModel.kt
@@ -3,47 +3,61 @@ package com.toyou.toyouandroid.presentation.fragment.emotionstamp
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import com.toyou.toyouandroid.network.AuthNetworkModule
+import androidx.lifecycle.viewModelScope
import com.toyou.toyouandroid.data.emotion.dto.EmotionRequest
import com.toyou.toyouandroid.data.emotion.dto.EmotionResponse
import com.toyou.toyouandroid.data.emotion.service.EmotionService
import com.toyou.toyouandroid.utils.TokenManager
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
import timber.log.Timber
+import javax.inject.Inject
-
-class HomeOptionViewModel(private val tokenManager: TokenManager) : ViewModel() {
+@HiltViewModel
+class HomeOptionViewModel @Inject constructor(
+ private val emotionService: EmotionService,
+ private val tokenManager: TokenManager
+) : ViewModel() {
private val _emotionResponse = MutableLiveData()
val emotionResponse: LiveData get() = _emotionResponse
- private val apiService: EmotionService = AuthNetworkModule.getClient().create(EmotionService::class.java)
+ private val _isLoading = MutableLiveData()
+ val isLoading: LiveData get() = _isLoading
- fun updateEmotion(emotionRequest: EmotionRequest) {
- val call = apiService.patchEmotion(emotionRequest)
+ private val _errorMessage = MutableLiveData()
+ val errorMessage: LiveData get() = _errorMessage
- call.enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
+ fun updateEmotion(emotionRequest: EmotionRequest) {
+ viewModelScope.launch {
+ _isLoading.value = true
+ _errorMessage.value = null
+
+ try {
+ val response = emotionService.patchEmotionSuspend(emotionRequest)
if (response.isSuccessful) {
_emotionResponse.postValue(response.body())
Timber.tag("emotionResponse").d("emotionResponse: $response")
} else {
- tokenManager.refreshToken(
- onSuccess = { updateEmotion(emotionRequest) }, // 토큰 갱신 후 다시 요청
- onFailure = { Timber.e("Failed to refresh token and get notices") }
- )
Timber.tag("API Error").e("Failed to update emotion. Code: ${response.code()}, Message: ${response.message()}")
+ if (response.code() == 401) {
+ tokenManager.refreshToken(
+ onSuccess = { updateEmotion(emotionRequest) },
+ onFailure = {
+ Timber.e("Failed to refresh token and update emotion")
+ _errorMessage.value = "인증 실패. 다시 로그인해주세요."
+ }
+ )
+ } else {
+ _errorMessage.value = "감정 업데이트에 실패했습니다."
+ }
}
+ } catch (e: Exception) {
+ Timber.tag("API Failure").e(e, "Error occurred during API call")
+ _errorMessage.value = "네트워크 오류가 발생했습니다."
+ } finally {
+ _isLoading.value = false
}
-
- override fun onFailure(call: Call, t: Throwable) {
- Timber.tag("API Failure").e(t, "Error occurred during API call")
- }
- })
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeFragment.kt
index aa294277..284b14e1 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeFragment.kt
@@ -9,6 +9,7 @@ import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.Navigation
@@ -35,13 +36,15 @@ import com.toyou.toyouandroid.presentation.fragment.record.CardInfoViewModel
import com.toyou.toyouandroid.presentation.viewmodel.RecordViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.CardViewModel
import com.toyou.toyouandroid.presentation.viewmodel.CardViewModelFactory
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
+import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
+import androidx.navigation.findNavController
+@AndroidEntryPoint
class HomeFragment : Fragment() {
private lateinit var navController: NavController
@@ -49,7 +52,7 @@ class HomeFragment : Fragment() {
private val binding: FragmentHomeBinding
get() = requireNotNull(_binding){"FragmentHomeBinding -> null"}
private lateinit var noticeViewModel: NoticeViewModel
- private lateinit var viewModel: HomeViewModel
+ private val viewModel: HomeViewModel by viewModels()
private lateinit var bottomSheetBehavior: BottomSheetBehavior
@@ -67,6 +70,9 @@ class HomeFragment : Fragment() {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
+ // HomeViewModel은 Hilt로 주입됨
+
+ // 다른 ViewModel들은 기존 방식 유지
val tokenStorage = TokenStorage(requireContext())
val authService = NetworkModule.getClient().create(AuthService::class.java)
val tokenManager = TokenManager(authService, tokenStorage)
@@ -78,19 +84,12 @@ class HomeFragment : Fragment() {
val recordRepository = RecordRepository(recordService)
val createService = AuthNetworkModule.getClient().create(CreateService::class.java)
val createRepository = CreateRepository(createService)
- val homeRepository = HomeRepository()
-
noticeViewModel = ViewModelProvider(
this,
NoticeViewModelFactory(noticeRepository, tokenManager)
)[NoticeViewModel::class.java]
- viewModel = ViewModelProvider(
- this,
- HomeViewModelFactory(tokenManager, homeRepository)
- )[HomeViewModel::class.java]
-
binding.lifecycleOwner = viewLifecycleOwner
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
@@ -135,7 +134,7 @@ class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- navController = Navigation.findNavController(view)
+ navController = view.findNavController()
(requireActivity() as MainActivity).hideBottomNavigation(false)
@@ -199,17 +198,17 @@ class HomeFragment : Fragment() {
setOnClickListener {}
}
- // 홈 화면 바텀 시트 설정
- viewModel.yesterdayCards.observe(viewLifecycleOwner) { yesterdayCards ->
- if (yesterdayCards.isNotEmpty()) {
- binding.homeBottomsheetPseudo.visibility = View.GONE
- binding.homeBottomSheetRv.visibility = View.VISIBLE
- setupRecyclerView(yesterdayCards)
- } else {
- binding.homeBottomsheetPseudo.visibility = View.VISIBLE
- binding.homeBottomSheetRv.visibility = View.GONE
- }
- }
+// // 홈 화면 바텀 시트 설정
+// viewModel.yesterdayCards.observe(viewLifecycleOwner) { yesterdayCards ->
+// if (yesterdayCards.isNotEmpty()) {
+// binding.homeBottomsheetPseudo.visibility = View.GONE
+// binding.homeBottomSheetRv.visibility = View.VISIBLE
+// setupRecyclerView(yesterdayCards)
+// } else {
+// binding.homeBottomsheetPseudo.visibility = View.VISIBLE
+// binding.homeBottomSheetRv.visibility = View.GONE
+// }
+// }
// 우체통 클릭시 일기카드 생성 화면으로 전환(임시)
binding.homeMailboxIv.setOnClickListener {
@@ -221,7 +220,7 @@ class HomeFragment : Fragment() {
cardViewModel.disableLock(false)
}
else {
- cardViewModel.getCardDetail(cardId.toLong())
+// cardViewModel.getCardDetail(cardId.toLong())
navController.navigate(R.id.action_navigation_home_to_modifyFragment)
cardViewModel.disableLock(true)
}
@@ -243,68 +242,68 @@ class HomeFragment : Fragment() {
navController.navigate(R.id.action_navigation_home_to_home_option_fragment)
}
- // 홈화면 조회 후 사용자의 당일 감정우표 반영
- userViewModel.emotion.observe(viewLifecycleOwner) { emotion ->
- when (emotion) {
- "HAPPY" -> {
- viewModel.updateHomeEmotion(
- R.drawable.home_emotion_happy,
- getString(R.string.home_emotion_happy_title),
- R.color.y01,
- R.drawable.background_yellow
- )
- }
- "EXCITED" -> {
- viewModel.updateHomeEmotion(
- R.drawable.home_emotion_exciting,
- getString(R.string.home_emotion_exciting_title),
- R.color.b01,
- R.drawable.background_skyblue
- )
- }
- "NORMAL" -> {
- viewModel.updateHomeEmotion(
- R.drawable.home_emotion_normal,
- getString(R.string.home_emotion_normal_title),
- R.color.p01,
- R.drawable.background_purple
- )
- }
- "NERVOUS" -> {
- viewModel.updateHomeEmotion(
- R.drawable.home_emotion_anxiety,
- getString(R.string.home_emotion_anxiety_title),
- R.color.g02,
- R.drawable.background_green
- )
- }
- "ANGRY" -> {
- viewModel.updateHomeEmotion(
- R.drawable.home_emotion_upset,
- getString(R.string.home_emotion_upset_title),
- R.color.r01,
- R.drawable.background_red
- )
- }
- }
- }
+// // 홈화면 조회 후 사용자의 당일 감정우표 반영
+// userViewModel.emotion.observe(viewLifecycleOwner) { emotion ->
+// when (emotion) {
+// "HAPPY" -> {
+// viewModel.updateHomeEmotion(
+// R.drawable.home_emotion_happy,
+// getString(R.string.home_emotion_happy_title),
+// R.color.y01,
+// R.drawable.background_yellow
+// )
+// }
+// "EXCITED" -> {
+// viewModel.updateHomeEmotion(
+// R.drawable.home_emotion_exciting,
+// getString(R.string.home_emotion_exciting_title),
+// R.color.b01,
+// R.drawable.background_skyblue
+// )
+// }
+// "NORMAL" -> {
+// viewModel.updateHomeEmotion(
+// R.drawable.home_emotion_normal,
+// getString(R.string.home_emotion_normal_title),
+// R.color.p01,
+// R.drawable.background_purple
+// )
+// }
+// "NERVOUS" -> {
+// viewModel.updateHomeEmotion(
+// R.drawable.home_emotion_anxiety,
+// getString(R.string.home_emotion_anxiety_title),
+// R.color.g02,
+// R.drawable.background_green
+// )
+// }
+// "ANGRY" -> {
+// viewModel.updateHomeEmotion(
+// R.drawable.home_emotion_upset,
+// getString(R.string.home_emotion_upset_title),
+// R.color.r01,
+// R.drawable.background_red
+// )
+// }
+// }
+// }
// 감정 선택에 따른 홈화면 리소스 변경
- viewModel.currentDate.observe(viewLifecycleOwner) { date ->
- binding.homeDateTv.text = date
- }
- viewModel.homeEmotion.observe(viewLifecycleOwner) { emotion ->
- binding.homeEmotionIv.setImageResource(emotion)
- }
- viewModel.text.observe(viewLifecycleOwner) { text ->
- binding.homeEmotionTv.text = text
- }
- viewModel.homeDateBackground.observe(viewLifecycleOwner) { date ->
- binding.homeDateTv.setBackgroundResource(date)
- }
- viewModel.homeBackground.observe(viewLifecycleOwner) { background ->
- binding.layoutHome.setBackgroundResource(background)
- }
+// viewModel.currentDate.observe(viewLifecycleOwner) { date ->
+// binding.homeDateTv.text = date
+// }
+// viewModel.homeEmotion.observe(viewLifecycleOwner) { emotion ->
+// binding.homeEmotionIv.setImageResource(emotion)
+// }
+// viewModel.text.observe(viewLifecycleOwner) { text ->
+// binding.homeEmotionTv.text = text
+// }
+// viewModel.homeDateBackground.observe(viewLifecycleOwner) { date ->
+// binding.homeDateTv.setBackgroundResource(date)
+// }
+// viewModel.homeBackground.observe(viewLifecycleOwner) { background ->
+// binding.layoutHome.setBackgroundResource(background)
+// }
// 알림 존재할 경우 알림 아이콘 빨간점 표시
userViewModel.uncheckedAlarm.observe(viewLifecycleOwner) { uncheckedAlarm ->
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeUiState.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeUiState.kt
new file mode 100644
index 00000000..c2c9b921
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeUiState.kt
@@ -0,0 +1,13 @@
+package com.toyou.toyouandroid.presentation.fragment.home
+
+import com.toyou.toyouandroid.data.emotion.dto.DiaryCard
+import com.toyou.toyouandroid.data.home.dto.response.YesterdayCard
+
+data class HomeUiState(
+ val currentDate: String = "",
+ val emotionText: String = "멘트",
+ val diaryCards: List? = null,
+ val yesterdayCards: List = emptyList(),
+ val isLoading: Boolean = false,
+ val isEmpty: Boolean = false
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeViewModel.kt
index b7e56c35..6e27eeec 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeViewModel.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/HomeViewModel.kt
@@ -4,89 +4,77 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import com.toyou.toyouandroid.R
-import com.toyou.toyouandroid.network.AuthNetworkModule
-import com.toyou.toyouandroid.data.emotion.dto.DiaryCard
-import com.toyou.toyouandroid.data.emotion.service.EmotionService
-import com.toyou.toyouandroid.data.emotion.dto.YesterdayFriendsResponse
-import com.toyou.toyouandroid.data.home.dto.response.YesterdayCard
import com.toyou.toyouandroid.domain.home.repository.HomeRepository
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.calendar.getCurrentDate
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
import timber.log.Timber
-import kotlin.math.log
+import javax.inject.Inject
-class HomeViewModel(private val tokenManager: TokenManager,
- private val repository: HomeRepository) : ViewModel() {
+@HiltViewModel
+class HomeViewModel @Inject constructor(
+ private val homeRepository: HomeRepository,
+ private val tokenManager: TokenManager
+) : ViewModel() {
- private val _homeEmotion = MutableLiveData()
- val homeEmotion: LiveData get() = _homeEmotion
-
- private val _text = MutableLiveData()
- val text: LiveData get() = _text
-
- private val _homeDateBackground = MutableLiveData()
- val homeDateBackground: LiveData get() = _homeDateBackground
-
- private val _homeBackground = MutableLiveData()
- val homeBackground: LiveData get() = _homeBackground
-
- private val _currentDate = MutableLiveData()
- val currentDate: LiveData get() = _currentDate
-
- private val _diaryCards = MutableLiveData?>()
- val diaryCards: LiveData?> get() = _diaryCards
-
- private val _isLoading = MutableLiveData()
- val isLoading: LiveData get() = _isLoading
-
- private val _yesterdayCards = MutableLiveData>()
- val yesterdayCards: LiveData> = _yesterdayCards
-
- private val _isEmpty = MutableLiveData()
- val isEmpty: LiveData get() = _isEmpty
-
- private val apiService: EmotionService = AuthNetworkModule.getClient().create(EmotionService::class.java)
+ private val _uiState = MutableLiveData(HomeUiState())
+ val uiState: LiveData get() = _uiState
init {
- _currentDate.value = getCurrentDate()
+ _uiState.value = _uiState.value?.copy(
+ currentDate = getCurrentDate()
+ )
}
- fun updateHomeEmotion(emotion: Int, text: String, date: Int, background: Int) {
- _homeEmotion.value = emotion
- _text.value = text
- _homeDateBackground.value = date
- _homeBackground.value = background
+ fun updateHomeEmotion(emotionText: String) {
+ _uiState.value = _uiState.value?.copy(
+ emotionText = emotionText
+ )
}
fun resetState() {
- _homeEmotion.value = R.drawable.home_emotion_none
- _text.value = "멘트"
- _homeDateBackground.value = R.color.g00
- _homeBackground.value = R.drawable.background_white
+ _uiState.value = _uiState.value?.copy(
+ emotionText = "멘트",
+ diaryCards = null,
+ yesterdayCards = emptyList()
+ )
}
+
fun getYesterdayCard() {
viewModelScope.launch {
+ _uiState.value = _uiState.value?.copy(isLoading = true)
try {
- val response = repository.getYesterdayCard()
+ val response = homeRepository.getYesterdayCard()
Timber.tag("HomeViewModel").d("yesterdayCards: ${response.result}")
if (response.isSuccess) {
- _yesterdayCards.value = response.result.yesterday
+ _uiState.value = _uiState.value?.copy(
+ yesterdayCards = response.result.yesterday,
+ isLoading = false,
+ isEmpty = response.result.yesterday.isEmpty()
+ )
Timber.tag("HomeViewModel").d("yesterdayCards: ${response.result.yesterday}")
} else {
+ _uiState.value = _uiState.value?.copy(isLoading = false)
tokenManager.refreshToken(
onSuccess = { getYesterdayCard() },
- onFailure = { Timber.tag("HomeViewModel").d("refresh error") }
+ onFailure = {
+ Timber.tag("HomeViewModel").d("refresh error")
+ _uiState.value = _uiState.value?.copy(
+ isLoading = false,
+ yesterdayCards = emptyList()
+ )
+ }
)
}
} catch (e: Exception) {
- _yesterdayCards.value = emptyList()
+ Timber.tag("HomeViewModel").e(e, "Error getting yesterday cards")
+ _uiState.value = _uiState.value?.copy(
+ yesterdayCards = emptyList(),
+ isLoading = false,
+ isEmpty = true
+ )
}
}
}
-
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/ModifyFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/ModifyFragment.kt
index b69a1b36..a967fe76 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/ModifyFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/ModifyFragment.kt
@@ -18,7 +18,6 @@ import com.toyou.toyouandroid.network.AuthNetworkModule
import com.toyou.toyouandroid.network.NetworkModule
import com.toyou.toyouandroid.presentation.viewmodel.CardViewModel
import com.toyou.toyouandroid.presentation.viewmodel.CardViewModelFactory
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/PreviewFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/PreviewFragment.kt
index 0bc90fe3..cbc0d933 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/PreviewFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/home/PreviewFragment.kt
@@ -20,7 +20,6 @@ import com.toyou.toyouandroid.network.AuthNetworkModule
import com.toyou.toyouandroid.network.NetworkModule
import com.toyou.toyouandroid.presentation.viewmodel.CardViewModel
import com.toyou.toyouandroid.presentation.viewmodel.CardViewModelFactory
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
import com.toyou.toyouandroid.utils.TokenManager
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt
index 2642091b..6dab2ead 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt
@@ -5,36 +5,29 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
-import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.ViewModelProvider
+import androidx.fragment.app.viewModels
import androidx.navigation.NavController
-import androidx.navigation.Navigation
import com.kakao.sdk.user.UserApiClient
import com.toyou.toyouandroid.R
import com.toyou.toyouandroid.databinding.FragmentMypageBinding
import com.toyou.toyouandroid.presentation.base.MainActivity
import com.toyou.toyouandroid.presentation.fragment.onboarding.SignupNicknameViewModel
-import com.toyou.toyouandroid.data.onboarding.service.AuthService
-import com.toyou.toyouandroid.domain.home.repository.HomeRepository
-import com.toyou.toyouandroid.network.AuthNetworkModule
-import com.toyou.toyouandroid.network.NetworkModule
-import com.toyou.toyouandroid.presentation.viewmodel.AuthViewModelFactory
import com.toyou.toyouandroid.presentation.fragment.home.HomeViewModel
-import com.toyou.toyouandroid.presentation.fragment.record.CalendarDialog
import com.toyou.toyouandroid.presentation.fragment.record.CalendarDialogViewModel
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
-import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.presentation.viewmodel.ViewModelManager
-import com.toyou.toyouandroid.utils.TokenStorage
import com.toyou.toyouandroid.utils.TutorialStorage
+import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
+import androidx.navigation.findNavController
+import androidx.core.net.toUri
+@AndroidEntryPoint
class MypageFragment : Fragment() {
private lateinit var navController: NavController
@@ -50,20 +43,12 @@ class MypageFragment : Fragment() {
private val calendarDialogViewModel: CalendarDialogViewModel by activityViewModels()
private var mypageDialog: MypageDialog? = null
private var myPageLogoutDialog: MyPageLogoutDialog? = null
- private var calendarDialog: CalendarDialog? = null
- private lateinit var homeViewModel: HomeViewModel
+ private val homeViewModel: HomeViewModel by viewModels()
private var sharedPreferences: SharedPreferences? = null
- private val mypageViewModel: MypageViewModel by activityViewModels {
- val tokenStorage = TokenStorage(requireContext())
- val authService: AuthService = NetworkModule.getClient().create(AuthService::class.java)
- val tokenManager = TokenManager(authService, tokenStorage)
-
- val authService2: AuthService = AuthNetworkModule.getClient().create(AuthService::class.java)
- AuthViewModelFactory(authService2, tokenStorage, tokenManager)
- }
+ private val mypageViewModel: MypageViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
@@ -72,15 +57,7 @@ class MypageFragment : Fragment() {
): View {
_binding = FragmentMypageBinding.inflate(inflater, container, false)
- val tokenStorage = TokenStorage(requireContext())
- val authService: AuthService = NetworkModule.getClient().create(AuthService::class.java)
- val tokenManager = TokenManager(authService, tokenStorage)
- val homeRepository = HomeRepository()
-
- homeViewModel = ViewModelProvider(
- this,
- HomeViewModelFactory(tokenManager, homeRepository)
- )[HomeViewModel::class.java]
+ // MypageViewModel과 HomeViewModel은 Hilt로 주입됨
sharedPreferences = requireActivity().getSharedPreferences("FCM_PREFERENCES", Context.MODE_PRIVATE)
@@ -89,7 +66,7 @@ class MypageFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- navController = Navigation.findNavController(view)
+ navController = view.findNavController()
(requireActivity() as MainActivity).hideBottomNavigation(false)
@@ -97,7 +74,7 @@ class MypageFragment : Fragment() {
mypageViewModel.updateMypage()
binding.mypageProfileBtn.setOnClickListener {
- navController.navigate(R.id.action_navigation_mypage_to_profile_fragment) // 프로필 화면으로 이동
+ navController.navigate(R.id.action_navigation_mypage_to_profile_fragment)
}
binding.mypageNoticeSetting.setOnClickListener {
@@ -128,27 +105,25 @@ class MypageFragment : Fragment() {
redirectLink("https://sumptuous-metacarpal-d3a.notion.site/1437c09ca64e80fb88f6d8ab881ffee3")
}
- // 사용자 닉네임 설정
- nicknameViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
- binding.profileNickname.text = nickname
- }
+ mypageViewModel.uiState.observe(viewLifecycleOwner) { uiState ->
+ uiState.nickname?.let { nickname ->
+ binding.profileNickname.text = nickname
+ }
- // 사용자 친구 수 설정
- mypageViewModel.friendNum.observe(viewLifecycleOwner) {friendNum ->
- val friendText = if (friendNum != null) {
- "친구 ${friendNum}명"
+ val friendText = if (uiState.friendNum != null) {
+ "친구 ${uiState.friendNum}명"
} else {
"친구 0명"
}
binding.profileFriendCount.text = friendText
}
- // 닉네임 변경시 프로필에 반영
- mypageViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
- binding.profileNickname.text = nickname
+ nicknameViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
+ if (mypageViewModel.uiState.value?.nickname == null) {
+ binding.profileNickname.text = nickname
+ }
}
- // 로그아웃 성공시 로그인 화면으로 이동
mypageViewModel.logoutSuccess.observe(viewLifecycleOwner) { isSuccess ->
if (isSuccess) {
mypageViewModel.setLogoutSuccess(false)
@@ -160,7 +135,6 @@ class MypageFragment : Fragment() {
}
}
- // 회원 탈퇴 성공시 로그인 화면으로 이동
mypageViewModel.signOutSuccess.observe(viewLifecycleOwner) { isSuccess ->
if (isSuccess) {
mypageViewModel.setSignOutSuccess(false)
@@ -201,7 +175,6 @@ class MypageFragment : Fragment() {
}
}
- // 회원 탈퇴
private fun handleSignout() {
Timber.tag("handleSignout").d("handleSignout")
@@ -214,7 +187,6 @@ class MypageFragment : Fragment() {
}
}
- // 회원 탈퇴 후 튜토리얼 다시 보이도록 설정
TutorialStorage(requireContext()).setTutorialNotShown()
sharedPreferences?.edit()?.putBoolean("isSubscribed", true)?.apply()
@@ -222,7 +194,6 @@ class MypageFragment : Fragment() {
mypageDialog?.dismiss()
}
- // 회원 로그아웃
private fun handleLogout() {
Timber.tag("handleLogout").d("handleWithdraw")
@@ -251,7 +222,7 @@ class MypageFragment : Fragment() {
private fun redirectLink(uri: String) {
val i = Intent(Intent.ACTION_VIEW)
- i.data = Uri.parse(uri)
+ i.data = uri.toUri()
startActivity(i)
}
override fun onDestroyView() {
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageUiState.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageUiState.kt
new file mode 100644
index 00000000..364adc4e
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageUiState.kt
@@ -0,0 +1,9 @@
+package com.toyou.toyouandroid.presentation.fragment.mypage
+
+data class MypageUiState(
+ val userId: Int? = null,
+ val nickname: String? = null,
+ val status: String? = null,
+ val friendNum: Int? = null,
+ val isLoading: Boolean = false
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt
index df4bfbdb..ad1f4a2f 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt
@@ -4,86 +4,85 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import com.toyou.toyouandroid.network.AuthNetworkModule
-import com.toyou.toyouandroid.data.mypage.dto.MypageResponse
import com.toyou.toyouandroid.data.mypage.service.MypageService
-import com.toyou.toyouandroid.data.onboarding.dto.response.SignUpResponse
import com.toyou.toyouandroid.data.onboarding.service.AuthService
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
import timber.log.Timber
+import javax.inject.Inject
-class MypageViewModel(
+@HiltViewModel
+class MypageViewModel @Inject constructor(
private val authService: AuthService,
+ private val mypageService: MypageService,
private val tokenStorage: TokenStorage,
private val tokenManager: TokenManager
) : ViewModel() {
+ private val _uiState = MutableLiveData(MypageUiState())
+ val uiState: LiveData get() = _uiState
+
private val _logoutSuccess = MutableLiveData()
val logoutSuccess: LiveData get() = _logoutSuccess
+ private val _signOutSuccess = MutableLiveData()
+ val signOutSuccess: LiveData get() = _signOutSuccess
+
fun setLogoutSuccess(value: Boolean) {
_logoutSuccess.value = value
}
+ fun setSignOutSuccess(value: Boolean) {
+ _signOutSuccess.value = value
+ }
+
fun kakaoLogout() {
viewModelScope.launch {
val refreshToken = tokenStorage.getRefreshToken().toString()
val accessToken = tokenStorage.getAccessToken().toString()
- Timber.d("Attempting to logout in with refresh token: $refreshToken")
+ Timber.d("Attempting to logout with refresh token: $refreshToken")
Timber.d("accessToken: $accessToken")
- authService.logout(refreshToken).enqueue(object : Callback {
- override fun onResponse(call: Call, response: Response) {
- if (response.isSuccessful) {
- Timber.i("Logout successfully")
- _logoutSuccess.value = true
- tokenStorage.clearTokens()
+ try {
+ val response = authService.logoutSuspend(refreshToken)
+ if (response.isSuccessful) {
+ Timber.i("Logout successfully")
+ _logoutSuccess.value = true
+ tokenStorage.clearTokens()
+ } else {
+ val errorMessage = response.errorBody()?.string() ?: "Unknown error: ${response.message()}"
+ Timber.e("API Error: $errorMessage")
+
+ if (response.code() == 401) {
+ tokenManager.refreshToken(
+ onSuccess = { kakaoLogout() },
+ onFailure = {
+ Timber.e("Failed to refresh token and kakao logout")
+ _logoutSuccess.value = false
+ }
+ )
} else {
- val errorMessage = response.errorBody()?.string() ?: "Unknown error: ${response.message()}"
- Timber.e("API Error: $errorMessage")
_logoutSuccess.value = false
-
- // 토큰 만료 시 토큰 갱신 후 로그아웃 재시도
- if (response.code() == 401) {
- tokenManager.refreshToken(
- onSuccess = { kakaoLogout() }, // 토큰 갱신 후 로그아웃 재시도
- onFailure = { Timber.e("Failed to refresh token and kakao logout") }
- )
- } else {
- _logoutSuccess.value = false
- }
}
}
-
- override fun onFailure(call: Call, t: Throwable) {
- val errorMessage = t.message ?: "Unknown error"
- Timber.e("Network Failure: $errorMessage")
- _logoutSuccess.value = false
- }
- })
+ } catch (e: Exception) {
+ Timber.e("Network Failure: ${e.message}")
+ _logoutSuccess.value = false
+ }
}
}
- private val _signOutSuccess = MutableLiveData()
- val signOutSuccess: LiveData get() = _signOutSuccess
-
- fun setSignOutSuccess(value: Boolean) {
- _signOutSuccess.value = value
- }
-
fun kakaoSignOut() {
- val refreshToken = tokenStorage.getRefreshToken().toString()
- val accessToken = tokenStorage.getAccessToken().toString()
- Timber.d("Attempting to signout in with refresh token: $refreshToken")
- Timber.d("accessToken: $accessToken")
+ viewModelScope.launch {
+ val refreshToken = tokenStorage.getRefreshToken().toString()
+ val accessToken = tokenStorage.getAccessToken().toString()
+ Timber.d("Attempting to signout with refresh token: $refreshToken")
+ Timber.d("accessToken: $accessToken")
- authService.signOut(refreshToken).enqueue(object : Callback {
- override fun onResponse(call: Call, response: Response) {
+ try {
+ val response = authService.signOutSuspend(refreshToken)
if (response.isSuccessful) {
Timber.i("SignOut successfully")
_signOutSuccess.value = true
@@ -91,70 +90,52 @@ class MypageViewModel(
} else {
val errorMessage = response.errorBody()?.string() ?: "Unknown error"
Timber.e("API Error: $errorMessage")
- _signOutSuccess.value = false
tokenManager.refreshToken(
onSuccess = { kakaoSignOut() },
- onFailure = { Timber.e("Failed to refresh token and kakao signout") }
+ onFailure = {
+ Timber.e("Failed to refresh token and kakao signout")
+ _signOutSuccess.value = false
+ }
)
}
- }
-
- override fun onFailure(call: Call, t: Throwable) {
- val errorMessage = t.message ?: "Unknown error"
- Timber.e("Network Failure: $errorMessage")
+ } catch (e: Exception) {
+ Timber.e("Network Failure: ${e.message}")
_signOutSuccess.value = false
}
- })
+ }
}
- private val myPageService: MypageService = AuthNetworkModule.getClient().create(MypageService::class.java)
-
- private val _friendNum = MutableLiveData()
- val friendNum: LiveData get() = _friendNum
-
- private val _userId = MutableLiveData()
- val userId: LiveData get() = _userId
-
- private val _nickname = MutableLiveData()
- val nickname: LiveData get() = _nickname
-
- private val _status = MutableLiveData()
- val status: LiveData get() = _status
-
fun updateMypage() {
- val call = myPageService.getMypage()
-
- call.enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
+ viewModelScope.launch {
+ _uiState.value = _uiState.value?.copy(isLoading = true)
+ try {
+ val response = mypageService.getMypageSuspend()
if (response.isSuccessful) {
- val userId = response.body()?.result?.userId
- val nickname = response.body()?.result?.nickname
- val friendNumber = response.body()?.result?.friendNum
- val status = response.body()?.result?.status
-
- _userId.postValue(userId)
- _friendNum.postValue(friendNumber)
- _nickname.postValue(nickname)
- _status.postValue(status)
-
- Timber.tag("updateFriendNum").d("FriendNum updated: $friendNumber")
- Timber.tag("updateStatus").d("Status updated: $status")
+ response.body()?.result?.let { result ->
+ _uiState.value = MypageUiState(
+ userId = result.userId,
+ nickname = result.nickname,
+ status = result.status,
+ friendNum = result.friendNum,
+ isLoading = false
+ )
+ Timber.tag("updateMypage").d("Mypage updated: $result")
+ }
} else {
- Timber.tag("API Error").e("Failed to update FriendNum. Code: ${response.code()}, Message: ${response.message()}")
- Timber.tag("API Error").e("Response Body: ${response.errorBody()?.string()}")
+ Timber.tag("API Error").e("Failed to update Mypage. Code: ${response.code()}, Message: ${response.message()}")
+ _uiState.value = _uiState.value?.copy(isLoading = false)
tokenManager.refreshToken(
- onSuccess = { updateMypage() }, // 토큰 갱신 후 다시 요청
- onFailure = { Timber.e("Failed to refresh token and get notices") }
+ onSuccess = { updateMypage() },
+ onFailure = {
+ Timber.e("Failed to refresh token and get mypage")
+ _uiState.value = _uiState.value?.copy(isLoading = false)
+ }
)
}
+ } catch (e: Exception) {
+ Timber.tag("API Failure").e(e, "Error occurred during API call")
+ _uiState.value = _uiState.value?.copy(isLoading = false)
}
-
- override fun onFailure(call: Call, t: Throwable) {
- Timber.tag("API Failure").e(t, "Error occurred during API call")
- }
- })
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt
index bd1934ee..bc93ee03 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt
@@ -11,6 +11,7 @@ import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
@@ -23,14 +24,14 @@ import com.toyou.toyouandroid.domain.create.repository.CreateRepository
import com.toyou.toyouandroid.domain.home.repository.HomeRepository
import com.toyou.toyouandroid.network.AuthNetworkModule
import com.toyou.toyouandroid.network.NetworkModule
-import com.toyou.toyouandroid.presentation.viewmodel.AuthViewModelFactory
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
+import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
+@AndroidEntryPoint
class ProfileFragment : Fragment() {
private lateinit var navController: NavController
@@ -38,18 +39,11 @@ class ProfileFragment : Fragment() {
private val binding: FragmentProfileBinding
get() = requireNotNull(_binding){"FragmentProfileBinding -> null"}
- private lateinit var viewModel: ProfileViewModel
+ private val viewModel: ProfileViewModel by viewModels()
private lateinit var userViewModel: UserViewModel
- private val mypageViewModel: MypageViewModel by activityViewModels {
- val tokenStorage = TokenStorage(requireContext())
- val authService: AuthService = NetworkModule.getClient().create(AuthService::class.java)
- val tokenManager = TokenManager(authService, tokenStorage)
-
- val authService2: AuthService = AuthNetworkModule.getClient().create(AuthService::class.java)
- AuthViewModelFactory(authService2, tokenStorage, tokenManager)
- }
+ private val mypageViewModel: MypageViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
@@ -64,15 +58,8 @@ class ProfileFragment : Fragment() {
val tokenManager = TokenManager(authService, tokenStorage)
val createService = AuthNetworkModule.getClient().create(CreateService::class.java)
val createRepository = CreateRepository(createService)
- val homeRepository = HomeRepository()
-
- viewModel = ViewModelProvider(
- this,
- HomeViewModelFactory(
- tokenManager, homeRepository
- )
- )[ProfileViewModel::class.java]
+ // ProfileViewModel은 Hilt로 주입됨
userViewModel = ViewModelProvider(
requireActivity(),
@@ -95,46 +82,46 @@ class ProfileFragment : Fragment() {
// navController 초기화
navController = findNavController()
- // 닉네임 변경시 기존 닉네임 불러오기
- mypageViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
- binding.signupNicknameInput.setText(nickname)
- }
-
- // 상태에 따른 배경 변경
- mypageViewModel.status.observe(viewLifecycleOwner) { status ->
- Timber.d("Status changed: $status") // 상태 변경 시 로그 출력
-
- when (status) {
- "SCHOOL" -> {
- Timber.d("Setting background for SCHOOL status") // SCHOOL 상태에 맞는 배경 설정 전 로그
- binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
- binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_input)
- }
- "COLLEGE" -> {
- Timber.d("Setting background for COLLEGE status") // COLLEGE 상태에 맞는 배경 설정 전 로그
- binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
- binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_input)
- }
- "OFFICE" -> {
- Timber.d("Setting background for OFFICE status") // OFFICE 상태에 맞는 배경 설정 전 로그
- binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
- binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_input)
- }
- "ETC" -> {
- Timber.d("Setting background for ETC status") // ETC 상태에 맞는 배경 설정 전 로그
- binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_input)
- binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
- }
- }
- }
+// // 닉네임 변경시 기존 닉네임 불러오기
+// mypageViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
+// binding.signupNicknameInput.setText(nickname)
+// }
+//
+// // 상태에 따른 배경 변경
+// mypageViewModel.status.observe(viewLifecycleOwner) { status ->
+// Timber.d("Status changed: $status") // 상태 변경 시 로그 출력
+//
+// when (status) {
+// "SCHOOL" -> {
+// Timber.d("Setting background for SCHOOL status") // SCHOOL 상태에 맞는 배경 설정 전 로그
+// binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
+// binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_input)
+// }
+// "COLLEGE" -> {
+// Timber.d("Setting background for COLLEGE status") // COLLEGE 상태에 맞는 배경 설정 전 로그
+// binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
+// binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_input)
+// }
+// "OFFICE" -> {
+// Timber.d("Setting background for OFFICE status") // OFFICE 상태에 맞는 배경 설정 전 로그
+// binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
+// binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_input)
+// }
+// "ETC" -> {
+// Timber.d("Setting background for ETC status") // ETC 상태에 맞는 배경 설정 전 로그
+// binding.signupStatusOption1.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption2.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption3.setBackgroundResource(R.drawable.signupnickname_input)
+// binding.signupStatusOption4.setBackgroundResource(R.drawable.signupnickname_doublecheck_activate)
+// }
+// }
+// }
// 이전 버튼
binding.signupNicknameBackLayout.setOnClickListener {
@@ -167,75 +154,75 @@ class ProfileFragment : Fragment() {
Toast.makeText(requireContext(), "프로필 수정이 완료되었습니다", Toast.LENGTH_SHORT).show()
}
- // 닉네임 중복 확인
- binding.signupAgreeNicknameDoublecheckBtn.setOnClickListener {
- mypageViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
- mypageViewModel.userId.observe(viewLifecycleOwner) { userId ->
- if (nickname != null && userId != null) {
- viewModel.checkDuplicate(nickname, userId)
- }
- }
- }
- hideKeyboard()
- }
-
- val buttonList = listOf(
- binding.signupStatusOption1,
- binding.signupStatusOption2,
- binding.signupStatusOption3,
- binding.signupStatusOption4
- )
-
- buttonList.forEach { button ->
- button.setOnClickListener {
- viewModel.onButtonClicked(button.id)
- updateButtonBackgrounds()
- }
- }
-
- viewModel.selectedStatusButtonId.observe(viewLifecycleOwner) { id ->
- id?.let {
- updateButtonBackgrounds()
- }
- }
+// // 닉네임 중복 확인
+// binding.signupAgreeNicknameDoublecheckBtn.setOnClickListener {
+// mypageViewModel.nickname.observe(viewLifecycleOwner) { nickname ->
+// mypageViewModel.userId.observe(viewLifecycleOwner) { userId ->
+// if (nickname != null && userId != null) {
+// viewModel.checkDuplicate(nickname, userId)
+// }
+// }
+// }
+// hideKeyboard()
+// }
+//
+// val buttonList = listOf(
+// binding.signupStatusOption1,
+// binding.signupStatusOption2,
+// binding.signupStatusOption3,
+// binding.signupStatusOption4
+// )
+//
+// buttonList.forEach { button ->
+// button.setOnClickListener {
+// viewModel.onButtonClicked(button.id)
+// updateButtonBackgrounds()
+// }
+// }
+
+// viewModel.selectedStatusButtonId.observe(viewLifecycleOwner) { id ->
+// id?.let {
+// updateButtonBackgrounds()
+// }
+// }
// 완료 버튼 활성화
viewModel.isNextButtonEnabled.observe(viewLifecycleOwner) { isEnabled ->
binding.signupNicknameBtn.isEnabled = isEnabled
}
- binding.root.setOnTouchListener { v, event ->
- if (event.action == MotionEvent.ACTION_DOWN) {
- hideKeyboard()
- v.performClick()
- }
- false
- }
- binding.root.setOnClickListener {
- hideKeyboard()
- }
+// binding.root.setOnTouchListener { v, event ->
+// if (event.action == MotionEvent.ACTION_DOWN) {
+// hideKeyboard()
+// v.performClick()
+// }
+// false
+// }
+// binding.root.setOnClickListener {
+// hideKeyboard()
+// }
}
- private fun updateButtonBackgrounds() {
- val buttonList = listOf(
- binding.signupStatusOption1,
- binding.signupStatusOption2,
- binding.signupStatusOption3,
- binding.signupStatusOption4
- )
- buttonList.forEach { button ->
- button.setBackgroundResource(viewModel.getButtonBackground(button.id))
- }
- }
-
- private fun hideKeyboard() {
- val imm = requireActivity().getSystemService(InputMethodManager::class.java)
- imm.hideSoftInputFromWindow(view?.windowToken, 0)
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- viewModel.setSelectedStatusButtonId(null)
- _binding = null
- }
+// private fun updateButtonBackgrounds() {
+// val buttonList = listOf(
+// binding.signupStatusOption1,
+// binding.signupStatusOption2,
+// binding.signupStatusOption3,
+// binding.signupStatusOption4
+// )
+// buttonList.forEach { button ->
+// button.setBackgroundResource(viewModel.getButtonBackground(button.id))
+// }
+// }
+//
+// private fun hideKeyboard() {
+// val imm = requireActivity().getSystemService(InputMethodManager::class.java)
+// imm.hideSoftInputFromWindow(view?.windowToken, 0)
+// }
+//
+// override fun onDestroyView() {
+// super.onDestroyView()
+// viewModel.setSelectedStatusButtonId(null)
+// _binding = null
+// }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileUiState.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileUiState.kt
new file mode 100644
index 00000000..8cde6d90
--- /dev/null
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileUiState.kt
@@ -0,0 +1,20 @@
+package com.toyou.toyouandroid.presentation.fragment.mypage
+
+data class ProfileUiState(
+ val title: String = "회원가입",
+ val textCount: String = "0/15",
+ val nickname: String = "",
+ val status: String = "",
+ val isDuplicateCheckEnabled: Boolean = false,
+ val isNextButtonEnabled: Boolean = false,
+ val duplicateCheckMessage: String = "중복된 닉네임인지 확인해주세요",
+ val isNicknameValid: Boolean = false,
+ val selectedStatusType: StatusType? = null
+)
+
+enum class StatusType(val value: String) {
+ SCHOOL("SCHOOL"),
+ COLLEGE("COLLEGE"),
+ OFFICE("OFFICE"),
+ ETC("ETC")
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileViewModel.kt
index 75695a3e..fa9a5ac3 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileViewModel.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileViewModel.kt
@@ -3,274 +3,222 @@ package com.toyou.toyouandroid.presentation.fragment.mypage
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import com.toyou.toyouandroid.R
-import com.toyou.toyouandroid.network.AuthNetworkModule
-import com.toyou.toyouandroid.data.onboarding.dto.NicknameCheckResponse
-import com.toyou.toyouandroid.data.onboarding.service.OnboardingService
-import com.toyou.toyouandroid.data.onboarding.dto.PatchNicknameRequest
-import com.toyou.toyouandroid.data.onboarding.dto.PatchNicknameResponse
-import com.toyou.toyouandroid.data.onboarding.dto.PatchStatusRequest
+import androidx.lifecycle.viewModelScope
+import com.toyou.toyouandroid.domain.profile.repository.ProfileRepository
import com.toyou.toyouandroid.utils.TokenManager
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
import timber.log.Timber
-
-class ProfileViewModel(private val tokenManager: TokenManager) : ViewModel() {
- private val _title = MutableLiveData()
- val title: LiveData get() = _title
-
- private val _textCount = MutableLiveData("0/15")
- val textCount: LiveData get() = _textCount
-
- fun updateTextCount(count: Int) {
- _textCount.value = "($count/15)"
- }
-
- private val inputText = MutableLiveData()
-
- private val _isDuplicateCheckEnabled = MutableLiveData(false)
- val isDuplicateCheckEnabled: LiveData = _isDuplicateCheckEnabled
-
- private val _duplicateCheckMessage = MutableLiveData().apply {
- value = "중복된 닉네임인지 확인해주세요"
- }
- val duplicateCheckMessage: LiveData = _duplicateCheckMessage
-
- private val _duplicateCheckMessageColor = MutableLiveData().apply {
- value = 0xFF000000.toInt()
- }
- val duplicateCheckMessageColor: LiveData = _duplicateCheckMessageColor
-
- private val _duplicateCheckButtonTextColor = MutableLiveData().apply {
- value = 0xFFA6A6A6.toInt()
- }
- val duplicateCheckButtonTextColor: LiveData = _duplicateCheckButtonTextColor
-
- private val _duplicateCheckButtonBackground = MutableLiveData().apply {
- value = R.drawable.next_button
- }
- val duplicateCheckButtonBackground: LiveData = _duplicateCheckButtonBackground
-
-
- private val _isNextButtonEnabled = MutableLiveData(false)
- val isNextButtonEnabled: LiveData = _isNextButtonEnabled
-
- private val _nextButtonTextColor = MutableLiveData().apply {
- value = 0xFFA6A6A6.toInt()
+import javax.inject.Inject
+
+@HiltViewModel
+class ProfileViewModel @Inject constructor(
+ private val profileRepository: ProfileRepository,
+ private val tokenManager: TokenManager
+) : ViewModel() {
+
+ private val _uiState = MutableLiveData(ProfileUiState())
+ val uiState: LiveData get() = _uiState
+
+ // 데이터 바인딩 호환성을 위한 프로퍼티
+ val textCount: LiveData = MutableLiveData("0/15")
+ val nickname: LiveData = MutableLiveData()
+ val duplicateCheckButtonTextColor: LiveData = MutableLiveData(0xFFA6A6A6.toInt())
+ val duplicateCheckButtonBackground: LiveData = MutableLiveData(com.toyou.toyouandroid.R.drawable.next_button)
+ val duplicateCheckMessage: LiveData = MutableLiveData("중복된 닉네임인지 확인해주세요")
+ val duplicateCheckMessageColor: LiveData = MutableLiveData(0xFF000000.toInt())
+ val nextButtonBackground: LiveData = MutableLiveData(com.toyou.toyouandroid.R.drawable.next_button)
+ val nextButtonTextColor: LiveData = MutableLiveData(0xFFA6A6A6.toInt())
+ val isNextButtonEnabled: LiveData = MutableLiveData(false)
+
+ private val _nicknameChangedSuccess = MutableLiveData()
+ val nicknameChangedSuccess: LiveData get() = _nicknameChangedSuccess
+
+ private val _duplicateCheckMessageType = MutableLiveData()
+ val duplicateCheckMessageType: LiveData get() = _duplicateCheckMessageType
+
+ init {
+ _uiState.value = ProfileUiState(title = "회원가입")
}
- val nextButtonTextColor: LiveData = _nextButtonTextColor
-
- private val _nextButtonBackground = MutableLiveData().apply {
- value = R.drawable.next_button
+
+ fun updateTextCount(count: Int) {
+ val countText = "($count/15)"
+ _uiState.value = _uiState.value?.copy(
+ textCount = countText
+ )
+ (textCount as MutableLiveData).value = countText
}
- val nextButtonBackground: LiveData = _nextButtonBackground
-
- private val _nickname = MutableLiveData()
- val nickname: LiveData get() = _nickname
-
- fun duplicateBtnActivate() {
- _duplicateCheckButtonTextColor.value = 0xFF000000.toInt()
- _duplicateCheckButtonBackground.value = R.drawable.signupnickname_doublecheck_activate
+
+ fun setNickname(newNickname: String) {
+ _uiState.value = _uiState.value?.copy(
+ nickname = newNickname,
+ isDuplicateCheckEnabled = newNickname.isNotEmpty()
+ )
+ (nickname as MutableLiveData).value = newNickname
}
-
+
fun updateLength15(length: Int) {
- if (length >= 15) {
- _duplicateCheckMessage.value = "15자 이내로 입력해주세요."
- _duplicateCheckMessageColor.value = 0xFF000000.toInt()
+ val messageType = if (length >= 15) {
+ DuplicateCheckMessageType.LENGTH_EXCEEDED
} else {
- _duplicateCheckMessage.value = "중복된 닉네임인지 확인해주세요"
- _duplicateCheckMessageColor.value = 0xFF000000.toInt()
+ DuplicateCheckMessageType.CHECK_REQUIRED
}
+ _duplicateCheckMessageType.value = messageType
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = messageType.message
+ )
}
-
- fun setNickname(newNickname: String) {
- _nickname.value = newNickname
+
+ fun duplicateBtnActivate() {
+ _uiState.value = _uiState.value?.copy(
+ isDuplicateCheckEnabled = true
+ )
+ (duplicateCheckButtonTextColor as MutableLiveData).value = 0xFF000000.toInt()
+ (duplicateCheckButtonBackground as MutableLiveData).value = com.toyou.toyouandroid.R.drawable.signupnickname_doublecheck_activate
}
-
+
fun resetNicknameEditState() {
- _duplicateCheckMessage.value = "중복된 닉네임인지 확인해주세요"
- _duplicateCheckMessageColor.value = 0xFF000000.toInt()
- _isNextButtonEnabled.value = false
- _nextButtonTextColor.value = 0xFFA6A6A6.toInt()
- _nextButtonBackground.value = R.drawable.next_button
- _duplicateCheckButtonTextColor.value = 0xFFA6A6A6.toInt()
- _duplicateCheckButtonBackground.value = R.drawable.next_button
- }
-
- fun nextButtonDisable() {
- _isNextButtonEnabled.value = false
- _nextButtonTextColor.value = 0xFFA6A6A6.toInt()
- _nextButtonBackground.value = R.drawable.next_button
- }
-
- private fun nextButtonEnableCheck() {
- if (_nicknameValidate.value == true) {
- _isNextButtonEnabled.value = true
- _nextButtonTextColor.value = 0xFF000000.toInt()
- _nextButtonBackground.value = R.drawable.next_button_enabled
- }
- }
-
- private val _nicknameValidate = MutableLiveData()
- private val nicknameValidate: LiveData get() = _nicknameValidate
-
- init {
- inputText.observeForever { text ->
- _isDuplicateCheckEnabled.value = !text.isNullOrEmpty()
- }
- _title.value = "회원가입"
- _nicknameValidate.value = true
- }
-
- private val apiService: OnboardingService = AuthNetworkModule.getClient().create(
- OnboardingService::class.java)
-
- // API를 호출하여 닉네임 중복 체크를 수행하는 함수
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.CHECK_REQUIRED.message,
+ isNextButtonEnabled = false,
+ isNicknameValid = false
+ )
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.CHECK_REQUIRED
+ }
+
fun checkDuplicate(userNickname: String, userId: Int) {
- val nickname = _nickname.value ?: return
-
- val call = apiService.getNicknameCheck(nickname, userId)
- call.enqueue(object : Callback {
- override fun onResponse(call: Call, response: Response) {
+ val nickname = _uiState.value?.nickname ?: return
+
+ viewModelScope.launch {
+ try {
+ val response = profileRepository.checkNickname(nickname, userId)
if (response.isSuccessful) {
val exists = response.body()?.result?.exists ?: false
- if (!exists) {
- _duplicateCheckMessage.value = "사용 가능한 닉네임입니다."
- _duplicateCheckMessageColor.value = 0xFFEA9797.toInt()
- _nicknameValidate.value = true
- nextButtonEnableCheck()
- } else {
- if (userNickname == nickname) {
- _duplicateCheckMessage.value = "이미 사용 중인 닉네임입니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- _nicknameValidate.value = false
- nextButtonEnableCheck()
- } else {
- _duplicateCheckMessage.value = "이미 사용 중인 닉네임입니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- _nicknameValidate.value = false
- nextButtonDisable()
- nextButtonEnableCheck()
- }
- }
+ handleNicknameCheckResult(exists, userNickname, nickname)
} else {
- _duplicateCheckMessage.value = "닉네임 확인에 실패했습니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- _nicknameValidate.value = false
- nextButtonDisable()
- nextButtonEnableCheck()
-
+ handleNicknameCheckError()
tokenManager.refreshToken(
- onSuccess = { checkDuplicate(userNickname, userId) }, // 토큰 갱신 후 다시 요청
- onFailure = { Timber.e("Failed to refresh token and get notices") }
+ onSuccess = { checkDuplicate(userNickname, userId) },
+ onFailure = { Timber.e("Failed to refresh token and check nickname") }
)
}
+ } catch (e: Exception) {
+ Timber.tag("API Failure").e(e, "Error checking nickname")
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.SERVER_ERROR
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.SERVER_ERROR.message,
+ isNicknameValid = false,
+ isNextButtonEnabled = false
+ )
}
-
- override fun onFailure(call: Call, t: Throwable) {
- Timber.tag("API Failure").e(t, "Error checking nickname")
- _duplicateCheckMessage.value = "서버에 연결할 수 없습니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- _nicknameValidate.value = false
- nextButtonDisable()
- nextButtonEnableCheck()
- }
- })
+ }
}
-
- private val _nicknameChangedSuccess = MutableLiveData()
- val nicknameChangedSuccess: LiveData get() = _nicknameChangedSuccess
-
+
+ private fun handleNicknameCheckResult(exists: Boolean, userNickname: String, nickname: String) {
+ val messageType = when {
+ !exists -> DuplicateCheckMessageType.AVAILABLE
+ userNickname == nickname -> DuplicateCheckMessageType.ALREADY_IN_USE_SAME
+ else -> DuplicateCheckMessageType.ALREADY_IN_USE
+ }
+
+ _duplicateCheckMessageType.value = messageType
+ val isValid = !exists || (userNickname == nickname)
+
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = messageType.message,
+ isNicknameValid = isValid,
+ isNextButtonEnabled = isValid
+ )
+
+ // 호환성 프로퍼티 업데이트
+ (duplicateCheckMessage as MutableLiveData).value = messageType.message
+ (duplicateCheckMessageColor as MutableLiveData).value = when {
+ !exists -> 0xFFEA9797.toInt()
+ else -> 0xFFFF0000.toInt()
+ }
+ (isNextButtonEnabled as MutableLiveData).value = isValid
+ if (isValid) {
+ (nextButtonTextColor as MutableLiveData).value = 0xFF000000.toInt()
+ (nextButtonBackground as MutableLiveData).value = com.toyou.toyouandroid.R.drawable.next_button_enabled
+ }
+ }
+
+ private fun handleNicknameCheckError() {
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.CHECK_FAILED
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.CHECK_FAILED.message,
+ isNicknameValid = false,
+ isNextButtonEnabled = false
+ )
+ }
+
fun changeNickname() {
- val nickname = _nickname.value ?: return
- val request = PatchNicknameRequest(nickname)
- val call = apiService.patchNickname(request)
- call.enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
+ val nickname = _uiState.value?.nickname ?: return
+
+ viewModelScope.launch {
+ try {
+ val response = profileRepository.updateNickname(nickname)
if (response.isSuccessful) {
- _duplicateCheckMessage.value = response.body()?.message.toString()
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
_nicknameChangedSuccess.postValue(true)
Timber.tag("changeNickname").d("$response")
} else {
- _duplicateCheckMessage.value = "닉네임 변경에 실패했습니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- Timber.tag("changeNickname").d("$response")
-
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.UPDATE_FAILED
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.UPDATE_FAILED.message
+ )
tokenManager.refreshToken(
- onSuccess = { changeNickname() }, // 토큰 갱신 후 다시 요청
- onFailure = { Timber.e("Failed to refresh token and get notices") }
+ onSuccess = { changeNickname() },
+ onFailure = { Timber.e("Failed to refresh token and update nickname") }
)
}
+ } catch (e: Exception) {
+ Timber.tag("API Failure").e(e, "Error updating nickname")
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.SERVER_ERROR
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.SERVER_ERROR.message
+ )
}
-
- override fun onFailure(call: Call, t: Throwable) {
- Timber.tag("API Failure").e(t, "Error updating nickname")
- _duplicateCheckMessage.value = "서버에 연결할 수 없습니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- }
- })
+ }
}
-
+
fun changeStatus() {
- val status = _status.value ?: return
- val request = PatchStatusRequest(status)
- val call = apiService.patchStatus(request)
- call.enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
+ val status = _uiState.value?.status ?: return
+
+ viewModelScope.launch {
+ try {
+ val response = profileRepository.updateStatus(status)
if (response.isSuccessful) {
Timber.tag("changeStatus").d("${response.body()}")
} else {
tokenManager.refreshToken(
- onSuccess = { changeStatus() }, // 토큰 갱신 후 다시 요청
- onFailure = { Timber.e("Failed to refresh token and get notices") }
+ onSuccess = { changeStatus() },
+ onFailure = { Timber.e("Failed to refresh token and update status") }
)
}
+ } catch (e: Exception) {
+ Timber.tag("API Failure").e(e, "Error updating status")
}
-
- override fun onFailure(call: Call, t: Throwable) {
- // 에러 처리 로직
- Timber.tag("API Failure").e(t, "Error updating nickname")
- }
- })
- }
-
- private val _selectedStatusButtonId = MutableLiveData(null)
- val selectedStatusButtonId: LiveData get() = _selectedStatusButtonId
-
- fun setSelectedStatusButtonId(id: Int?) {
- _selectedStatusButtonId.value = id
- }
-
- private val _status = MutableLiveData()
- val status: LiveData get() = _status
-
- fun onButtonClicked(buttonId: Int) {
- if (_selectedStatusButtonId.value == buttonId) return
- _selectedStatusButtonId.value = buttonId
-
- when (buttonId) {
- R.id.signup_status_option_1 -> _status.value = "SCHOOL"
- R.id.signup_status_option_2 -> _status.value = "COLLEGE"
- R.id.signup_status_option_3 -> _status.value = "OFFICE"
- R.id.signup_status_option_4 -> _status.value = "ETC"
- }
-
- nextButtonEnableCheck()
- }
-
- fun getButtonBackground(buttonId: Int): Int {
- return if (_selectedStatusButtonId.value == buttonId) {
- R.drawable.signupnickname_doublecheck_activate // 선택된 상태의 배경
- } else {
- R.drawable.signupnickname_input // 기본 상태의 배경
}
}
+
+ fun onStatusButtonClicked(statusType: StatusType) {
+ if (_uiState.value?.selectedStatusType == statusType) return
+
+ _uiState.value = _uiState.value?.copy(
+ selectedStatusType = statusType,
+ status = statusType.value,
+ isNextButtonEnabled = true
+ )
+ }
+}
+
+enum class DuplicateCheckMessageType(val message: String) {
+ CHECK_REQUIRED("중복된 닉네임인지 확인해주세요"),
+ LENGTH_EXCEEDED("15자 이내로 입력해주세요."),
+ AVAILABLE("사용 가능한 닉네임입니다."),
+ ALREADY_IN_USE("이미 사용 중인 닉네임입니다."),
+ ALREADY_IN_USE_SAME("이미 사용 중인 닉네임입니다."),
+ CHECK_FAILED("닉네임 확인에 실패했습니다."),
+ UPDATE_FAILED("닉네임 변경에 실패했습니다."),
+ SERVER_ERROR("서버에 연결할 수 없습니다.")
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt
index 87bc5c9b..26ebd44d 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt
@@ -146,7 +146,7 @@ class NoticeFragment : Fragment(), NoticeAdapterListener {
navController.navigate(R.id.action_navigation_notice_to_create_fragment)
}
else {
- cardViewModel.getCardDetail(cardId.toLong())
+// cardViewModel.getCardDetail(cardId.toLong())
navController.navigate(R.id.action_navigation_notice_to_modify_fragment)
}
}
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt
index fcb90b41..98f42b94 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt
@@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
@@ -20,11 +21,12 @@ import com.toyou.toyouandroid.domain.home.repository.HomeRepository
import com.toyou.toyouandroid.network.NetworkModule
import com.toyou.toyouandroid.presentation.base.MainActivity
import com.toyou.toyouandroid.presentation.fragment.home.HomeViewModel
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.ViewModelManager
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
+import dagger.hilt.android.AndroidEntryPoint
+@AndroidEntryPoint
class SignupNicknameFragment : Fragment() {
private lateinit var navController: NavController
@@ -32,10 +34,10 @@ class SignupNicknameFragment : Fragment() {
private val binding: FragmentSignupnicknameBinding
get() = requireNotNull(_binding){"FragmentSignupnicknameBinding -> null"}
- private val viewModel: SignupNicknameViewModel by activityViewModels()
- private val nicknameViewModel: SignupNicknameViewModel by activityViewModels()
+ private val viewModel: SignupNicknameViewModel by viewModels()
+ private val nicknameViewModel: SignupNicknameViewModel by viewModels()
- private lateinit var homeViewModel: HomeViewModel
+ private val homeViewModel: HomeViewModel by viewModels()
private lateinit var viewModelManager: ViewModelManager
override fun onCreateView(
@@ -45,15 +47,8 @@ class SignupNicknameFragment : Fragment() {
): View {
_binding = FragmentSignupnicknameBinding.inflate(inflater, container, false)
- val tokenStorage = TokenStorage(requireContext())
- val authService: AuthService = NetworkModule.getClient().create(AuthService::class.java)
- val tokenManager = TokenManager(authService, tokenStorage)
- val homeRepository = HomeRepository()
-
- homeViewModel = ViewModelProvider(
- this,
- HomeViewModelFactory(tokenManager, homeRepository)
- )[HomeViewModel::class.java]
+ // SignupNicknameViewModel은 Hilt로 주입됨
+ // 다른 ViewModel들은 기존 방식 유지할 필요가 있다면 여기에 초기화 코드 추가
binding.viewModel = viewModel
binding.lifecycleOwner = this
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt
index f827b08d..9ebd9bde 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt
@@ -3,153 +3,136 @@ package com.toyou.toyouandroid.presentation.fragment.onboarding
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import com.toyou.toyouandroid.R
-import com.toyou.toyouandroid.network.NetworkModule
-import com.toyou.toyouandroid.data.onboarding.dto.NicknameCheckResponse
-import com.toyou.toyouandroid.data.onboarding.service.OnboardingService
-import retrofit2.Call
-import retrofit2.Callback
-import retrofit2.Response
+import androidx.lifecycle.viewModelScope
+import com.toyou.toyouandroid.domain.profile.repository.ProfileRepository
+import com.toyou.toyouandroid.presentation.fragment.mypage.DuplicateCheckMessageType
+import com.toyou.toyouandroid.presentation.fragment.mypage.ProfileUiState
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
import timber.log.Timber
-
-class SignupNicknameViewModel : ViewModel() {
-
- private val _title = MutableLiveData()
- val title: LiveData get() = _title
-
- private val _backButtonAction = MutableLiveData<() -> Unit>()
- val backButtonAction: LiveData<() -> Unit> get() = _backButtonAction
-
- private val _textCount = MutableLiveData("0/15")
- val textCount: LiveData get() = _textCount
-
- fun updateTextCount(count: Int) {
- _textCount.value = "($count/15)"
- }
-
- private val inputText = MutableLiveData()
-
- private val _isDuplicateCheckEnabled = MutableLiveData(false)
- val isDuplicateCheckEnabled: LiveData = _isDuplicateCheckEnabled
-
- private val _duplicateCheckMessage = MutableLiveData().apply {
- value = "중복된 닉네임인지 확인해주세요"
- }
- val duplicateCheckMessage: LiveData = _duplicateCheckMessage
-
- private val _duplicateCheckMessageColor = MutableLiveData().apply {
- value = 0xFF000000.toInt()
- }
- val duplicateCheckMessageColor: LiveData = _duplicateCheckMessageColor
-
- private val _duplicateCheckButtonTextColor = MutableLiveData().apply {
- value = 0xFFA6A6A6.toInt()
- }
- val duplicateCheckButtonTextColor: LiveData = _duplicateCheckButtonTextColor
-
- private val _duplicateCheckButtonBackground = MutableLiveData().apply {
- value = R.drawable.next_button
- }
- val duplicateCheckButtonBackground: LiveData = _duplicateCheckButtonBackground
-
-
- private val _isNextButtonEnabled = MutableLiveData(false)
- val isNextButtonEnabled: LiveData = _isNextButtonEnabled
-
- private val _nextButtonTextColor = MutableLiveData().apply {
- value = 0xFFA6A6A6.toInt()
- }
- val nextButtonTextColor: LiveData = _nextButtonTextColor
-
- private val _nextButtonBackground = MutableLiveData().apply {
- value = R.drawable.next_button
- }
- val nextButtonBackground: LiveData = _nextButtonBackground
-
- private val _nickname = MutableLiveData()
- val nickname: LiveData get() = _nickname
-
+import javax.inject.Inject
+
+@HiltViewModel
+class SignupNicknameViewModel @Inject constructor(
+ private val profileRepository: ProfileRepository
+) : ViewModel() {
+
+ private val _uiState = MutableLiveData(ProfileUiState())
+ val uiState: LiveData get() = _uiState
+
+ // 데이터 바인딩 호환성을 위한 프로퍼티
+ val nickname: LiveData = MutableLiveData()
+ val textCount: LiveData = MutableLiveData("0/15")
+ val duplicateCheckButtonTextColor: LiveData = MutableLiveData(0xFFA6A6A6.toInt())
+ val duplicateCheckButtonBackground: LiveData = MutableLiveData(com.toyou.toyouandroid.R.drawable.next_button)
+ val duplicateCheckMessage: LiveData = MutableLiveData("중복된 닉네임인지 확인해주세요")
+ val duplicateCheckMessageColor: LiveData = MutableLiveData(0xFF000000.toInt())
+ val nextButtonBackground: LiveData = MutableLiveData(com.toyou.toyouandroid.R.drawable.next_button)
+ val nextButtonTextColor: LiveData = MutableLiveData(0xFFA6A6A6.toInt())
+ val isNextButtonEnabled: LiveData = MutableLiveData(false)
+
+ private val _duplicateCheckMessageType = MutableLiveData()
+ val duplicateCheckMessageType: LiveData get() = _duplicateCheckMessageType
+
init {
- inputText.observeForever { text ->
- _isDuplicateCheckEnabled.value = !text.isNullOrEmpty()
- }
- _title.value = "회원가입"
-// _backButtonAction.value = { /* 회원가입 화면에서의 back 버튼 로직 */ }
+ _uiState.value = ProfileUiState(title = "회원가입")
}
-
- fun duplicateBtnActivate() {
- _duplicateCheckButtonTextColor.value = 0xFF000000.toInt()
- _duplicateCheckButtonBackground.value = R.drawable.signupnickname_doublecheck_activate
+
+ fun updateTextCount(count: Int) {
+ val countText = "($count/15)"
+ _uiState.value = _uiState.value?.copy(
+ textCount = countText
+ )
+ (textCount as MutableLiveData).value = countText
}
-
+
+ fun setNickname(newNickname: String) {
+ _uiState.value = _uiState.value?.copy(
+ nickname = newNickname,
+ isDuplicateCheckEnabled = newNickname.isNotEmpty()
+ )
+ (nickname as MutableLiveData).value = newNickname
+ }
+
fun updateLength15(length: Int) {
- if (length >= 15) {
- _duplicateCheckMessage.value = "15자 이내로 입력해주세요."
- _duplicateCheckMessageColor.value = 0xFF000000.toInt()
+ val messageType = if (length >= 15) {
+ DuplicateCheckMessageType.LENGTH_EXCEEDED
} else {
- _duplicateCheckMessage.value = "중복된 닉네임인지 확인해주세요"
- _duplicateCheckMessageColor.value = 0xFF000000.toInt()
+ DuplicateCheckMessageType.CHECK_REQUIRED
}
+ _duplicateCheckMessageType.value = messageType
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = messageType.message
+ )
}
-
- fun setNickname(newNickname: String) {
- _nickname.value = newNickname
+
+ fun duplicateBtnActivate() {
+ _uiState.value = _uiState.value?.copy(
+ isDuplicateCheckEnabled = true
+ )
+ (duplicateCheckButtonTextColor as MutableLiveData).value = 0xFF000000.toInt()
+ (duplicateCheckButtonBackground as MutableLiveData).value = com.toyou.toyouandroid.R.drawable.signupnickname_doublecheck_activate
}
-
+
fun resetState() {
- _duplicateCheckMessage.value = "중복된 닉네임인지 확인해주세요"
- _duplicateCheckMessageColor.value = 0xFF000000.toInt()
- _isNextButtonEnabled.value = false
- _nextButtonTextColor.value = 0xFFA6A6A6.toInt()
- _nextButtonBackground.value = R.drawable.next_button
- _nickname.value = ""
- _duplicateCheckButtonTextColor.value = 0xFFA6A6A6.toInt()
- _duplicateCheckButtonBackground.value = R.drawable.next_button
- }
-
- fun nextButtonDisable() {
- _isNextButtonEnabled.value = false
- _nextButtonTextColor.value = 0xFFA6A6A6.toInt()
- _nextButtonBackground.value = R.drawable.next_button
+ _uiState.value = ProfileUiState(title = "회원가입")
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.CHECK_REQUIRED
}
-
- private val retrofit = NetworkModule.getClient()
- private val apiService: OnboardingService = retrofit.create(OnboardingService::class.java)
-
- // API를 호출하여 닉네임 중복 체크를 수행하는 함수
+
fun checkDuplicate(userId: Int) {
- val nickname = _nickname.value ?: return
-
- val call = apiService.getNicknameCheck(nickname, userId)
- call.enqueue(object : Callback {
- override fun onResponse(call: Call, response: Response) {
+ val nickname = _uiState.value?.nickname ?: return
+
+ viewModelScope.launch {
+ try {
+ val response = profileRepository.checkNickname(nickname, userId)
if (response.isSuccessful) {
val exists = response.body()?.result?.exists ?: false
- if (!exists) {
- _duplicateCheckMessage.value = "사용 가능한 닉네임입니다."
- _duplicateCheckMessageColor.value = 0xFFEA9797.toInt()
-
- _isNextButtonEnabled.value = true
- _nextButtonTextColor.value = 0xFF000000.toInt()
- _nextButtonBackground.value = R.drawable.next_button_enabled
- } else {
- _duplicateCheckMessage.value = "이미 사용 중인 닉네임입니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- nextButtonDisable()
- }
+ handleNicknameCheckResult(exists)
} else {
- _duplicateCheckMessage.value = "닉네임 확인에 실패했습니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- nextButtonDisable()
+ handleNicknameCheckError()
}
+ } catch (e: Exception) {
+ Timber.tag("API Failure").e(e, "Error checking nickname")
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.SERVER_ERROR
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.SERVER_ERROR.message,
+ isNicknameValid = false,
+ isNextButtonEnabled = false
+ )
}
-
- override fun onFailure(call: Call, t: Throwable) {
- Timber.tag("API Failure").e(t, "Error checking nickname")
- _duplicateCheckMessage.value = "서버에 연결할 수 없습니다."
- _duplicateCheckMessageColor.value = 0xFFFF0000.toInt()
- nextButtonDisable()
- }
- })
+ }
+ }
+
+ private fun handleNicknameCheckResult(exists: Boolean) {
+ val messageType = if (!exists) {
+ DuplicateCheckMessageType.AVAILABLE
+ } else {
+ DuplicateCheckMessageType.ALREADY_IN_USE
+ }
+
+ _duplicateCheckMessageType.value = messageType
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = messageType.message,
+ isNicknameValid = !exists,
+ isNextButtonEnabled = !exists
+ )
+
+ // 호환성 프로퍼티 업데이트
+ (duplicateCheckMessage as MutableLiveData).value = messageType.message
+ (duplicateCheckMessageColor as MutableLiveData).value = if (!exists) 0xFFEA9797.toInt() else 0xFFFF0000.toInt()
+ (isNextButtonEnabled as MutableLiveData).value = !exists
+ if (!exists) {
+ (nextButtonTextColor as MutableLiveData).value = 0xFF000000.toInt()
+ (nextButtonBackground as MutableLiveData).value = com.toyou.toyouandroid.R.drawable.next_button_enabled
+ }
+ }
+
+ private fun handleNicknameCheckError() {
+ _duplicateCheckMessageType.value = DuplicateCheckMessageType.CHECK_FAILED
+ _uiState.value = _uiState.value?.copy(
+ duplicateCheckMessage = DuplicateCheckMessageType.CHECK_FAILED.message,
+ isNicknameValid = false,
+ isNextButtonEnabled = false
+ )
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupStatusFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupStatusFragment.kt
index 7fea17f9..8e8dec82 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupStatusFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupStatusFragment.kt
@@ -18,7 +18,7 @@ import com.toyou.toyouandroid.data.onboarding.service.AuthService
import com.toyou.toyouandroid.fcm.domain.FCMRepository
import com.toyou.toyouandroid.fcm.service.FCMService
import com.toyou.toyouandroid.network.AuthNetworkModule
-import com.toyou.toyouandroid.presentation.viewmodel.AuthViewModelFactory
+//import com.toyou.toyouandroid.presentation.viewmodel.AuthViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.LoginViewModelFactory
import com.toyou.toyouandroid.utils.TokenManager
import com.toyou.toyouandroid.utils.TokenStorage
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCardDetailFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCardDetailFragment.kt
index e327d4ac..bca6a8ec 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCardDetailFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCardDetailFragment.kt
@@ -18,7 +18,6 @@ import com.toyou.toyouandroid.domain.create.repository.CreateRepository
import com.toyou.toyouandroid.domain.record.RecordRepository
import com.toyou.toyouandroid.network.AuthNetworkModule
import com.toyou.toyouandroid.network.NetworkModule
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.RecordViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardContainerFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardContainerFragment.kt
index 4de3e6a8..47915663 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardContainerFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardContainerFragment.kt
@@ -24,7 +24,6 @@ import com.toyou.toyouandroid.network.NetworkModule
import com.toyou.toyouandroid.presentation.base.MainActivity
import com.toyou.toyouandroid.presentation.fragment.record.CalendarDialog
import com.toyou.toyouandroid.presentation.fragment.record.CalendarDialogViewModel
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.RecordViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardDetailFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardDetailFragment.kt
index f2f3fc45..e3652556 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardDetailFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyCardDetailFragment.kt
@@ -19,7 +19,6 @@ import com.toyou.toyouandroid.domain.create.repository.CreateRepository
import com.toyou.toyouandroid.domain.record.RecordRepository
import com.toyou.toyouandroid.network.AuthNetworkModule
import com.toyou.toyouandroid.network.NetworkModule
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.RecordViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModelFactory
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/social/SendFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/social/SendFragment.kt
index 6280ad15..1f2bca99 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/social/SendFragment.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/social/SendFragment.kt
@@ -20,7 +20,6 @@ import com.toyou.toyouandroid.fcm.domain.FCMRepository
import com.toyou.toyouandroid.fcm.service.FCMService
import com.toyou.toyouandroid.network.AuthNetworkModule
import com.toyou.toyouandroid.network.NetworkModule
-import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.SocialViewModel
import com.toyou.toyouandroid.presentation.viewmodel.SocialViewModelFactory
import com.toyou.toyouandroid.presentation.viewmodel.UserViewModel
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/AuthViewModelFactory.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/AuthViewModelFactory.kt
deleted file mode 100644
index 763363d2..00000000
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/AuthViewModelFactory.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.toyou.toyouandroid.presentation.viewmodel
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.toyou.toyouandroid.data.onboarding.service.AuthService
-import com.toyou.toyouandroid.presentation.fragment.mypage.MypageViewModel
-import com.toyou.toyouandroid.presentation.fragment.onboarding.LoginViewModel
-import com.toyou.toyouandroid.utils.TokenManager
-import com.toyou.toyouandroid.utils.TokenStorage
-
-class AuthViewModelFactory(
- private val authService: AuthService,
- private val tokenStorage: TokenStorage,
- private val tokenManager: TokenManager
-) : ViewModelProvider.Factory {
- override fun create(modelClass: Class): T {
- /*if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return LoginViewModel(authService, tokenStorage, tokenManager) as T
- } else */
- if (modelClass.isAssignableFrom(MypageViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return MypageViewModel(authService, tokenStorage, tokenManager) as T
- }
- throw IllegalArgumentException("Unknown ViewModel class")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/CardViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/CardViewModel.kt
index dd12ab5c..6acb9d9f 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/CardViewModel.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/CardViewModel.kt
@@ -30,7 +30,7 @@ class CardViewModel(private val tokenManager: TokenManager,
private val _previewChoose = MutableLiveData>()
val previewChoose : LiveData> get() = _previewChoose
//private val repository = CreateRepository(tokenManager)
- private val homeRepository = HomeRepository()
+// private val homeRepository = HomeRepository()
val exposure : LiveData get() = _exposure
private val _exposure = MutableLiveData()
@@ -163,76 +163,76 @@ class CardViewModel(private val tokenManager: TokenManager,
private val _receiver = MutableLiveData()
val receiver: LiveData get() = _receiver
- fun getCardDetail(id : Long) {
- viewModelScope.launch {
- try {
- val response = homeRepository.getCardDetail(id)
- if (response.isSuccess) {
- val detailCard = response.result
- val previewCardList = mutableListOf()
- _exposure.value = detailCard.exposure
- _date.value = detailCard.date
- _emotion.value = detailCard.emotion
- _receiver.value = detailCard.receiver
-
- detailCard.questions.let { questionList ->
- questionList.forEach { question ->
- val previewCard = when(question.type) {
- "OPTIONAL" -> {
- PreviewCardModel(
- question = question.content,
- fromWho = question.questioner,
- options = question.options,
- type = question.options!!.size,
- answer = question.answer,
- id = question.id
- )
- }
-
- "SHORT_ANSWER" -> {
- PreviewCardModel(
- question = question.content,
- fromWho = question.questioner,
- options = question.options,
- type = 0,
- answer = question.answer,
- id = question.id
- )
- }
-
- else -> {
- PreviewCardModel(
- question = question.content,
- fromWho = question.questioner,
- options = question.options,
- type = 1,
- answer = question.answer,
- id = question.id
- )
- }
- }
- previewCardList.add(previewCard)
- _previewCards.value = previewCardList
- }
- }
-
- } else {
- // 오류 처리
- Timber.tag("CardViewModel").d("detail API 호출 실패: ${response.message}")
- tokenManager.refreshToken(
- onSuccess = { getCardDetail(id) },
- onFailure = { Timber.tag("CardViewModel").d("refresh error")}
- )
- }
- } catch (e: Exception) {
- Timber.tag("CardViewModel").d("detail 예외 발생: ${e.message}")
- tokenManager.refreshToken(
- onSuccess = { getCardDetail(id) },
- onFailure = { Timber.tag("CardViewModel").d("refresh error")}
- )
- }
- }
- }
+// fun getCardDetail(id : Long) {
+// viewModelScope.launch {
+// try {
+// val response = homeRepository.getCardDetail(id)
+// if (response.isSuccess) {
+// val detailCard = response.result
+// val previewCardList = mutableListOf()
+// _exposure.value = detailCard.exposure
+// _date.value = detailCard.date
+// _emotion.value = detailCard.emotion
+// _receiver.value = detailCard.receiver
+//
+// detailCard.questions.let { questionList ->
+// questionList.forEach { question ->
+// val previewCard = when(question.type) {
+// "OPTIONAL" -> {
+// PreviewCardModel(
+// question = question.content,
+// fromWho = question.questioner,
+// options = question.options,
+// type = question.options!!.size,
+// answer = question.answer,
+// id = question.id
+// )
+// }
+//
+// "SHORT_ANSWER" -> {
+// PreviewCardModel(
+// question = question.content,
+// fromWho = question.questioner,
+// options = question.options,
+// type = 0,
+// answer = question.answer,
+// id = question.id
+// )
+// }
+//
+// else -> {
+// PreviewCardModel(
+// question = question.content,
+// fromWho = question.questioner,
+// options = question.options,
+// type = 1,
+// answer = question.answer,
+// id = question.id
+// )
+// }
+// }
+// previewCardList.add(previewCard)
+// _previewCards.value = previewCardList
+// }
+// }
+//
+// } else {
+// // 오류 처리
+// Timber.tag("CardViewModel").d("detail API 호출 실패: ${response.message}")
+// tokenManager.refreshToken(
+// onSuccess = { getCardDetail(id) },
+// onFailure = { Timber.tag("CardViewModel").d("refresh error")}
+// )
+// }
+// } catch (e: Exception) {
+// Timber.tag("CardViewModel").d("detail 예외 발생: ${e.message}")
+// tokenManager.refreshToken(
+// onSuccess = { getCardDetail(id) },
+// onFailure = { Timber.tag("CardViewModel").d("refresh error")}
+// )
+// }
+// }
+// }
private fun mapToPatchModels(questionsDto: QuestionsDto) {
val cardModels = mutableListOf()
diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/HomeViewModelFactory.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/HomeViewModelFactory.kt
index 514b1ce7..537fbb06 100644
--- a/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/HomeViewModelFactory.kt
+++ b/app/src/main/java/com/toyou/toyouandroid/presentation/viewmodel/HomeViewModelFactory.kt
@@ -8,30 +8,30 @@ import com.toyou.toyouandroid.presentation.fragment.home.HomeViewModel
import com.toyou.toyouandroid.presentation.fragment.mypage.ProfileViewModel
import com.toyou.toyouandroid.utils.TokenManager
-class HomeViewModelFactory(
- private val tokenManager: TokenManager,
- private val repository: HomeRepository
-) : ViewModelProvider.Factory {
- override fun create(modelClass: Class): T {
- if (modelClass.isAssignableFrom(HomeOptionViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return HomeOptionViewModel(tokenManager) as T
- } else if (modelClass.isAssignableFrom(HomeViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return HomeViewModel(tokenManager, repository) as T
- } else if (modelClass.isAssignableFrom(ProfileViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return ProfileViewModel(tokenManager) as T
- }
- /*else if (modelClass.isAssignableFrom(CardViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return CardViewModel(tokenManager) as T
- }
- else if (modelClass.isAssignableFrom(UserViewModel::class.java)) {
-
- @Suppress("UNCHECKED_CAST")
- return UserViewModel(tokenManager) as T
- }*/
- throw IllegalArgumentException("Unknown ViewModel class")
- }
-}
\ No newline at end of file
+//class HomeViewModelFactory(
+// private val tokenManager: TokenManager,
+// private val repository: HomeRepository
+//) : ViewModelProvider.Factory {
+// override fun create(modelClass: Class): T {
+// if (modelClass.isAssignableFrom(HomeOptionViewModel::class.java)) {
+// @Suppress("UNCHECKED_CAST")
+// return HomeOptionViewModel(tokenManager) as T
+// } else if (modelClass.isAssignableFrom(HomeViewModel::class.java)) {
+// @Suppress("UNCHECKED_CAST")
+// return HomeViewModel(tokenManager, repository) as T
+// } else if (modelClass.isAssignableFrom(ProfileViewModel::class.java)) {
+// @Suppress("UNCHECKED_CAST")
+// return ProfileViewModel(tokenManager) as T
+// }
+// /*else if (modelClass.isAssignableFrom(CardViewModel::class.java)) {
+// @Suppress("UNCHECKED_CAST")
+// return CardViewModel(tokenManager) as T
+// }
+// else if (modelClass.isAssignableFrom(UserViewModel::class.java)) {
+//
+// @Suppress("UNCHECKED_CAST")
+// return UserViewModel(tokenManager) as T
+// }*/
+// throw IllegalArgumentException("Unknown ViewModel class")
+// }
+//}
\ No newline at end of file