Skip to content

Commit 5458359

Browse files
authored
[BASE] #22 Hilt 모듈 구현 (#24)
* [chore] hilt 의존성 추가 * [feature] PokitApplication 구현 및 등록 * [feature] NetworkModule 모듈 구현 * [chore] 타임아웃 설정 * [chore] auth request, response 데이터 추가 * [chore] auth api 추가 * [chore] auth api 수정 * [chore] 버전 카탈로그 라이브러리 추가 - domain 모듈 inject - logging-interceptor * [feature] hilt + 네트워크 모듈 구현 * [chore] @androidentrypoint 애노테이션 추가 * [chore] kotest 의존성 추가 * [feature] sns로그인 api연동 * [feature] 테스트 토큰 인터셉터 구현 * [feature] 닉네임 입력 화면 설계 * [chore] 뷰모델 주입 * [chore] 미사용 리소스 제거 * [chore] 코딩 컨벤션 적용 * [chore] 코딩 컨벤션 적용 * [chore] orbit 제거 * [chore] LoginScreen 로직 수정 * [feature] 애플 로그인 구현 * [feature] 네트워크 통신 모듈 구현 * [chore] 클래스명 수정 * [chore] 주석 제거 * [feature] parseErrorResult 함수 구현 * [chore] 닉네임 중복 처리 api 세팅 * [chore] parseErrorResult 분리 및 적용 * [chore] 중복 닉네임 api 세팅 * [chore] 코딩 컨벤션 반영 * [chore] ktlint rule 추가 * [chore] ktlint_standard_function-name 제거 * [chore] 파일 이름 수정
1 parent a68735a commit 5458359

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+716
-64
lines changed

.editorconfig

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@ indent_style = space
1111
trim_trailing_whitespace = true
1212
insert_final_newline = true
1313
tab_width = 4
14-
ij_kotlin_allow_trailing_comma = true
15-
ktlint_standard_function-name = false
14+
ij_kotlin_allow_trailing_comma = true

app/build.gradle.kts

+13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
plugins {
22
alias(libs.plugins.com.android.application)
33
alias(libs.plugins.org.jetbrains.kotlin.android)
4+
alias(libs.plugins.hilt)
5+
alias(libs.plugins.googleServices)
6+
id("kotlin-kapt")
47
}
58

69
android {
@@ -67,5 +70,15 @@ dependencies {
6770
debugImplementation(libs.androidx.ui.test.manifest)
6871

6972
implementation(project(":core:ui"))
73+
implementation(project(":data"))
74+
implementation(project(":domain"))
7075
implementation(project(":feature:login"))
76+
77+
// hilt
78+
implementation(libs.hilt)
79+
kapt(libs.hilt.compiler)
80+
81+
// firebase
82+
implementation(platform(libs.firebase.bom))
83+
implementation(libs.firebase.auth.ktx)
7184
}

app/google-services.json

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"project_info": {
3+
"project_number": "217769178527",
4+
"project_id": "pokit-f5c83",
5+
"storage_bucket": "pokit-f5c83.appspot.com"
6+
},
7+
"client": [
8+
{
9+
"client_info": {
10+
"mobilesdk_app_id": "1:217769178527:android:5d7efa4ceafe61c37af9aa",
11+
"android_client_info": {
12+
"package_name": "pokitmons.pokit"
13+
}
14+
},
15+
"oauth_client": [
16+
{
17+
"client_id": "217769178527-jaa8p8nfmic1j1065qs5a7vfqt18qec0.apps.googleusercontent.com",
18+
"client_type": 1,
19+
"android_info": {
20+
"package_name": "pokitmons.pokit",
21+
"certificate_hash": "9ded6dcd446add68f506001f3c1b457cc1c3be9e"
22+
}
23+
},
24+
{
25+
"client_id": "217769178527-mmbheg9v5npdhdrbfq78slpsk8lt2nga.apps.googleusercontent.com",
26+
"client_type": 1,
27+
"android_info": {
28+
"package_name": "pokitmons.pokit",
29+
"certificate_hash": "b2f3e34f8e02d15beb0d10d3d48a05148e943642"
30+
}
31+
},
32+
{
33+
"client_id": "217769178527-tslgsrrr1o8bli4hr4qnas2u9kg80a9h.apps.googleusercontent.com",
34+
"client_type": 3
35+
}
36+
],
37+
"api_key": [
38+
{
39+
"current_key": "AIzaSyDMh93QvJGUUX8-E-wyJoSS3cFrwfw8Q3w"
40+
}
41+
],
42+
"services": {
43+
"appinvite_service": {
44+
"other_platform_oauth_client": [
45+
{
46+
"client_id": "217769178527-l4prj2q9qsuvkodc2cpi84psvul5rth2.apps.googleusercontent.com",
47+
"client_type": 3
48+
},
49+
{
50+
"client_id": "217769178527-021j3dpbues9rhbkp6cffnn19mdajorq.apps.googleusercontent.com",
51+
"client_type": 2,
52+
"ios_info": {
53+
"bundle_id": "com.pokitmons.pokit.App"
54+
}
55+
}
56+
]
57+
}
58+
}
59+
}
60+
],
61+
"configuration_version": "1"
62+
}

