Skip to content
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
32 changes: 26 additions & 6 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />

<application
Expand Down Expand Up @@ -36,7 +37,26 @@

<meta-data
android:name="com.kakao.vectormap.AppKey"
android:value="${KAKAO_NATIVE_KEY}"/>
android:value="${KAKAO_NATIVE_KEY}" />
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="${KAKAO_NATIVE_KEY}" />

<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="oauth"
android:scheme="kakao${KAKAO_NATIVE_KEY}" />
</intent-filter>
</activity>
</application>

</manifest>
3 changes: 2 additions & 1 deletion app/src/main/java/com/paw/key/PawKeyApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import coil.ImageLoaderFactory
import coil.disk.DiskCache
import coil.memory.MemoryCache
import coil.util.DebugLogger
import com.kakao.sdk.common.KakaoSdk
import com.kakao.vectormap.KakaoMapSdk
import com.naver.maps.map.NaverMapSdk
import dagger.hilt.android.HiltAndroidApp
Expand All @@ -22,10 +23,10 @@ class PawKeyApplication : Application(), ImageLoaderFactory {

override fun onCreate() {
super.onCreate()

setTimber()
setDarkMode()

KakaoSdk.init(this, kakaoNativeKey)
KakaoMapSdk.init(this, kakaoNativeKey)
NaverMapSdk.getInstance(this).client =
NaverMapSdk.NcpKeyClient(BuildConfig.NAVERMAP_CLIENT_ID)
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/paw/key/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ import com.paw.key.data.repositoryimpl.walklist.WalkListDetailRepositoryImpl
import com.paw.key.data.repositoryimpl.walkreview.WalkReviewRepositoryImpl
import com.paw.key.data.remote.datasource.datasourceimpl.AuthRemoteDataSourceImpl
import com.paw.key.data.remote.datasource.datasourceimpl.GoogleAuthDataSourceImpl
import com.paw.key.data.remote.datasource.datasourceimpl.KakaoAuthDataSourceImpl
import com.paw.key.data.remote.datasource.login.AuthRemoteDataSource
import com.paw.key.data.remote.datasource.login.GoogleAuthDataSource
import com.paw.key.data.remote.datasource.login.KakaoAuthDataSource
import com.paw.key.domain.repository.ArchivedListRepository
import com.paw.key.domain.repository.DummyRepository
import com.paw.key.domain.repository.LikeRepository
Expand Down Expand Up @@ -66,6 +68,11 @@ interface RepositoryModule {
impl: GoogleAuthDataSourceImpl,
): GoogleAuthDataSource

@Binds
abstract fun bindKakaoAuthDataSource(
impl: KakaoAuthDataSourceImpl
): KakaoAuthDataSource

@Binds
fun bindsDummyRepository(
dummyRepositoryImpl: DummyRepositoryImpl
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.paw.key.data.remote.datasource.datasourceimpl

import com.paw.key.data.dto.request.LoginRequestDto
import com.paw.key.data.dto.response.BaseResponse
import com.paw.key.data.dto.response.LoginResponseDto
import com.paw.key.data.remote.datasource.login.AuthRemoteDataSource
import com.paw.key.data.service.login.LoginService
import javax.inject.Inject

class AuthRemoteDataSourceImpl @Inject constructor(
private val loginService: LoginService
private val loginService: LoginService,
) : AuthRemoteDataSource {
override suspend fun login(idToken: String, deviceId: String): LoginResponseDto {
return loginService.login(
Expand All @@ -18,4 +17,13 @@ class AuthRemoteDataSourceImpl @Inject constructor(
)
)
}

override suspend fun loginKakao(idToken: String, deviceId: String): LoginResponseDto {
return loginService.loginKakao(
LoginRequestDto(
idToken = idToken,
deviceId = deviceId
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.paw.key.data.remote.datasource.datasourceimpl

import android.content.Context
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.paw.key.core.util.suspendRunCatching
import com.paw.key.data.remote.datasource.login.KakaoAuthDataSource
import kotlinx.coroutines.suspendCancellableCoroutine
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

class KakaoAuthDataSourceImpl @Inject constructor() : KakaoAuthDataSource {
override suspend fun signIn(context: Context): Result<String> = suspendRunCatching {
val accessToken = getKakaoAccessToken(context)
accessToken
}

private suspend fun getKakaoAccessToken(context: Context): String =
suspendCancellableCoroutine { continuation ->
val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
when {
error != null -> {
continuation.resumeWithException(error)
}
token != null -> {
continuation.resume(token.accessToken)
}
else -> {
continuation.resumeWithException(
IllegalStateException("Token and error are both null")
)
}
}
}

if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
continuation.resumeWithException(error)
return@loginWithKakaoTalk
}
when {
token != null -> callback(token, null)
error != null -> {
UserApiClient.instance.loginWithKakaoAccount(
context,
callback = callback
)
}
}
}
} else {
UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ import com.paw.key.data.dto.response.LoginResponseDto

interface AuthRemoteDataSource {
suspend fun login(idToken: String, deviceId: String): LoginResponseDto

suspend fun loginKakao(idToken: String, deviceId: String): LoginResponseDto
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.paw.key.data.remote.datasource.login

import android.content.Context

interface KakaoAuthDataSource {
suspend fun signIn(context: Context): Result<String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.paw.key.core.util.suspendRunCatching
import com.paw.key.data.dto.response.LoginResponseDto
import com.paw.key.data.remote.datasource.login.AuthRemoteDataSource
import com.paw.key.data.remote.datasource.login.GoogleAuthDataSource
import com.paw.key.data.remote.datasource.login.KakaoAuthDataSource
import com.paw.key.domain.repository.login.AuthRepository
import dagger.hilt.android.qualifiers.ApplicationContext
import timber.log.Timber
Expand All @@ -14,26 +15,32 @@ import javax.inject.Inject
class AuthRepositoryImpl @Inject constructor(
private val authRemoteDataSource: AuthRemoteDataSource,
private val googleAuthDataSource: GoogleAuthDataSource,
private val kakaoAuthDataSource: KakaoAuthDataSource,
@ApplicationContext private val context: Context
) : AuthRepository {

override suspend fun signInWithGoogle(context: Context): Result<String> =
googleAuthDataSource.signIn(context).map { it.idToken }

override suspend fun signInWithKakao(context: Context): Result<String> =
kakaoAuthDataSource.signIn(context)

override suspend fun login(idToken: String, deviceId: String): Result<LoginResponseDto> =
suspendRunCatching {

val loginResponse = authRemoteDataSource.login(idToken, deviceId)
saveTokens(loginResponse)
loginResponse
}

UserDataStore.saveAcessToken(
context = this.context,
token = loginResponse.accessToken
)
UserDataStore.saveRefreshToken(
context = this.context,
token = loginResponse.refreshToken
)

override suspend fun loginKakao(idToken: String, deviceId: String): Result<LoginResponseDto> =
suspendRunCatching {
val loginResponse = authRemoteDataSource.loginKakao(idToken, deviceId)
saveTokens(loginResponse)
loginResponse
}

private suspend fun saveTokens(loginResponse: LoginResponseDto) {
UserDataStore.saveAcessToken(context, loginResponse.accessToken)
UserDataStore.saveRefreshToken(context, loginResponse.refreshToken)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ interface LoginService {
suspend fun login(
@Body loginRequestDto: LoginRequestDto
): LoginResponseDto

@POST("auth/kakao/login")
suspend fun loginKakao(
@Body loginRequestDto: LoginRequestDto
): LoginResponseDto
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ import com.paw.key.data.dto.response.LoginResponseDto

interface AuthRepository {
suspend fun signInWithGoogle(context: Context): Result<String>
suspend fun signInWithKakao(context: Context): Result<String>
suspend fun login(idToken: String, deviceId: String): Result<LoginResponseDto>
suspend fun loginKakao(idToken: String, deviceId: String): Result<LoginResponseDto>
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -143,12 +144,18 @@ fun LoginScreen(
Image(
painter = painterResource(R.drawable.img_login_sub),
contentDescription = stringResource(R.string.ic_login_sub_image),
contentScale = ContentScale.Crop,
)

LoginSocialButton(
logo = R.drawable.ic_login_kakao,
loginText = stringResource(R.string.ic_login_kakao),
onClick = {},
onClick = {
viewModel.onKakaoSignIn(
context = context,
onSuccess = navigateHome
)
},
modifier = Modifier
.background(
shape = RoundedCornerShape(12.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,28 @@ class LoginViewModel @Inject constructor(
}
}

fun onKakaoSignIn(
context: Context,
onSuccess: () -> Unit,
) {
viewModelScope.launch {
authRepository.signInWithKakao(context)
.onSuccess { accessToken ->
val deviceId = getDeviceId(context)
authRepository.loginKakao(accessToken, deviceId)
.onSuccess { response ->
onSuccess()
}
.onFailure { e ->
Timber.e(e, "Full stack trace:")
}
}
.onFailure { e ->
Timber.e("[KAKAO_VM] Step 2: SDK login FAILED")
}
}
}

private fun getDeviceId(context: Context): String {
return android.provider.Settings.Secure.getString(
context.contentResolver,
Expand Down