Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat/#36 submit to mypage] 제출 페이지를 마이페이지로 수정 #41

Merged
merged 3 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.zucchini.ssuplector.di

import android.content.Context
import android.content.Intent
import com.zucchini.auth.LoginActivity
import com.zucchini.common.NavigationProvider
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
Expand All @@ -23,6 +24,6 @@ class DefaultNavigationProvider @Inject constructor(
}

override fun toLogin(): Intent {
TODO("Not yet implemented")
return Intent(context, LoginActivity::class.java)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import com.sample.network.model.BaseResponse
import com.sample.network.reponse.LoginResponse
import com.sample.network.reponse.RefreshResponse
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

interface AuthService {
Expand All @@ -18,4 +20,14 @@ interface AuthService {
suspend fun refreshToken(
@Body refreshToken: String = "",
): BaseResponse<RefreshResponse>

@DELETE("api/auth/kakao/logout")
suspend fun logout(
@Header("Authorization") accessToken: String,
): BaseResponse<Unit>

@DELETE("api/auth/withdraw")
suspend fun withdrawal(
@Header("Authorization") accessToken: String,
): BaseResponse<Unit>
}
10 changes: 8 additions & 2 deletions data/src/main/java/com/zucchini/data/AuthRepositoryImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ class AuthRepositoryImpl @Inject constructor(
}

override suspend fun logout(accessToken: String): Result<Unit> {
TODO("Not yet implemented")
val bearerToken = "Bearer $accessToken"
return runCatching {
authService.logout(bearerToken)
}
}

override suspend fun withdrawal(accessToken: String): Result<Unit> {
TODO("Not yet implemented")
val bearerToken = "Bearer $accessToken"
return runCatching {
authService.withdrawal(bearerToken)
}
}
}
13 changes: 2 additions & 11 deletions feature/projects/src/main/java/com/zucchini/auth/LoginActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class LoginActivity @Inject constructor(
kakaoLogin()
collectKakaoLogin()
setLoginViewPager()
collectAutoLoginState()
}

private fun kakaoLogin() {
Expand All @@ -54,18 +53,10 @@ class LoginActivity @Inject constructor(
navigateToMain()
} else {
// TODO 회원가입
navigateToMain()
}
else -> Timber.d(getString(R.string.fail_kakao_login))
}
}.launchIn(lifecycleScope)
}

private fun collectAutoLoginState() {
viewModel.isAutoLoginState.flowWithLifecycle(lifecycle).onEach { isAutoLogin ->
if (!isAutoLogin) {
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
else -> Timber.e("Kakao Login Failed")
}
}.launchIn(lifecycleScope)
}
Expand Down
14 changes: 2 additions & 12 deletions feature/projects/src/main/java/com/zucchini/auth/LoginViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ class LoginViewModel @Inject constructor(
private val _isLogin = MutableStateFlow(false)
val isLogin = _isLogin.asStateFlow()

private val _isAutoLoginState = MutableStateFlow<Boolean>(false)
val isAutoLoginState = _isAutoLoginState.asStateFlow()

init {
updateAutoLoginState()
}

fun loginWithKakaoApp(context: Context) {
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
Expand All @@ -54,7 +48,7 @@ class LoginViewModel @Inject constructor(
}
Log.d(
"networkPreference",
"accessToken: ${networkPreference.accessToken} refreshToken: ${networkPreference.refreshToken} developerId: ${networkPreference.developerId} autoLoginConfigured: ${networkPreference.autoLoginConfigured}"
"accessToken: ${networkPreference.accessToken} refreshToken: ${networkPreference.refreshToken} developerId: ${networkPreference.developerId} autoLoginConfigured: ${networkPreference.autoLoginConfigured}",
)
_isLogin.value = it.isLogin
_kakaoLoginSuccess.value = true
Expand Down Expand Up @@ -97,8 +91,4 @@ class LoginViewModel @Inject constructor(
}
}
}

