diff --git a/app/.idea/.gitignore b/app/.idea/.gitignore
new file mode 100644
index 00000000..26d33521
--- /dev/null
+++ b/app/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/app/.idea/gradle.xml b/app/.idea/gradle.xml
new file mode 100644
index 00000000..0364d75f
--- /dev/null
+++ b/app/.idea/gradle.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/misc.xml b/app/.idea/misc.xml
new file mode 100644
index 00000000..a318cae6
--- /dev/null
+++ b/app/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.idea/vcs.xml b/app/.idea/vcs.xml
new file mode 100644
index 00000000..6c0b8635
--- /dev/null
+++ b/app/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 3248bed4..843b6fd0 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -27,6 +27,8 @@ android {
buildConfigField("String", "BASE_URL", getBaseUrl("BASE_URL"))
buildConfigField("String", "NAVER_CLIENT_ID", getBaseUrl("NAVER_CLIENT_ID"))
buildConfigField("String", "NAVER_CLIENT_SECRET", getBaseUrl("NAVER_CLIENT_SECRET"))
+ buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"${getBaseUrl("KAKAO_NATIVE_APP_KEY")}\"")
+ manifestPlaceholders["kakaoKey"] = "kakao${getBaseUrl("KAKAO_NATIVE_APP_KEY")}"
}
buildTypes {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3a0df392..b2322d17 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,6 +32,20 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/example/numberoneproject/data/network/ApiService.kt b/app/src/main/java/com/example/numberoneproject/data/network/ApiService.kt
index cc1fd0d4..1382df0a 100644
--- a/app/src/main/java/com/example/numberoneproject/data/network/ApiService.kt
+++ b/app/src/main/java/com/example/numberoneproject/data/network/ApiService.kt
@@ -22,6 +22,12 @@ interface ApiService {
@Body body: TokenRequestBody
): ApiResult
+ //카카오 로그인
+ @POST("/token/kakao")
+ suspend fun userKakaoLogin(
+ @Body body: TokenRequestBody
+ ): ApiResult
+
// 로그인 테스트
@GET("/api/logintest")
suspend fun apiLoginTest(
diff --git a/app/src/main/java/com/example/numberoneproject/data/repositoryimpl/LoginRepositoryImpl.kt b/app/src/main/java/com/example/numberoneproject/data/repositoryimpl/LoginRepositoryImpl.kt
index fa24055c..610ec2c8 100644
--- a/app/src/main/java/com/example/numberoneproject/data/repositoryimpl/LoginRepositoryImpl.kt
+++ b/app/src/main/java/com/example/numberoneproject/data/repositoryimpl/LoginRepositoryImpl.kt
@@ -22,6 +22,10 @@ class LoginRepositoryImpl @Inject constructor(
return service.userNaverLogin(naverLoginBody)
}
+ override suspend fun userKakaoLogin(kakaoLoginBody: TokenRequestBody): ApiResult{
+ return service.userKakaoLogin(kakaoLoginBody)
+ }
+
override suspend fun testLogin(token: String): ApiResult {
return service.apiLoginTest(token)
}
diff --git a/app/src/main/java/com/example/numberoneproject/domain/repository/LoginRepository.kt b/app/src/main/java/com/example/numberoneproject/domain/repository/LoginRepository.kt
index e55be3bb..8aafcc60 100644
--- a/app/src/main/java/com/example/numberoneproject/domain/repository/LoginRepository.kt
+++ b/app/src/main/java/com/example/numberoneproject/domain/repository/LoginRepository.kt
@@ -8,5 +8,6 @@ import com.example.numberoneproject.data.network.ApiResult
interface LoginRepository {
suspend fun refreshAccessToken(body: TokenRequestBody): ApiResult
suspend fun userNaverLogin(naverLoginBody: TokenRequestBody): ApiResult
+ suspend fun userKakaoLogin(kakaoLoginBody: TokenRequestBody) : ApiResult
suspend fun testLogin(token: String) : ApiResult
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/numberoneproject/domain/usecase/KakaoLoginUsecase.kt b/app/src/main/java/com/example/numberoneproject/domain/usecase/KakaoLoginUsecase.kt
new file mode 100644
index 00000000..2a1c5984
--- /dev/null
+++ b/app/src/main/java/com/example/numberoneproject/domain/usecase/KakaoLoginUsecase.kt
@@ -0,0 +1,16 @@
+package com.example.numberoneproject.domain.usecase
+
+import com.example.numberoneproject.data.model.LoginTokenResponse
+import com.example.numberoneproject.data.model.TokenRequestBody
+import com.example.numberoneproject.data.network.ApiResult
+import com.example.numberoneproject.domain.repository.LoginRepository
+import javax.inject.Inject
+class KakaoLoginUsecase @Inject constructor(
+ private val loginRepository: LoginRepository
+) {
+ suspend operator fun invoke(
+ loginBody: TokenRequestBody
+ ) : ApiResult{
+ return loginRepository.userKakaoLogin(loginBody)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/numberoneproject/presentation/di/MyApplication.kt b/app/src/main/java/com/example/numberoneproject/presentation/di/MyApplication.kt
index d4ca38d8..1422b2a7 100644
--- a/app/src/main/java/com/example/numberoneproject/presentation/di/MyApplication.kt
+++ b/app/src/main/java/com/example/numberoneproject/presentation/di/MyApplication.kt
@@ -1,9 +1,15 @@
package com.example.numberoneproject.presentation.di
import android.app.Application
+import com.example.numberoneproject.BuildConfig
+import com.kakao.sdk.common.KakaoSdk
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MyApplication: Application() {
-
+ val KAKAO = BuildConfig.KAKAO_NATIVE_APP_KEY
+ override fun onCreate() {
+ super.onCreate()
+ KakaoSdk.init(this,KAKAO)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/numberoneproject/presentation/view/LoginActivity.kt b/app/src/main/java/com/example/numberoneproject/presentation/view/LoginActivity.kt
index a9ad3ada..6edf4a3c 100644
--- a/app/src/main/java/com/example/numberoneproject/presentation/view/LoginActivity.kt
+++ b/app/src/main/java/com/example/numberoneproject/presentation/view/LoginActivity.kt
@@ -4,7 +4,9 @@ import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
+import android.widget.Toast
import androidx.activity.viewModels
+import androidx.lifecycle.lifecycleScope
import com.example.numberoneproject.BuildConfig
import com.example.numberoneproject.R
import com.example.numberoneproject.data.model.TokenRequestBody
@@ -14,6 +16,10 @@ import com.example.numberoneproject.presentation.base.BaseActivity
import com.example.numberoneproject.presentation.util.Extensions.repeatOnStarted
import com.example.numberoneproject.presentation.util.TokenManager
import com.example.numberoneproject.presentation.viewmodel.LoginViewModel
+import com.kakao.sdk.auth.model.OAuthToken
+import com.kakao.sdk.common.model.ClientError
+import com.kakao.sdk.common.model.ClientErrorCause
+import com.kakao.sdk.user.UserApiClient
import com.navercorp.nid.NaverIdLoginSDK
import com.navercorp.nid.oauth.NidOAuthLogin
import com.navercorp.nid.oauth.OAuthLoginCallback
@@ -21,6 +27,8 @@ import com.navercorp.nid.profile.NidProfileCallback
import com.navercorp.nid.profile.data.NidProfileResponse
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
@AndroidEntryPoint
class LoginActivity : BaseActivity(R.layout.activity_login) {
@@ -106,4 +114,33 @@ class LoginActivity : BaseActivity(R.layout.activity_login
NaverIdLoginSDK.authenticate(this, oauthLoginCallback)
}
+
+ fun setupKakaoLogin(view:View){
+ //카카오 계정 로그인
+ val callback : (OAuthToken?, Throwable?) -> Unit = {token, error->
+ if(error != null){
+ Toast.makeText(this,"카카오계정 로그인 실패 ${error}",Toast.LENGTH_SHORT).show()
+ }
+ else if(token != null){
+ loginVM.userKakaoLogin(TokenRequestBody(token.accessToken))
+ }
+ }
+ //카카오톡 어플있다면 카카오톡 로그인 시도
+ if(UserApiClient.instance.isKakaoTalkLoginAvailable(this)){
+ UserApiClient.instance.loginWithKakaoTalk(this){token, error->
+ if(error != null){
+ Toast.makeText(this,"카카오톡 로그인 실패 ${error}",Toast.LENGTH_SHORT).show()
+ if(error is ClientError && error.reason == ClientErrorCause.Cancelled){
+ return@loginWithKakaoTalk
+ }
+ UserApiClient.instance.loginWithKakaoAccount(this, callback = callback)
+ }else if(token != null){
+ loginVM.userKakaoLogin(TokenRequestBody(token.accessToken))
+ }
+ }
+ }
+ else{
+ UserApiClient.instance.loginWithKakaoAccount(this, callback=callback)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/numberoneproject/presentation/view/SplashActivity.kt b/app/src/main/java/com/example/numberoneproject/presentation/view/SplashActivity.kt
index cadd8852..c1529f5f 100644
--- a/app/src/main/java/com/example/numberoneproject/presentation/view/SplashActivity.kt
+++ b/app/src/main/java/com/example/numberoneproject/presentation/view/SplashActivity.kt
@@ -10,20 +10,27 @@ import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
+import android.util.Log
import android.widget.Toast
+import androidx.lifecycle.lifecycleScope
import com.example.numberoneproject.R
+import com.example.numberoneproject.presentation.util.Extensions.repeatOnStarted
+import com.example.numberoneproject.presentation.util.TokenManager
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
class SplashActivity : AppCompatActivity() {
private val DURATION_TIME = 2000L // 스플래시 화면 지연시간
private lateinit var cm2 : ConnectivityManager
+ private val tokenManager: TokenManager = TokenManager(this)
private val networkCallBack = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
// 네트워크가 정상적인 경우
Toast.makeText(this@SplashActivity, "연결성공 $network", Toast.LENGTH_SHORT).show()
-
+ checkLogin()
Handler(Looper.getMainLooper()).postDelayed({
- startActivity(Intent( this@SplashActivity,LoginActivity::class.java))
+ //startActivity(Intent( this@SplashActivity,LoginActivity::class.java))
finish()
}, DURATION_TIME)
}
@@ -38,12 +45,29 @@ class SplashActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
+
val builder = NetworkRequest.Builder()
cm2 = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
cm2.registerNetworkCallback(builder.build(),networkCallBack)
}
+ //자동로그인 가능한지 확인
+ fun checkLogin(){
+ lifecycleScope.launch{
+ tokenManager.accessToken.collectLatest {
+ if(it.isNotEmpty()){
+ val intent = Intent(this@SplashActivity,MainActivity::class.java)
+ startActivity(intent)
+ }
+ else{
+ val intent = Intent(this@SplashActivity,LoginActivity::class.java)
+ startActivity(intent)
+ }
+ }
+ }
+ }
+
override fun onDestroy() {
super.onDestroy()
cm2 = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
diff --git a/app/src/main/java/com/example/numberoneproject/presentation/viewmodel/LoginViewModel.kt b/app/src/main/java/com/example/numberoneproject/presentation/viewmodel/LoginViewModel.kt
index 98822347..170c7037 100644
--- a/app/src/main/java/com/example/numberoneproject/presentation/viewmodel/LoginViewModel.kt
+++ b/app/src/main/java/com/example/numberoneproject/presentation/viewmodel/LoginViewModel.kt
@@ -7,6 +7,7 @@ import com.example.numberoneproject.data.model.TokenRequestBody
import com.example.numberoneproject.data.network.ApiResult
import com.example.numberoneproject.data.network.onFailure
import com.example.numberoneproject.data.network.onSuccess
+import com.example.numberoneproject.domain.usecase.KakaoLoginUsecase
import com.example.numberoneproject.domain.usecase.NaverLoginUseCase
import com.example.numberoneproject.domain.usecase.RefreshAccessTokenUseCase
import com.example.numberoneproject.domain.usecase.TestUseCase
@@ -22,6 +23,7 @@ import javax.inject.Inject
class LoginViewModel @Inject constructor(
private val tokenManager: TokenManager,
private val naverLoginUseCase: NaverLoginUseCase,
+ private val kakaoLoginUsecase: KakaoLoginUsecase,
private val testLoginUseCase: TestUseCase,
private val refreshAccessTokenUseCase: RefreshAccessTokenUseCase
) : ViewModel() {
@@ -41,6 +43,18 @@ class LoginViewModel @Inject constructor(
}
}
+ fun userKakaoLogin(loginBody: TokenRequestBody) {
+ viewModelScope.launch {
+ kakaoLoginUsecase(loginBody)
+ .onSuccess {
+ tokenManager.writeLoginTokens(it.accessToken, it.refreshToken)
+ }
+ .onFailure {
+ _loginErrorState.value = it
+ }
+ }
+ }
+
/** loginTest 관련 코드는 지금은 테스트 용도고 금방 지워질 코드 **/
fun loginTest() {
viewModelScope.launch {
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index f8cb6ab2..42143d6c 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -22,7 +22,8 @@
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#FFEB3B"
- android:text="카카오 로그인" />
+ android:text="카카오 로그인"
+ android:onClick="@{(v) -> activity.setupKakaoLogin(v)}"/>