Skip to content

Commit b58abb9

Browse files
authored
Merge branch 'develop' into 17-feature-alarmsettingview
2 parents 2b182e7 + 11c3848 commit b58abb9

File tree

119 files changed

+2983
-449
lines changed

Some content is hidden

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

119 files changed

+2983
-449
lines changed

data/build.gradle

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
plugins {
22
id 'com.android.library'
33
id 'org.jetbrains.kotlin.android'
4-
id 'kotlin-kapt'
54
id 'com.google.dagger.hilt.android'
5+
id 'kotlin-kapt'
66
}
77

88
Properties properties = new Properties()
@@ -19,7 +19,12 @@ android {
1919
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2020
consumerProguardFiles "consumer-rules.pro"
2121

22-
buildConfigField("String", "TMAP_URL", properties['TMAP_URL'])
22+
23+
buildConfigField "String", "T_MAP_URL", properties['t_map_url']
24+
buildConfigField "String", "WS_BUS_URL", properties['ws_bus_url']
25+
buildConfigField "String", "APIS_URL", properties['apis_url']
26+
buildConfigField "String", "OPEN_API_SEOUL_URL", properties['open_api_seoul_url']
27+
buildConfigField "String", "T_MAP_APP_KEY", properties['t_map_app_key']
2328
buildConfigField "String", "SUBWAY_KEY", properties['subway_key']
2429
buildConfigField "String", "BUS_KEY", properties['bus_key']
2530
}
@@ -59,7 +64,23 @@ dependencies {
5964
implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
6065

6166
// Moshi
62-
implementation 'com.squareup.moshi:moshi-kotlin:1.13.0'
63-
implementation 'com.squareup.moshi:moshi:1.13.0'
64-
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.13.0'
67+
implementation 'com.squareup.moshi:moshi-kotlin:1.14.0'
68+
implementation 'com.squareup.moshi:moshi:1.14.0'
69+
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.14.0'
70+
71+
// xml parser
72+
implementation 'com.tickaroo.tikxml:annotation:0.8.13'
73+
implementation 'com.tickaroo.tikxml:core:0.8.13'
74+
implementation 'com.tickaroo.tikxml:retrofit-converter:0.8.13'
75+
kapt 'com.tickaroo.tikxml:processor:0.8.13'
76+
77+
// Room
78+
implementation "androidx.room:room-runtime:2.4.3"
79+
annotationProcessor "androidx.room:room-compiler:2.4.3"
80+
kapt "androidx.room:room-compiler:2.4.3"
81+
implementation "androidx.room:room-ktx:2.4.3"
82+
}
83+
84+
kapt {
85+
correctErrorTypes true
6586
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.stop.data.di
2+
3+
import com.stop.data.remote.network.*
4+
import dagger.Module
5+
import dagger.Provides
6+
import dagger.hilt.InstallIn
7+
import dagger.hilt.components.SingletonComponent
8+
import retrofit2.Retrofit
9+
import javax.inject.Named
10+
import javax.inject.Singleton
11+
12+
@InstallIn(SingletonComponent::class)
13+
@Module
14+
internal object ApiModule {
15+
16+
@Provides
17+
@Singleton
18+
fun provideTmapApiService(@Named("Tmap") retrofit: Retrofit): TmapApiService {
19+
return retrofit.create(TmapApiService::class.java)
20+
}
21+
22+
@Provides
23+
@Singleton
24+
fun provideFakeTmapApiService(@Named("Tmap") retrofit: Retrofit): FakeTmapApiService {
25+
return retrofit.create(FakeTmapApiService::class.java)
26+
}
27+
28+
@Provides
29+
@Singleton
30+
fun provideOpenApiSeoulService(@Named("OpenApiSeoul") retrofit: Retrofit): OpenApiSeoulService {
31+
return retrofit.create(OpenApiSeoulService::class.java)
32+
}
33+
34+
@Provides
35+
@Singleton
36+
fun provideWsBusApiService(@Named("WsBus") retrofit: Retrofit): WsBusApiService {
37+
return retrofit.create(WsBusApiService::class.java)
38+
}
39+
40+
@Provides
41+
@Singleton
42+
fun provideApisDataService(@Named("ApisData") retrofit: Retrofit): ApisDataService {
43+
return retrofit.create(ApisDataService::class.java)
44+
}
45+
46+
@Provides
47+
@Singleton
48+
fun providePlaceApiService(@Named("Tmap") retrofit: Retrofit): NearPlaceApiService {
49+
return retrofit.create(NearPlaceApiService::class.java)
50+
}
51+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.stop.data.di
2+
3+
import com.stop.data.local.source.alarm.AlarmLocalDataSource
4+
import com.stop.data.local.source.alarm.AlarmLocalDataSourceImpl
5+
import com.stop.data.remote.source.nearplace.NearPlaceRemoteDataSource
6+
import com.stop.data.remote.source.nearplace.NearPlaceRemoteDataSourceImpl
7+
import com.stop.data.remote.source.route.RouteRemoteDataSource
8+
import com.stop.data.remote.source.route.RouteRemoteDataSourceImpl
9+
import dagger.Binds
10+
import dagger.Module
11+
import dagger.hilt.InstallIn
12+
import dagger.hilt.components.SingletonComponent
13+
import javax.inject.Singleton
14+
15+
@InstallIn(SingletonComponent::class)
16+
@Module
17+
internal interface DataSourceModule {
18+
19+
@Binds
20+
@Singleton
21+
fun provideNearPlaceRemoteDataSource(
22+
nearPlaceRemoteDataSourceImpl: NearPlaceRemoteDataSourceImpl
23+
): NearPlaceRemoteDataSource
24+
25+
@Binds
26+
@Singleton
27+
fun provideRouteRemoteDataSource(
28+
routeRemoteDataSourceImpl: RouteRemoteDataSourceImpl
29+
): RouteRemoteDataSource
30+
31+
@Binds
32+
@Singleton
33+
fun provideAlarmLocalDataSource(
34+
alarmLocalDataSourceImpl: AlarmLocalDataSourceImpl
35+
): AlarmLocalDataSource
36+
37+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.stop.data.di
2+
3+
import android.content.Context
4+
import androidx.room.Room
5+
import com.stop.data.local.database.dao.AlarmDao
6+
import com.stop.data.local.database.dao.TroubleShooterApplicationDatabase
7+
import com.stop.data.local.database.dao.TroubleShooterApplicationDatabase.Companion.DB_NAME
8+
import dagger.Module
9+
import dagger.Provides
10+
import dagger.hilt.InstallIn
11+
import dagger.hilt.android.qualifiers.ApplicationContext
12+
import dagger.hilt.components.SingletonComponent
13+
import javax.inject.Singleton
14+
15+
@InstallIn(SingletonComponent::class)
16+
@Module
17+
class DatabaseModule {
18+
19+
@Provides
20+
@Singleton
21+
fun provideApplicationDatabase(@ApplicationContext context: Context): TroubleShooterApplicationDatabase {
22+
return Room.databaseBuilder(
23+
context,
24+
TroubleShooterApplicationDatabase::class.java,
25+
DB_NAME
26+
).fallbackToDestructiveMigration()
27+
.build()
28+
}
29+
30+
@Provides
31+
@Singleton
32+
fun provideAlarmDao(troubleShooterApplicationDatabase: TroubleShooterApplicationDatabase): AlarmDao {
33+
return troubleShooterApplicationDatabase.getAlarmDao()
34+
}
35+
}

data/src/main/java/com/stop/data/di/NetworkModule.kt

Lines changed: 141 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,183 @@ package com.stop.data.di
22

33
import com.squareup.moshi.Moshi
44
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
5-
import com.stop.data.remote.ResponseAdapterFactory
6-
import com.stop.data.remote.network.NearPlaceApiService
75
import com.stop.data.BuildConfig
6+
import com.stop.data.remote.ResultCallAdapter
7+
import com.tickaroo.tikxml.TikXml
8+
import com.tickaroo.tikxml.retrofit.TikXmlConverterFactory
89
import dagger.Module
910
import dagger.Provides
1011
import dagger.hilt.InstallIn
1112
import dagger.hilt.components.SingletonComponent
13+
import okhttp3.Interceptor
14+
import okhttp3.MediaType.Companion.toMediaTypeOrNull
1215
import okhttp3.OkHttpClient
16+
import okhttp3.Protocol
17+
import okhttp3.Response
18+
import okhttp3.ResponseBody.Companion.toResponseBody
1319
import okhttp3.logging.HttpLoggingInterceptor
1420
import retrofit2.Retrofit
1521
import retrofit2.converter.moshi.MoshiConverterFactory
16-
import java.util.concurrent.TimeUnit
22+
import javax.inject.Named
1723
import javax.inject.Singleton
1824

19-
@Module
2025
@InstallIn(SingletonComponent::class)
26+
@Module
2127
internal object NetworkModule {
2228

29+
private const val T_MAP_APP_KEY_NAME = "appKey"
30+
private const val OPEN_API_SEOUL_KEY_NAME = "KEY"
31+
private const val APIS_KEY_NAME = "ServiceKey"
32+
private const val WS_KEY_NAME = "ServiceKey"
33+
34+
private const val T_MAP_ROUTE_URL = "transit/routes"
35+
36+
/**
37+
* resources에 fake 데이터가 담긴 파일을 넣어줘야 Fake TMap이 정상적으로 동작합니다.
38+
*/
39+
private const val FAKE_JSON_URI = "response.json"
40+
2341
@Provides
2442
@Singleton
25-
fun provideHttpClient(): OkHttpClient {
43+
fun provideOkHttpClient(
44+
customInterceptor: CustomInterceptor,
45+
loggingInterceptor: HttpLoggingInterceptor,
46+
): OkHttpClient {
2647
return OkHttpClient.Builder()
27-
.readTimeout(10, TimeUnit.SECONDS)
28-
.connectTimeout(10, TimeUnit.SECONDS)
29-
.writeTimeout(15, TimeUnit.SECONDS)
30-
.addInterceptor(getLoggingInterceptor())
48+
.addInterceptor(loggingInterceptor)
49+
.addInterceptor(customInterceptor)
3150
.build()
3251
}
3352

34-
private fun getLoggingInterceptor(): HttpLoggingInterceptor =
35-
HttpLoggingInterceptor().apply {
36-
level = HttpLoggingInterceptor.Level.BODY
37-
}
3853

3954
@Provides
4055
@Singleton
41-
fun provideMoshi(): Moshi =
42-
Moshi.Builder()
43-
.add(KotlinJsonAdapterFactory())
56+
fun provideMoshi(): Moshi {
57+
return Moshi.Builder()
58+
.addLast(KotlinJsonAdapterFactory())
4459
.build()
60+
}
4561

62+
@Provides
4663
@Singleton
64+
fun provideTikXmlConverterFactory(): TikXmlConverterFactory {
65+
return TikXmlConverterFactory.create(TikXml.Builder().exceptionOnUnreadXml(false).build())
66+
}
67+
68+
@Provides
69+
fun provideCustomInterceptor(): CustomInterceptor {
70+
return CustomInterceptor()
71+
}
72+
4773
@Provides
48-
fun provideRetrofitInstance(
74+
fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
75+
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
76+
}
77+
78+
@Provides
79+
fun provideResultCallAdapter(): ResultCallAdapter.Factory {
80+
return ResultCallAdapter.Factory()
81+
}
82+
83+
@Provides
84+
@Named("Tmap")
85+
fun provideTmapRetrofitInstance(
4986
okHttpClient: OkHttpClient,
50-
moshi: Moshi
87+
moshi: Moshi,
88+
resultCallAdapter: ResultCallAdapter.Factory,
5189
): Retrofit {
5290
return Retrofit.Builder()
53-
.baseUrl(BuildConfig.TMAP_URL)
91+
.baseUrl(BuildConfig.T_MAP_URL)
5492
.client(okHttpClient)
55-
.addCallAdapterFactory(ResponseAdapterFactory())
93+
.addCallAdapterFactory(resultCallAdapter)
5694
.addConverterFactory(MoshiConverterFactory.create(moshi))
5795
.build()
5896
}
5997

6098
@Provides
61-
@Singleton
62-
fun providePlaceApiService(retrofit: Retrofit): NearPlaceApiService {
63-
return retrofit.create(NearPlaceApiService::class.java)
99+
@Named("OpenApiSeoul")
100+
fun provideOpenApiSeoulRetrofitInstance(
101+
okHttpClient: OkHttpClient,
102+
moshi: Moshi,
103+
resultCallAdapter: ResultCallAdapter.Factory,
104+
): Retrofit {
105+
return Retrofit.Builder()
106+
.baseUrl(BuildConfig.OPEN_API_SEOUL_URL)
107+
.client(okHttpClient)
108+
.addCallAdapterFactory(resultCallAdapter)
109+
.addConverterFactory(MoshiConverterFactory.create(moshi))
110+
.build()
64111
}
65112

113+
@Provides
114+
@Named("WsBus")
115+
fun provideWsBusRetrofitInstance(
116+
okHttpClient: OkHttpClient,
117+
moshi: Moshi,
118+
resultCallAdapter: ResultCallAdapter.Factory,
119+
): Retrofit {
120+
return Retrofit.Builder()
121+
.baseUrl(BuildConfig.WS_BUS_URL)
122+
.client(okHttpClient)
123+
.addCallAdapterFactory(resultCallAdapter)
124+
.addConverterFactory(MoshiConverterFactory.create(moshi))
125+
.build()
126+
}
127+
128+
@Provides
129+
@Named("ApisData")
130+
fun provideApisDataRetrofitInstance(
131+
okHttpClient: OkHttpClient,
132+
tikXmlConverterFactory: TikXmlConverterFactory,
133+
resultCallAdapter: ResultCallAdapter.Factory,
134+
): Retrofit {
135+
return Retrofit.Builder()
136+
.baseUrl(BuildConfig.APIS_URL)
137+
.client(okHttpClient)
138+
.addCallAdapterFactory(resultCallAdapter)
139+
.addConverterFactory(tikXmlConverterFactory)
140+
.build()
141+
}
142+
143+
class CustomInterceptor : Interceptor {
144+
override fun intercept(chain: Interceptor.Chain): Response {
145+
val url = chain.request().url.toUri().toString()
146+
147+
if (url.contains(T_MAP_ROUTE_URL)) {
148+
val response = readJson(FAKE_JSON_URI)
149+
return chain.proceed(chain.request())
150+
.newBuilder()
151+
.code(200)
152+
.protocol(Protocol.HTTP_2)
153+
.message("success")
154+
.body(
155+
response.toByteArray()
156+
.toResponseBody("application/json".toMediaTypeOrNull())
157+
).addHeader("content-type", "application/json")
158+
.build()
159+
}
160+
161+
val (name: String, key: String) = when {
162+
url.contains(BuildConfig.OPEN_API_SEOUL_URL) -> Pair(OPEN_API_SEOUL_KEY_NAME, BuildConfig.BUS_KEY)
163+
url.contains(BuildConfig.T_MAP_URL) -> Pair(T_MAP_APP_KEY_NAME, BuildConfig.T_MAP_APP_KEY)
164+
url.contains(BuildConfig.APIS_URL) -> Pair(APIS_KEY_NAME, BuildConfig.BUS_KEY)
165+
url.contains(BuildConfig.WS_BUS_URL) -> Pair(WS_KEY_NAME, BuildConfig.BUS_KEY)
166+
else -> {
167+
return chain.proceed(chain.request())
168+
}
169+
}
170+
171+
return with(chain) {
172+
val newRequest = request().newBuilder()
173+
.addHeader(name, key)
174+
.build()
175+
proceed(newRequest)
176+
}
177+
}
178+
179+
private fun readJson(fileName: String): String {
180+
return Thread.currentThread().contextClassLoader?.getResource(fileName)
181+
?.readText() ?: ""
182+
}
183+
}
66184
}

0 commit comments

Comments
 (0)