private fun updateAutoLoginState() {
_isAutoLoginState.value = networkPreference.autoLoginConfigured
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ class MainActivity : AppCompatActivity() {
val navController = navHostFragment.navController
binding.bnvMain.setupWithNavController(navController)
}

private fun loadMyLoginInfo() {

}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
package com.zucchini.projects

import androidx.lifecycle.ViewModel
import com.sample.network.datastore.NetworkPreference
import com.kakao.sdk.user.UserApiClient
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject

@HiltViewModel
class MainViewModel @Inject constructor(
private val netPreference: NetworkPreference,
) : ViewModel()
class MainViewModel @Inject constructor() : ViewModel() {

private val _userNickname = MutableStateFlow("")
val userNickname = _userNickname.asStateFlow()

private val _userEmail = MutableStateFlow("")
val userEmail = _userEmail.asStateFlow()

private val _userProfile = MutableStateFlow("")
val userProfile = _userProfile.asStateFlow()

init {
getKakaoUserInfo()
}

private fun getKakaoUserInfo() {
UserApiClient.instance.me { user, error ->
if (error != null) {
_userNickname.value = ""
_userEmail.value = ""
_userProfile.value = ""
} else if (user != null) {
_userNickname.value = user.kakaoAccount?.profile?.nickname ?: "no nickname"
_userEmail.value = user.kakaoAccount?.email ?: "no email"
_userProfile.value = user.kakaoAccount?.profile?.thumbnailImageUrl ?: ""
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,32 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import coil.load
import coil.transform.RoundedCornersTransformation
import com.zucchini.common.NavigationProvider
import com.zucchini.feature.projects.R
import com.zucchini.feature.projects.databinding.FragmentMypageBinding
import com.zucchini.projects.MainViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject

@AndroidEntryPoint
class MypageFragment : Fragment() {
private var _binding: FragmentMypageBinding? = null
private val binding: FragmentMypageBinding get() = _binding!!

private val mainViewModel by activityViewModels<MainViewModel>()
private val viewModel by viewModels<MypageViewModel>()

@Inject
lateinit var navigationProvider: NavigationProvider

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand All @@ -22,7 +42,12 @@ class MypageFragment : Fragment() {

navigateToWebDocs()
navigateToKakaoOpenChat()
navigateToSubmitForms()
navigateToMyDevInfo()
loadMyKakaoInfo()
collectLogoutState()
collectWithdrawalState()
clickLogout()
clickWithdrawal()

return binding.root
}
Expand All @@ -48,16 +73,68 @@ class MypageFragment : Fragment() {
}
}

private fun navigateToSubmitForms() {
binding.btnApplyDeveloper.setOnClickListener {
val developerFormUri = getString(R.string.developer_form)
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(developerFormUri))
startActivity(intent)
private fun navigateToMyDevInfo() {
binding.tvNavigateToMyInfo.setOnClickListener {
// TODO 개발자 상세정보로 이동
}
binding.btnApplyProject.setOnClickListener {
val projectFormUri = getString(R.string.project_form)
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(projectFormUri))
startActivity(intent)
}

private fun navigateToLoginActivity() {
val intent = navigationProvider.toLogin()
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
activity?.finish()
}

private fun loadMyKakaoInfo() {
mainViewModel.userEmail.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach { email ->
binding.tvUserEmail.text = email
}
.launchIn(viewLifecycleOwner.lifecycleScope)

mainViewModel.userNickname.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach { nickname ->
binding.tvUserName.text = nickname
}
.launchIn(viewLifecycleOwner.lifecycleScope)

mainViewModel.userProfile.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach { image ->
binding.ivDeveloperImage.load(image) {
crossfade(true)
placeholder(R.drawable.developer_default_image)
transformations(RoundedCornersTransformation())
}
}
.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun collectLogoutState() {
viewModel.logoutSuccess.flowWithLifecycle(lifecycle).onEach { success ->
if (success) {
navigateToLoginActivity()
}
}.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun collectWithdrawalState() {
viewModel.withdrawalSuccess.flowWithLifecycle(lifecycle).onEach { success ->
if (success) {
navigateToLoginActivity()
}
}.launchIn(viewLifecycleOwner.lifecycleScope)
}

private fun clickLogout() {
binding.tvLogout.setOnClickListener {
viewModel.logout()
}
}

private fun clickWithdrawal() {
binding.tvWithdrawal.setOnClickListener {
viewModel.withdrawal()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.zucchini.projects.mypage

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kakao.sdk.user.UserApiClient
import com.sample.network.datastore.NetworkPreference
import com.zucchini.domain.repository.AuthRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
class MypageViewModel @Inject constructor(
private val preference: NetworkPreference,
private val authRepository: AuthRepository,

) : ViewModel() {

private val _logoutSuccess = MutableStateFlow<Boolean>(false)
val logoutSuccess = _logoutSuccess.asStateFlow()

private val _withdrawalSuccess = MutableStateFlow<Boolean>(false)
val withdrawalSuccess = _withdrawalSuccess.asStateFlow()

fun logout() {
viewModelScope.launch {
authRepository.logout(preference.accessToken).onSuccess {
preference.clear()
_logoutSuccess.value = true
}.onFailure {
_logoutSuccess.value = false
Timber.d("failed to logout $it")
}
}
}

fun withdrawal() {
viewModelScope.launch {
authRepository.withdrawal(preference.accessToken).onSuccess {
preference.clear()
kakaoUnlink()
}.onFailure {
_withdrawalSuccess.value = false
Timber.d("failed to withdrawal")
}
}
}

private fun kakaoUnlink() {
UserApiClient.instance.unlink { error ->
if (error != null) {
_withdrawalSuccess.value = false
Timber.d("failed to unlink: $error")
} else {
_withdrawalSuccess.value = true
}
}
}
}
Loading
Loading