app/src/main/AndroidManifest.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
<uses-permission android:name="android.permission.INTERNET" />
66

77
<application
8-
android:allowBackup="true"
8+
android:name=".PokitApplication"
9+
android:allowBackup="false"
910
android:dataExtractionRules="@xml/data_extraction_rules"
1011
android:fullBackupContent="@xml/backup_rules"
1112
android:icon="@mipmap/ic_launcher"

app/src/main/java/pokitmons/pokit/MainActivity.kt

+2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package pokitmons.pokit
33
import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
6+
import dagger.hilt.android.AndroidEntryPoint
67
import pokitmons.pokit.core.ui.theme.PokitTheme
78
import pokitmons.pokit.navigation.LoginNavHost
89

10+
@AndroidEntryPoint
911
class MainActivity : ComponentActivity() {
1012
override fun onCreate(savedInstanceState: Bundle?) {
1113
super.onCreate(savedInstanceState)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package pokitmons.pokit
2+
3+
import android.app.Application
4+
import com.google.firebase.FirebaseApp
5+
import dagger.hilt.android.HiltAndroidApp
6+
7+
@HiltAndroidApp
8+
class PokitApplication : Application() {
9+
override fun onCreate() {
10+
super.onCreate()
11+
FirebaseApp.initializeApp(this)
12+
}
13+
}

build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ plugins {
44
alias(libs.plugins.org.jetbrains.kotlin.android) apply false
55
alias(libs.plugins.ktlint.gradle) apply false
66
alias(libs.plugins.org.jetbrains.kotlin.jvm) apply false
7+
alias(libs.plugins.hilt) apply false
78
alias(libs.plugins.com.android.library) apply false
9+
alias(libs.plugins.googleServices) apply false
810
}
911

1012
subprojects {

data/build.gradle.kts

+27
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
plugins {
22
alias(libs.plugins.com.android.library)
33
alias(libs.plugins.org.jetbrains.kotlin.android)
4+
alias(libs.plugins.kotlin.serialization)
5+
alias(libs.plugins.hilt)
6+
id("kotlin-kapt")
47
}
58

69
android {
10+
tasks.withType<Test>().configureEach {
11+
useJUnitPlatform()
12+
}
13+
714
namespace = "pokitmons.pokit.data"
815
compileSdk = 34
916

@@ -38,6 +45,26 @@ dependencies {
3845
implementation(libs.appcompat)
3946
implementation(libs.material)
4047
testImplementation(libs.junit)
48+
testImplementation(project(":feature:login"))
4149
androidTestImplementation(libs.androidx.junit)
4250
androidTestImplementation(libs.androidx.espresso.core)
51+
52+
// kotest
53+
testImplementation(libs.kotest.runner.junit5)
54+
testImplementation(libs.kotlin.reflect)
55+
56+
// hilt
57+
implementation(libs.hilt)
58+
kapt(libs.hilt.compiler)
59+
60+
// serialization
61+
implementation(libs.kotlinx.serialization.json)
62+
63+
// retrofit
64+
implementation(libs.retrofit)
65+
implementation(libs.retrofit.converter.serialization)
66+
implementation(libs.okhttp)
67+
implementation(libs.logging.interceptor)
68+
69+
implementation(project(":domain"))
4370
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package pokitmons.pokit.data.api
2+
3+
import pokitmons.pokit.data.model.auth.request.SNSLoginRequest
4+
import pokitmons.pokit.data.model.auth.response.DuplicateNicknameResponse
5+
import pokitmons.pokit.data.model.auth.response.SNSLoginResponse
6+
import retrofit2.http.Body
7+
import retrofit2.http.GET
8+
import retrofit2.http.POST
9+
import retrofit2.http.Path
10+
11+
interface AuthApi {
12+
@POST("auth/signin")
13+
suspend fun snsLogin(
14+
@Body snsLoginRequest: SNSLoginRequest,
15+
): SNSLoginResponse
16+
17+
@GET("user/duplicate/{nickname}")
18+
suspend fun checkDuplicateNickname(
19+
@Path(value = "nickname") nickname: String,
20+
): DuplicateNicknameResponse
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package pokitmons.pokit.data.datasource.remote.auth
2+
3+
import pokitmons.pokit.data.model.auth.request.SNSLoginRequest
4+
import pokitmons.pokit.data.model.auth.response.DuplicateNicknameResponse
5+
import pokitmons.pokit.data.model.auth.response.SNSLoginResponse
6+
7+
interface AuthDataSource {
8+
// suspend fun signUp(signUpRequest: SignUpRequest): PokitResponse<SignUpResponse>
9+
suspend fun snsLogin(snsLoginRequest: SNSLoginRequest): SNSLoginResponse
10+
suspend fun checkDuplicateNickname(nickname: String): DuplicateNicknameResponse
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package pokitmons.pokit.data.datasource.remote.auth
2+
3+
import pokitmons.pokit.data.api.AuthApi
4+
import pokitmons.pokit.data.model.auth.request.SNSLoginRequest
5+
import pokitmons.pokit.data.model.auth.response.DuplicateNicknameResponse
6+
import pokitmons.pokit.data.model.auth.response.SNSLoginResponse
7+
import javax.inject.Inject
8+
9+
class RemoteAuthDataSourceImpl @Inject constructor(private val authApi: AuthApi) : AuthDataSource {
10+
override suspend fun snsLogin(snsLoginRequest: SNSLoginRequest): SNSLoginResponse {
11+
return authApi.snsLogin(snsLoginRequest)
12+
}
13+
14+
override suspend fun checkDuplicateNickname(nickname: String): DuplicateNicknameResponse {
15+
return authApi.checkDuplicateNickname(nickname)
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package pokitmons.pokit.data.di.auth
2+
3+
import dagger.Binds
4+
import dagger.Module
5+
import dagger.hilt.InstallIn
6+
import dagger.hilt.components.SingletonComponent
7+
import pokitmons.pokit.data.datasource.remote.auth.AuthDataSource
8+
import pokitmons.pokit.data.datasource.remote.auth.RemoteAuthDataSourceImpl
9+
import pokitmons.pokit.data.repository.auth.AuthRepositoryImpl
10+
import pokitmons.pokit.domain.repository.auth.AuthRepository
11+
import javax.inject.Singleton
12+
13+
@Module
14+
@InstallIn(SingletonComponent::class)
15+
abstract class AuthModule {
16+
@Binds
17+
@Singleton
18+
abstract fun bindAuthRepository(authRepositoryImpl: AuthRepositoryImpl): AuthRepository
19+
20+
@Binds
21+
@Singleton
22+
abstract fun bindAuthDataSource(authDataSourceImpl: RemoteAuthDataSourceImpl): AuthDataSource
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package pokitmons.pokit.data.di.network
2+
3+
import okhttp3.Interceptor
4+
import okhttp3.Request
5+
import okhttp3.Response
6+
import java.io.IOException
7+
8+
// 토큰 api 수정될 때 까지 사용
9+
class BearerTokenInterceptor : Interceptor {
10+
@Throws(IOException::class)
11+
override fun intercept(chain: Interceptor.Chain): Response {
12+
val originalRequest: Request = chain.request()
13+
val requestWithToken: Request = originalRequest.newBuilder()
14+
.header(
15+
"Authorization",
16+
"Bearer eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzIxNjU4MjUxLCJleHAiOj" +
17+
"MwMDE3MjE2NTgyNTF9.gw6LZimKLuZJ2y0UV5cgvk3F7o92pkRIDgx-qlD_S7qEI01QAFt9dZDyHADabftI"
18+
)
19+
.build()
20+
21+
return chain.proceed(requestWithToken)
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package pokitmons.pokit.data.di.network
2+
3+
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
4+
import dagger.Module
5+
import dagger.Provides
6+
import dagger.hilt.InstallIn
7+
import dagger.hilt.components.SingletonComponent
8+
import kotlinx.serialization.json.Json
9+
import okhttp3.MediaType.Companion.toMediaType
10+
import okhttp3.OkHttpClient
11+
import okhttp3.logging.HttpLoggingInterceptor
12+
import pokitmons.pokit.data.api.AuthApi
13+
import retrofit2.Retrofit
14+
import java.util.concurrent.TimeUnit
15+
import javax.inject.Singleton
16+
17+
private const val BASE_URL = "https://pokit.site"
18+
private const val API = "api"
19+
private const val VERSION = "v1"
20+
21+
private const val READ_TIME_OUT = 20000L
22+
private const val WRITE_TIME_OUT = 20000L
23+
24+
@Module
25+
@InstallIn(SingletonComponent::class)
26+
object NetworkModule {
27+
@Singleton
28+
@Provides
29+
fun provideOkHttpClient(): OkHttpClient {
30+
return OkHttpClient.Builder()
31+
.addInterceptor(BearerTokenInterceptor())
32+
.addInterceptor(
33+
HttpLoggingInterceptor().apply {
34+
level = HttpLoggingInterceptor.Level.BODY
35+
}
36+
)
37+
.readTimeout(READ_TIME_OUT, TimeUnit.SECONDS)
38+
.writeTimeout(WRITE_TIME_OUT, TimeUnit.SECONDS)
39+
.build()
40+
}
41+
42+
@Singleton
43+
@Provides
44+
fun provideJson(): Json {
45+
return Json {
46+
ignoreUnknownKeys = true
47+
coerceInputValues = true
48+
prettyPrint = true
49+
}
50+
}
51+
52+
@Singleton
53+
@Provides
54+
fun provideRetrofit(
55+
okHttpClient: OkHttpClient,
56+
json: Json,
57+
): Retrofit {
58+
val converterFactory = json.asConverterFactory("application/json; charset=UTF8".toMediaType())
59+
return Retrofit.Builder()
60+
.baseUrl("$BASE_URL/$API/$VERSION/")
61+
.addConverterFactory(converterFactory)
62+
.client(okHttpClient)
63+
.build()
64+
}
65+
66+
@Provides
67+
fun provideAuthService(retrofit: Retrofit): AuthApi {
68+
return retrofit.create(AuthApi::class.java)
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package pokitmons.pokit.data.mapper.auth
2+
3+
import pokitmons.pokit.data.model.auth.response.DuplicateNicknameResponse
4+
import pokitmons.pokit.data.model.auth.response.SNSLoginResponse
5+
import pokitmons.pokit.domain.model.auth.DuplicateNicknameResult
6+
import pokitmons.pokit.domain.model.auth.SNSLoginResult
7+
8+
object AuthMapper {
9+
fun mapperToSNSLogin(snsLoginResponse: SNSLoginResponse): SNSLoginResult {
10+
return SNSLoginResult(
11+
accessToken = snsLoginResponse.accessToken,
12+
refreshToken = snsLoginResponse.refreshToken
13+
)
14+
}
15+
16+
fun mapperToDuplicateNickname(checkDuplicateNicknameResponse: DuplicateNicknameResponse): DuplicateNicknameResult {
17+
return DuplicateNicknameResult(
18+
isDuplicate = checkDuplicateNicknameResponse.isDuplicate
19+
)
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pokitmons.pokit.data.model.auth.request
2+
3+
import kotlinx.serialization.Serializable
4+
5+
@Serializable
6+
data class SNSLoginRequest(
7+
val authPlatform: String,
8+
val idToken: String,
9+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package pokitmons.pokit.data.model.auth.request
2+
3+
data class SignUpRequest(
4+
val nickname: String,
5+
val interests: List<String>,
6+
)

0 commit comments

Comments
 (0)