Skip to content

Commit

Permalink
feat: 소셜 로그인 기능 구현 (#235)
Browse files Browse the repository at this point in the history
* design: LoginActivty에 필요한 drawable source 추가

* design: LoginActivty에 필요한 string source 추가

* feat: 소셜 로그인을 위한 gradle 추가

* feat: 난독화 시 카카오 SDK가 포함되지 않도록 규칙 설정

* feat: 카카오 로그인 API key 숨김 처리

* feat: 인터넷 사용 권한 허용

* feat: 카카오 로그인 기능을 위한 Redirect URI 설정 추가

* feat: Kakao SDK를 초기화하는 application 구현

* feat: Kakao 로그인 기능 Util 구현

* design: LoginActivity 뷰 구현

* feat: 게임 상태가 진행 중이 아닐 때 Splash 화면에서 로그인 화면으로 이동하도록 구현

* feat: 상태바 색상 변경

* feat: 로그인 기능 구현

* feat: 사용자의 카카오 계정 닉네임을 마이페이지에 보여주는 기능 구현

* feat: 서버와 통신해 토큰을 얻어올 때 필요한 Dto, Domain 객체 생성

* feat: Dto, Domain 변환 mapper 추가

* feat: 서버와 통신하여 로그인 인증을 해주는 retrofit service 구현

* feat: 로그인 인증을 통해 토큰을 가져와주는 레포지토리 구현

* feat: 서버에게 받은 토큰을 저장하는 SharedPreference 구현

* feat: 서버에게 토큰을 받아와 로컬 저장소에 저장하는 기능 구현

* feat: 카카오 API KEY 감추기에 따른 yml 파일 수정

* fix: yml 파일 오류 수정

* fix: yml 파일 오류 수정

* fix: yml 파일 오류 수정

* fix: yml 파일 오류 수정

* refactor: ktlint 적용

* refactor: yml 파일 코드 정리

* refactor: 암호화 처리 되는 EncryptedSharedPreferences로 변경

* feat: retrofit Header에 서버에서 받아온 토큰 넣어주기 구현

* refactor: 카카오 토큰을 함수 인자로 받아오도록 수정

* rename: preference가 사용된 파일명을 datasource로 변경

* refactor: 함수 인자명 변경
hyunji1203 authored Aug 9, 2023
1 parent 1e89906 commit 74dda58
Showing 31 changed files with 509 additions and 10 deletions.
18 changes: 15 additions & 3 deletions .github/workflows/android_ci.yml
Original file line number Diff line number Diff line change
@@ -38,8 +38,12 @@ jobs:
- name: Add Local Properties
env:
API_KEY: ${{ secrets.BASE_URL }}
KAKAO_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
KAKAO_SCHEME: ${{ secrets.KAKAO_REDIRECTION_SCHEME }}
run: |
echo BASE_URL=\"$API_KEY\" > ./local.properties
echo BASE_URL=\"$API_KEY\" >> ./local.properties
echo KAKAO_NATIVE_APP_KEY=\"KAKAO_APP_KEY\" >> ./local.properties
echo kakao_redirection_scheme=\"KAKAO_SCHEME\" >> ./local.properties
- name: Run ktlint
run: ./gradlew ktlintCheck
@@ -74,8 +78,12 @@ jobs:
- name: Add Local Properties
env:
API_KEY: ${{ secrets.BASE_URL }}
KAKAO_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
KAKAO_SCHEME: ${{ secrets.KAKAO_REDIRECTION_SCHEME }}
run: |
echo BASE_URL=\"$API_KEY\" > ./local.properties
echo BASE_URL=\"$API_KEY\" >> ./local.properties
echo KAKAO_NATIVE_APP_KEY=\"KAKAO_APP_KEY\" >> ./local.properties
echo kakao_redirection_scheme=\"KAKAO_SCHEME\" >> ./local.properties
- name: Add Google Service Json file
run: echo '${{ secrets.GOOGLE_SERVICES_JSON_FILE }}' > ./app/google-services.json
@@ -113,8 +121,12 @@ jobs:
- name: Add Local Properties
env:
API_KEY: ${{ secrets.BASE_URL }}
KAKAO_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
KAKAO_SCHEME: ${{ secrets.KAKAO_REDIRECTION_SCHEME }}
run: |
echo BASE_URL=\"$API_KEY\" > ./local.properties
echo BASE_URL=\"$API_KEY\" >> ./local.properties
echo KAKAO_NATIVE_APP_KEY=\"KAKAO_APP_KEY\" >> ./local.properties
echo kakao_redirection_scheme=\"KAKAO_SCHEME\" >> ./local.properties
- name: Add Google Service Json file
run: echo '${{ secrets.GOOGLE_SERVICES_JSON_FILE }}' > ./app/google-services.json
8 changes: 8 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ android {

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "BASE_URL", properties["BASE_URL"]
buildConfigField "String", "KAKAO_NATIVE_APP_KEY", properties["KAKAO_NATIVE_APP_KEY"]
resValue "string", "kakao_redirection_scheme", properties["kakao_redirection_scheme"]
}

buildTypes {
@@ -94,4 +96,10 @@ dependencies {
implementation(platform('com.google.firebase:firebase-bom:32.2.0'))
implementation "com.google.firebase:firebase-analytics-ktx"
implementation("com.google.firebase:firebase-crashlytics-ktx")

// kakao Login
implementation "com.kakao.sdk:v2-user:2.15.0"

// EncryptedSharedPreferences
implementation "androidx.security:security-crypto-ktx:1.1.0-alpha03"
}
5 changes: 4 additions & 1 deletion android/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -18,4 +18,7 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

-keep class com.kakao.sdk.**.model.* { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
19 changes: 19 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -9,8 +9,10 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".presentation.login.NaagaApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@@ -56,6 +58,23 @@
<activity
android:name=".presentation.mypage.MyPageActivity"
android:exported="false" />
<activity
android:name=".presentation.login.LoginActivity"
android:exported="false" />
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<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="@string/kakao_redirection_scheme" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.now.naaga.data.local

interface AuthDataSource {
fun getAccessToken(): String?
fun setAccessToken(newToken: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.now.naaga.data.local

import android.content.Context
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey

class KakaoAuthDataSource(context: Context) : AuthDataSource {
private val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()

private val pref =
EncryptedSharedPreferences.create(
context,
SECRET_SHARED_PREFS_FILE_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
)

override fun getAccessToken(): String {
return pref.getString(ACCESS_TOKEN_KEY, "") ?: ""
}

override fun setAccessToken(newToken: String) {
pref.edit().putString(ACCESS_TOKEN_KEY, newToken).apply()
}

companion object {
private const val SECRET_SHARED_PREFS_FILE_NAME = "secret_shared_prefs"
private const val ACCESS_TOKEN_KEY = "access_token_key"
}
}
23 changes: 23 additions & 0 deletions android/app/src/main/java/com/now/naaga/data/mapper/AuthMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.now.naaga.data.mapper

import com.now.domain.model.AuthPlatformType
import com.now.domain.model.NaagaAuth
import com.now.domain.model.PlatformAuth
import com.now.naaga.data.remote.dto.NaagaAuthDto
import com.now.naaga.data.remote.dto.PlatformAuthDto

fun PlatformAuthDto.toDomain(): PlatformAuth {
return PlatformAuth(token, AuthPlatformType.findByName(type))
}

fun PlatformAuth.toDto(): PlatformAuthDto {
return PlatformAuthDto(token, type.name)
}

fun NaagaAuthDto.toDomain(): NaagaAuth {
return NaagaAuth(accessToken, refreshToken)
}

fun NaagaAuth.toDto(): NaagaAuthDto {
return NaagaAuthDto(accessToken, refreshToken)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.now.naaga.data.remote.dto

import kotlinx.serialization.Serializable

@Serializable
data class NaagaAuthDto(
val accessToken: String,
val refreshToken: String?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.now.naaga.data.remote.dto

import kotlinx.serialization.Serializable

@Serializable
data class PlatformAuthDto(
val token: String,
val type: String,
)
Original file line number Diff line number Diff line change
@@ -2,14 +2,15 @@ package com.now.naaga.data.remote.retrofit

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.now.naaga.BuildConfig
import com.now.naaga.data.local.KakaoAuthDataSource
import com.now.naaga.presentation.login.NaagaApplication.Companion.getContext
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit

object RetrofitFactory {
private const val BASIC_USER_TOKEN = "Basic MTExQHdvb3dhLmNvbToxMTEx"
private const val BASE_URL = BuildConfig.BASE_URL

val retrofit: Retrofit = Retrofit.Builder()
@@ -19,9 +20,10 @@ object RetrofitFactory {
.build()

private fun createInterceptor(): Interceptor = Interceptor { chain ->
val token = KakaoAuthDataSource(getContext()).getAccessToken()
with(chain) {
val newRequest = request().newBuilder()
.addHeader("Authorization", BASIC_USER_TOKEN)
.addHeader("Authorization", token)
.addHeader("Content-Type", "application/json")
.build()
proceed(newRequest)
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package com.now.naaga.data.remote.retrofit

import com.now.naaga.data.remote.retrofit.RetrofitFactory.retrofit
import com.now.naaga.data.remote.retrofit.service.AdventureService
import com.now.naaga.data.remote.retrofit.service.AuthService
import com.now.naaga.data.remote.retrofit.service.PlaceService
import com.now.naaga.data.remote.retrofit.service.RankService
import com.now.naaga.data.remote.retrofit.service.StatisticsService
@@ -11,4 +12,5 @@ object ServicePool {
val rankService = retrofit.create(RankService::class.java)
val statisticsService = retrofit.create(StatisticsService::class.java)
val placeService = retrofit.create(PlaceService::class.java)
val authService = retrofit.create(AuthService::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.now.naaga.data.remote.retrofit.service

import com.now.naaga.data.remote.dto.NaagaAuthDto
import com.now.naaga.data.remote.dto.PlatformAuthDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface AuthService {
@POST("/auth")
fun requestToken(
@Body platformAuthDto: PlatformAuthDto,
): Call<NaagaAuthDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.now.naaga.data.repository

import com.now.domain.model.NaagaAuth
import com.now.domain.model.PlatformAuth
import com.now.domain.repository.AuthRepository
import com.now.naaga.data.mapper.toDomain
import com.now.naaga.data.mapper.toDto
import com.now.naaga.data.remote.retrofit.ServicePool
import com.now.naaga.data.remote.retrofit.fetchNaagaResponse

class DefaultAuthRepository : AuthRepository {
override fun getToken(
platformAuth: PlatformAuth,
callback: (Result<NaagaAuth>) -> Unit,
) {
val call = ServicePool.authService.requestToken(platformAuth.toDto())
call.fetchNaagaResponse(
onSuccess = { callback(Result.success(it.toDomain())) },
onFailure = { callback(Result.failure(it)) },
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.now.naaga.presentation.login

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.ViewModelProvider
import com.kakao.sdk.auth.TokenManagerProvider
import com.now.naaga.R
import com.now.naaga.data.local.KakaoAuthDataSource
import com.now.naaga.data.repository.DefaultAuthRepository
import com.now.naaga.databinding.ActivityLoginBinding
import com.now.naaga.presentation.beginadventure.BeginAdventureActivity
import com.now.naaga.util.loginWithKakao

class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
private lateinit var viewModel: LoginViewModel

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.lifecycleOwner = this
initViewModel()
setClickListeners()
setStatusBar()
getToken()?.let { viewModel.fetchToken(it) }
}

private fun initViewModel() {
val authRepository = DefaultAuthRepository()
val authPreference = KakaoAuthDataSource(this)
val factory = LoginViewModelFactory(authRepository, authPreference)
viewModel = ViewModelProvider(this, factory)[LoginViewModel::class.java]
}

private fun getToken(): String? {
return TokenManagerProvider.instance.manager.getToken()?.accessToken
}

private fun setClickListeners() {
binding.ivLoginKakao.setOnClickListener {
loginWithKakao(this) { navigateHome() }
}
}

private fun setStatusBar() {
window.apply {
statusBarColor = getColor(R.color.white)
WindowInsetsControllerCompat(this, this.decorView).isAppearanceLightStatusBars = true
}
}

private fun navigateHome() {
startActivity(BeginAdventureActivity.getIntent(this))
finish()
}

companion object {
fun getIntent(context: Context): Intent {
return Intent(context, LoginActivity::class.java)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.now.naaga.presentation.login

import androidx.lifecycle.ViewModel
import com.now.domain.model.AuthPlatformType.KAKAO
import com.now.domain.model.PlatformAuth
import com.now.domain.repository.AuthRepository
import com.now.naaga.data.local.AuthDataSource

class LoginViewModel(
private val authRepository: AuthRepository,
private val authDataSource: AuthDataSource,
) : ViewModel() {
fun fetchToken(token: String) {
authRepository.getToken(
PlatformAuth(token, KAKAO),
callback = { result ->
result
.onSuccess { authDataSource.setAccessToken(it.accessToken) }
.onFailure { }
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.now.naaga.presentation.login

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.now.domain.repository.AuthRepository
import com.now.naaga.data.local.AuthDataSource

class LoginViewModelFactory(
private val authRepository: AuthRepository,
private val authDataSource: AuthDataSource,
) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
return LoginViewModel(authRepository, authDataSource) as T
} else {
throw IllegalArgumentException()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.now.naaga.presentation.login

import android.app.Application
import android.content.Context
import com.kakao.sdk.common.KakaoSdk
import com.now.naaga.BuildConfig

class NaagaApplication : Application() {
init {
instance = this
}

override fun onCreate() {
super.onCreate()
KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY)
}

companion object {
private var instance: NaagaApplication? = null
fun getContext(): Context {
return instance?.applicationContext ?: throw IllegalStateException()
}
}
}
Original file line number Diff line number Diff line change
@@ -56,6 +56,7 @@ class MyPageActivity : AppCompatActivity(), AnalyticsDelegate by DefaultAnalytic
viewModel.fetchRank()
viewModel.fetchStatistics()
viewModel.fetchPlaces()
viewModel.fetchNickname()
}

private fun subscribe() {
@@ -66,7 +67,9 @@ class MyPageActivity : AppCompatActivity(), AnalyticsDelegate by DefaultAnalytic
val placesUiModel = places.map { it.toUiModel() }
binding.customGridMypagePlaces.initContent(placesUiModel)
}

viewModel.nickname.observe(this) { nickname ->
binding.tvMypageNickname.text = nickname
}
viewModel.errorMessage.observe(this) { errorMessage ->
if (NaagaThrowable.ServerConnectFailure().message == errorMessage) {
Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show()
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.now.naaga.presentation.mypage

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.kakao.sdk.user.UserApiClient
import com.now.domain.model.OrderType
import com.now.domain.model.Place
import com.now.domain.model.Rank
@@ -30,6 +32,9 @@ class MyPageViewModel(
private val _errorMessage = MutableLiveData<String>()
val errorMessage: LiveData<String> = _errorMessage

private val _nickname = MutableLiveData<String>()
val nickname: LiveData<String> = _nickname

fun fetchRank() {
rankRepository.getMyRank { result: Result<Rank> ->
result
@@ -54,10 +59,27 @@ class MyPageViewModel(
}
}

fun fetchNickname() {
UserApiClient.instance.me { user, error ->
if (error != null) {
Log.d(KAKAO_USER_INFO_LOG_TAG, KAKAO_USER_INFO_FAIL_MESSAGE + error)
} else if (user != null) {
Log.d(KAKAO_USER_INFO_LOG_TAG, KAKAO_USER_INFO_SUCCESS_MESSAGE)
_nickname.value = user.kakaoAccount?.profile?.nickname.toString()
}
}
}

private fun setErrorMessage(throwable: Throwable) {
when (throwable) {
is NaagaThrowable.ServerConnectFailure ->
_errorMessage.value = throwable.message
}
}

companion object {
private const val KAKAO_USER_INFO_LOG_TAG = "kakao user"
private const val KAKAO_USER_INFO_FAIL_MESSAGE = "사용자 정보 요청 실패"
private const val KAKAO_USER_INFO_SUCCESS_MESSAGE = "사용자 정보 요청 성공"
}
}
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import com.now.domain.model.AdventureStatus.IN_PROGRESS
import com.now.domain.model.AdventureStatus.NONE
import com.now.naaga.R
import com.now.naaga.presentation.beginadventure.BeginAdventureActivity
import com.now.naaga.presentation.login.LoginActivity
import com.now.naaga.presentation.onadventure.OnAdventureActivity

class SplashActivity : AppCompatActivity() {
@@ -44,8 +45,8 @@ class SplashActivity : AppCompatActivity() {
OnAdventureActivity.getIntentWithAdventure(this, adventure)
}
}
DONE -> BeginAdventureActivity.getIntent(this)
NONE -> BeginAdventureActivity.getIntent(this)
DONE -> LoginActivity.getIntent(this)
NONE -> LoginActivity.getIntent(this)
}
startActivity(intent)
finish()
44 changes: 44 additions & 0 deletions android/app/src/main/java/com/now/naaga/util/UserApiClientExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.now.naaga.util

import android.content.Context
import android.util.Log
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

private const val KAKAO_LOGIN_LOG_TAG = "kakao login"
private const val KAKAO_LOGIN_FAIL_MESSAGE = "카카오계정으로 로그인 실패"
private const val KAKAO_LOGIN_SUCCESS_MESSAGE = "카카오계정으로 로그인 성공"

private fun getLoginCallback(doNextAction: () -> Unit): (OAuthToken?, Throwable?) -> Unit {
val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
Log.d(KAKAO_LOGIN_LOG_TAG, KAKAO_LOGIN_FAIL_MESSAGE + error)
} else if (token != null) {
Log.d(KAKAO_LOGIN_LOG_TAG, KAKAO_LOGIN_SUCCESS_MESSAGE + token.accessToken)
doNextAction()
}
}
return callback
}

fun loginWithKakao(context: Context, doNextAction: () -> Unit) {
val callback = getLoginCallback(doNextAction)
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
if (error != null) {
Log.d(KAKAO_LOGIN_LOG_TAG, KAKAO_LOGIN_FAIL_MESSAGE + error)
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
return@loginWithKakaoTalk
}
UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
} else if (token != null) {
Log.d(KAKAO_LOGIN_LOG_TAG, KAKAO_LOGIN_SUCCESS_MESSAGE + token.accessToken)
doNextAction()
}
}
} else {
UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions android/app/src/main/res/drawable/ic_logo_purple.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="208dp"
android:height="229dp"
android:viewportWidth="208"
android:viewportHeight="229">
<path
android:pathData="M101.52,79.95L169.59,60.25C182.49,55.13 180.79,64.5 178.33,69.83C171.53,92.99 156.64,140.6 151.54,145.7C146.43,150.79 141.37,146.14 139.48,143.18C135.34,135.24 130.78,119.7 130.13,116.41C129.49,113.13 125.33,109.04 122.83,108.41C122,108.15 116.48,105.73 101.06,98.16C85.63,90.59 94.94,82.87 101.52,79.95Z"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M101.52,50.06L169.59,30.36C182.49,25.24 180.79,34.61 178.33,39.94C171.53,63.1 156.64,110.71 151.54,115.81C146.43,120.9 141.37,116.25 139.48,113.29C135.34,105.35 130.78,89.81 130.13,86.52C129.49,83.24 125.33,79.15 122.83,78.52C122,78.26 116.48,75.84 101.06,68.27C85.63,60.7 94.94,52.98 101.52,50.06Z"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M92.72,61.12V90.49"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M180.05,32.13V61.49"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M82.89,162.74L96.98,149.7C98.33,148.46 99.43,146.95 100.22,145.27L100.52,144.64C101.32,142.94 101.71,141.08 101.65,139.2V139.2C101.59,137.34 101.09,135.52 100.2,133.89L100.16,133.82C99.33,132.3 98.17,130.98 96.78,129.97L96.33,129.63C94.61,128.39 92.65,127.55 90.59,127.18L89.3,126.95M66.23,134.49V134.49C59.22,133.75 52.17,133.57 45.14,133.95L44.76,133.97M16.23,167.22L16.11,170.66C16.01,173.72 16.2,176.79 16.68,179.81L16.89,181.14C17.26,183.43 17.86,185.68 18.67,187.84V187.84C19.74,190.65 21.16,193.3 22.91,195.71L23.03,195.89C24.5,197.91 26.17,199.77 28.03,201.42L28.65,201.98C30.84,203.94 33.24,205.64 35.79,207.06V207.06C38.56,208.59 41.49,209.78 44.53,210.6L44.61,210.62C46.97,211.26 49.38,211.67 51.82,211.86L52.84,211.94C55.41,212.14 57.98,212.03 60.52,211.63V211.63C64.19,211.05 67.74,209.85 71.03,208.08L72.24,207.43L77.04,203.98C78.11,203.22 79.07,202.3 79.89,201.26L80.49,200.49C82.44,198.01 83.33,194.83 82.96,191.67V191.67C82.79,190.16 82.33,188.71 81.62,187.38L80.89,186.03C80.07,184.51 78.93,183.19 77.55,182.19L77.06,181.83C74.73,180.12 71.79,179.53 69,180.21V180.21C67.8,180.5 66.65,181.02 65.63,181.74L61.99,184.31C60.22,185.56 58.17,186.31 56.04,186.49V186.49C52.66,186.77 49.32,185.6 46.82,183.26L44.03,180.65"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M97.06,119.8L82.86,133.4C81.8,134.41 80.59,135.25 79.27,135.87L78.35,136.31C75.84,137.5 73,137.68 70.37,136.81C69.31,136.46 68.31,135.95 67.4,135.29L64.27,133.03C63.29,132.32 62.25,131.72 61.15,131.23L59.32,130.42C56.73,129.26 53.84,129.08 51.13,129.89C49.31,130.43 47.65,131.4 46.26,132.73L44.43,134.49C42.7,136.14 41.53,138.31 41.07,140.69C40.57,143.35 40.99,146.11 42.28,148.47L42.7,149.24C43.58,150.88 44.78,152.31 46.23,153.46L46.73,153.85C49.31,155.91 52.55,156.89 55.81,156.62C58.09,156.43 60.29,155.62 62.18,154.29L65.63,151.85C66.65,151.13 67.8,150.61 69,150.32C71.79,149.64 74.73,150.23 77.06,151.94L77.55,152.3C78.93,153.3 80.07,154.62 80.89,156.14L81.62,157.49C82.33,158.82 82.79,160.27 82.96,161.78C83.33,164.94 82.44,168.12 80.49,170.6L79.89,171.37C79.07,172.41 78.11,173.33 77.04,174.1L72.24,177.54L71.03,178.19C67.74,179.96 64.19,181.16 60.52,181.74C57.98,182.15 55.41,182.25 52.84,182.05L51.82,181.97C49.38,181.79 46.97,181.37 44.61,180.74L44.53,180.71C41.49,179.89 38.56,178.7 35.79,177.17C33.24,175.75 30.84,174.05 28.65,172.09L28.03,171.53C26.17,169.88 24.5,168.02 23.03,166L22.91,165.83C21.16,163.41 19.74,160.76 18.67,157.95C17.86,155.79 17.26,153.54 16.89,151.25L16.56,149.18C16.16,146.65 16,144.09 16.09,141.52C16.18,138.74 16.57,135.97 17.24,133.26L17.33,132.89C17.89,130.62 18.67,128.4 19.65,126.28C21.3,122.69 23.51,119.4 26.2,116.53L26.47,116.24C28.49,114.09 30.74,112.18 33.18,110.56L34.01,110.01C36.38,108.43 38.95,107.11 41.59,106.11C44.86,104.86 48.32,104.08 51.79,103.8C54.39,103.59 57.01,103.67 59.6,104.02L60.45,104.13C63.05,104.49 65.61,105.07 68.11,105.87L72.42,107.25C73.32,107.54 74.29,107.31 74.98,106.66L80.32,101.54C81.67,100.25 83.25,99.24 84.97,98.55L85.73,98.25C87.36,97.61 89.11,97.37 90.84,97.55C92.73,97.75 94.54,98.45 96.09,99.58L96.78,100.08C98.17,101.09 99.33,102.41 100.16,103.93L100.2,104C101.09,105.63 101.59,107.45 101.65,109.31C101.71,111.19 101.32,113.06 100.52,114.75L100.19,115.45C99.42,117.08 98.36,118.56 97.06,119.8Z"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M101.74,109.39V138.75"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
<path
android:pathData="M16.01,146.45V175.82"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#D4A5E4"/>
</vector>
48 changes: 48 additions & 0 deletions android/app/src/main/res/layout/activity_login.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".presentation.login.LoginActivity">

<ImageView
android:id="@+id/iv_login_kakao"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_kakao_login" />

<ImageView
android:id="@+id/imageView3"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:adjustViewBounds="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_logo_purple" />

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:fontFamily="@font/pretendard_medium"
android:text="@string/login_app_title"
android:textColor="@color/main_purple"
android:textSize="50sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView3" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
1 change: 0 additions & 1 deletion android/app/src/main/res/layout/activity_my_page.xml
Original file line number Diff line number Diff line change
@@ -38,7 +38,6 @@
android:layout_marginStart="@dimen/space_default_large"
android:fontFamily="@font/pretendard_bold"
android:includeFontPadding="false"
android:text="@{viewModel.rank.player.nickname}"
android:textColor="@color/white"
android:textSize="52sp"
android:maxLines="1"
3 changes: 3 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -90,4 +90,7 @@
<string name="hint_using_dialog_description">힌트가 %d개 남았어요</string>
<string name="hint_using_dialog_continue">힌트 받기</string>
<string name="hint_using_dialog_give_up">취소 하기</string>

<!-- LoginActivity -->
<string name="login_app_title">NAAGA</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.now.domain.model

enum class AuthPlatformType {
KAKAO,
NONE, ;

companion object {
fun findByName(text: String): AuthPlatformType {
return AuthPlatformType.values().find { it.name == text } ?: NONE
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.now.domain.model

data class NaagaAuth(
val accessToken: String,
val refreshToken: String?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.now.domain.model

data class PlatformAuth(
val token: String,
val type: AuthPlatformType,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.now.domain.repository

import com.now.domain.model.NaagaAuth
import com.now.domain.model.PlatformAuth

interface AuthRepository {
fun getToken(
platformAuth: PlatformAuth,
callback: (Result<NaagaAuth>) -> Unit,
)
}
3 changes: 3 additions & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -13,6 +13,9 @@ dependencyResolutionManagement {
maven {
url 'https://naver.jfrog.io/artifactory/maven/'
}
maven {
url 'https://devrepo.kakao.com/nexus/content/groups/public/'
}
}
}
rootProject.name = "Naaga"

0 comments on commit 74dda58

Please sign in to comment.