Skip to content

Commit ac536c8

Browse files
authored
Merge pull request #554 from TeamSparker/release-1.1.0
#551 재재업로드 Release 1.1.0
2 parents c09b34b + 821956a commit ac536c8

File tree

125 files changed

+1503
-88
lines changed

Some content is hidden

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

125 files changed

+1503
-88
lines changed

.idea/deploymentTargetDropDown.xml

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ android {
1515
applicationId "com.teamsparker.android"
1616
minSdk 26
1717
targetSdk 31
18-
versionCode 4
19-
versionName "1.0.2"
18+
versionCode 5
19+
versionName "1.1.0"
2020

2121
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2222
}

app/src/main/java/com/teamsparker/android/data/local/datasource/LocalPreferencesDataSourceImpl.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ class LocalPreferencesDataSourceImpl @Inject constructor(
105105
}
106106

107107
companion object {
108-
private const val ACCESS_TOKEN = "ACCESS_TOKEN"
109-
private const val USER_KAKAO_USER_ID = "USER_KAKAO_USER_ID"
110-
private const val USER_NICKNAME = "USER_NAME"
111-
private const val ALARM_LOCAL_SAVED = "ALARM_LOCAL_SAVED"
108+
const val ACCESS_TOKEN = "ACCESS_TOKEN"
109+
const val USER_KAKAO_USER_ID = "USER_KAKAO_USER_ID"
110+
const val USER_NICKNAME = "USER_NAME"
111+
const val ALARM_LOCAL_SAVED = "ALARM_LOCAL_SAVED"
112112
const val DEFAULT_STRING_VALUE = ""
113113
}
114114
}

app/src/main/java/com/teamsparker/android/data/remote/RetrofitBuilder.kt

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.teamsparker.android.data.remote
22

3+
import com.teamsparker.android.data.remote.calladapter.CustomCallAdapterFactory
34
import com.teamsparker.android.data.remote.service.*
45
import okhttp3.Interceptor
56
import okhttp3.OkHttpClient
@@ -28,19 +29,20 @@ object RetrofitBuilder {
2829
.addInterceptor(headerInterceptor)
2930
.build()
3031

31-
3232
private val retrofit: Retrofit = Retrofit.Builder()
3333
.baseUrl(BASE_URL)
3434
.client(okHttpClient)
35+
.addCallAdapterFactory(CustomCallAdapterFactory())
3536
.addConverterFactory(GsonConverterFactory.create())
3637
.build()
3738

3839
// 이 밑에다가 이런식으로 서비스 객체 생성하기
3940
// val sampleService: SampleService = retrofit.create(SampleService::class.java)
4041

41-
val habitService : HabitService = retrofit.create(HabitService::class.java)
42+
val habitService: HabitService = retrofit.create(HabitService::class.java)
4243
val storageService: StorageService = retrofit.create(StorageService::class.java)
43-
val photoCollectionService: PhotoCollectionService = retrofit.create(PhotoCollectionService::class.java)
44+
val photoCollectionService: PhotoCollectionService =
45+
retrofit.create(PhotoCollectionService::class.java)
4446
val photoMainService: PhotoMainService = retrofit.create(PhotoMainService::class.java)
4547
val setStatusService: SetStatusService = retrofit.create(SetStatusService::class.java)
4648
val sendSparkService: SendSparkService = retrofit.create(SendSparkService::class.java)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.teamsparker.android.data.remote.calladapter
2+
3+
import okhttp3.Request
4+
import okio.Timeout
5+
import retrofit2.Call
6+
import retrofit2.Callback
7+
import retrofit2.Response
8+
import java.io.IOException
9+
10+
class CustomCall<T : Any>(private val call: Call<T>) : Call<NetworkState<T>> {
11+
12+
override fun enqueue(callback: Callback<NetworkState<T>>) {
13+
call.enqueue(object : Callback<T> {
14+
override fun onResponse(call: Call<T>, response: Response<T>) {
15+
val body = response.body()
16+
val code = response.code()
17+
val error = response.errorBody()?.string()
18+
19+
if (response.isSuccessful) {
20+
if (body != null) {
21+
callback.onResponse(
22+
this@CustomCall,
23+
Response.success(NetworkState.Success(body))
24+
)
25+
} else {
26+
callback.onResponse(
27+
this@CustomCall,
28+
Response.success(
29+
NetworkState.UnknownError(
30+
IllegalStateException("body값이 null로 넘어옴"),
31+
"body값이 null로 넘어옴"
32+
)
33+
)
34+
)
35+
}
36+
} else {
37+
callback.onResponse(
38+
this@CustomCall,
39+
Response.success(NetworkState.Failure(code, error))
40+
)
41+
}
42+
}
43+
44+
override fun onFailure(call: Call<T>, t: Throwable) {
45+
val errorResponse = when (t) {
46+
is IOException -> NetworkState.NetworkError(t)
47+
else -> NetworkState.UnknownError(t, "onFailure에 진입,IoException 이외의 에러")
48+
}
49+
callback.onResponse(this@CustomCall, Response.success(errorResponse))
50+
}
51+
})
52+
}
53+
54+
override fun clone(): Call<NetworkState<T>> = CustomCall(call.clone())
55+
56+
override fun execute(): Response<NetworkState<T>> {
57+
throw UnsupportedOperationException("커스텀한 callAdapter에서는 execute를 사용하지 않습니다 ")
58+
}
59+
60+
override fun isExecuted(): Boolean = call.isExecuted
61+
62+
override fun cancel() = call.cancel()
63+
64+
override fun isCanceled(): Boolean = call.isCanceled
65+
66+
override fun request(): Request = call.request()
67+
68+
override fun timeout(): Timeout = call.timeout()
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.teamsparker.android.data.remote.calladapter
2+
3+
import retrofit2.Call
4+
import retrofit2.CallAdapter
5+
import java.lang.reflect.Type
6+
7+
class CustomCallAdapter<R : Any>(private val responseType: Type) :
8+
CallAdapter<R, Call<NetworkState<R>>> {
9+
override fun responseType(): Type = responseType
10+
11+
override fun adapt(call: Call<R>): Call<NetworkState<R>> = CustomCall(call)
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.teamsparker.android.data.remote.calladapter
2+
3+
import retrofit2.Call
4+
import retrofit2.CallAdapter
5+
import retrofit2.Retrofit
6+
import java.lang.reflect.ParameterizedType
7+
import java.lang.reflect.Type
8+
9+
class CustomCallAdapterFactory : CallAdapter.Factory() {
10+
11+
override fun get(
12+
returnType: Type,
13+
annotations: Array<out Annotation>,
14+
retrofit: Retrofit
15+
): CallAdapter<*, *>? {
16+
if (Call::class.java != getRawType(returnType)) {
17+
return null
18+
}
19+
20+
check(returnType is ParameterizedType) {
21+
"return type must be parameterized as Call<NetworkState<Foo>> or Call<NetworkState<out Foo>>"
22+
}
23+
24+
val responseType = getParameterUpperBound(0, returnType)
25+
26+
if (getRawType(responseType) != NetworkState::class.java) {
27+
return null
28+
}
29+
30+
check(responseType is ParameterizedType) {
31+
"Response must be parameterized as NetworkState<Foo> or NetworkState<out Foo>"
32+
}
33+
34+
val bodyType = getParameterUpperBound(0, responseType)
35+
36+
return CustomCallAdapter<Any>(bodyType)
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.teamsparker.android.data.remote.calladapter
2+
3+
import java.io.IOException
4+
5+
sealed class NetworkState<out T : Any> {
6+
7+
// 200대 응답 성공한것
8+
data class Success<T : Any>(val body: T) : NetworkState<T>()
9+
10+
// isSuccessful 이 false인 경우(200~300대 응답이 아닌경우)
11+
data class Failure(val code: Int, val error: String?) : NetworkState<Nothing>()
12+
13+
// onFailure로 넘어간경우(네트워크 오류,timeout 같은거)
14+
data class NetworkError(val error: IOException) : NetworkState<Nothing>()
15+
16+
// 예상 못한에러(기타 모든 에러처리)
17+
data class UnknownError(val t: Throwable?, val errorState: String) : NetworkState<Nothing>()
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.teamsparker.android.data.remote.calladapter
2+
3+
class RetrofitFailureStateException(error: String?, val code: Int) : Exception(error)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.teamsparker.android.data.remote.datasource
2+
3+
import com.teamsparker.android.data.remote.calladapter.NetworkState
4+
import com.teamsparker.android.data.remote.entity.response.BaseResponse
5+
import com.teamsparker.android.data.remote.entity.response.HabitRoomTimeLine
6+
import com.teamsparker.android.data.remote.service.HabitRoomTimeLineService
7+
import javax.inject.Inject
8+
9+
class HabitRoomTImeLineDataSourceImpl @Inject constructor(
10+
private val habitRoomTimeLineService: HabitRoomTimeLineService
11+
) : HabitRoomTimeLineDataSource {
12+
override suspend fun getHabitRoomTimeLine(roomId: Int): NetworkState<BaseResponse<HabitRoomTimeLine>> =
13+
habitRoomTimeLineService.getHabitRoomRimeLine(roomId)
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.teamsparker.android.data.remote.datasource
2+
3+
import com.teamsparker.android.data.remote.calladapter.NetworkState
4+
import com.teamsparker.android.data.remote.entity.response.BaseResponse
5+
import com.teamsparker.android.data.remote.entity.response.HabitRoomTimeLine
6+
7+
interface HabitRoomTimeLineDataSource {
8+
9+
suspend fun getHabitRoomTimeLine(roomId: Int): NetworkState<BaseResponse<HabitRoomTimeLine>>
10+
}

app/src/main/java/com/teamsparker/android/data/remote/entity/response/HabitResponse.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ data class HabitResponse(
55
val roomName: String,
66
val leftDay: Int,
77
val life: Int,
8-
val lifeDeductionCount : Int,
98
val startDate: String,
109
val endDate: String,
1110
val fromStart: Boolean,
1211
val moment: String,
1312
val purpose: String,
1413
val myRecord: HabitRecord,
1514
val otherRecords: List<OtherRecord>,
15+
val isTimelineNew: Boolean,
16+
val isTermNew: Boolean
1617
)
1718

1819
data class HabitRecord(
@@ -22,13 +23,13 @@ data class HabitRecord(
2223
val recordId: Int,
2324
val rest: Int = -1,
2425
val status: String,
25-
val userId: Int,
26+
val userId: Int
2627
)
2728

2829
data class OtherRecord(
2930
val nickname: String,
3031
val profileImg: String,
3132
val recordId: Int,
3233
val status: String,
33-
val userId: Int,
34+
val userId: Int
3435
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.teamsparker.android.data.remote.entity.response
2+
3+
import com.google.gson.annotations.SerializedName
4+
5+
data class HabitRoomTimeLine(
6+
@SerializedName("timelines")
7+
val timelines: List<Timeline>
8+
)
9+
10+
data class Timeline(
11+
@SerializedName("content")
12+
val content: String,
13+
@SerializedName("day")
14+
val day: String,
15+
@SerializedName("isNew")
16+
val isNew: Boolean,
17+
@SerializedName("profiles")
18+
val profiles: List<String>,
19+
@SerializedName("title")
20+
val title: String
21+
)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package com.teamsparker.android.data.remote.repository
22

3+
import com.teamsparker.android.data.remote.entity.response.HabitRoomTimeLine
4+
35
interface HabitRepository {
46

57
fun setHabitUserGuideState(state: Boolean)
68

79
fun getHabitUserGuideState(): Boolean
10+
11+
suspend fun getHabitRoomTimeLine(roomId: Int): Result<HabitRoomTimeLine>
812
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package com.teamsparker.android.data.remote.repository
22

33
import com.teamsparker.android.data.local.datasource.LocalPreferencesHabitDataSource
4+
import com.teamsparker.android.data.remote.calladapter.NetworkState
5+
import com.teamsparker.android.data.remote.calladapter.RetrofitFailureStateException
6+
import com.teamsparker.android.data.remote.datasource.HabitRoomTimeLineDataSource
7+
import com.teamsparker.android.data.remote.entity.response.HabitRoomTimeLine
8+
import timber.log.Timber.Forest.tag
9+
import java.security.cert.CertificateException
410
import javax.inject.Inject
511

612
class HabitRepositoryImpl @Inject constructor(
7-
private val localPreferencesHabitDataSource: LocalPreferencesHabitDataSource
13+
private val localPreferencesHabitDataSource: LocalPreferencesHabitDataSource,
14+
private val habitRoomTimeLineDataSource: HabitRoomTimeLineDataSource
815
) : HabitRepository {
916

1017
override fun setHabitUserGuideState(state: Boolean) {
@@ -13,4 +20,22 @@ class HabitRepositoryImpl @Inject constructor(
1320

1421
override fun getHabitUserGuideState(): Boolean =
1522
localPreferencesHabitDataSource.getHabitUserGuideState()
23+
24+
override suspend fun getHabitRoomTimeLine(roomId: Int): Result<HabitRoomTimeLine> {
25+
when (val response = habitRoomTimeLineDataSource.getHabitRoomTimeLine(roomId)) {
26+
is NetworkState.Success -> return Result.success(
27+
response.body.data
28+
)
29+
is NetworkState.Failure ->
30+
if (response.code == 401) throw CertificateException("토큰 만료 오류")
31+
else return Result.failure(
32+
RetrofitFailureStateException(response.error, response.code)
33+
)
34+
is NetworkState.NetworkError -> tag("${this.javaClass.name}_getHabitRoomTimeLine")
35+
.d(response.error)
36+
is NetworkState.UnknownError -> tag("${this.javaClass.name}_getHabitRoomTimeLine")
37+
.d(response.t)
38+
}
39+
return Result.failure(IllegalStateException("NetworkError or UnKnownError please check timber"))
40+
}
1641
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.teamsparker.android.data.remote.service
2+
3+
import com.teamsparker.android.data.remote.calladapter.NetworkState
4+
import com.teamsparker.android.data.remote.entity.response.BaseResponse
5+
import com.teamsparker.android.data.remote.entity.response.HabitRoomTimeLine
6+
import retrofit2.http.GET
7+
import retrofit2.http.Path
8+
9+
interface HabitRoomTimeLineService {
10+
@GET("room/{roomId}/timeline")
11+
suspend fun getHabitRoomRimeLine(
12+
@Path("roomId") roomId: Int
13+
): NetworkState<BaseResponse<HabitRoomTimeLine>>
14+
}

app/src/main/java/com/teamsparker/android/di/RemoteDataSourceModule.kt

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.teamsparker.android.di
22

33
import com.teamsparker.android.data.remote.datasource.*
44
import com.teamsparker.android.data.remote.service.*
5+
import dagger.Binds
56
import dagger.Module
67
import dagger.Provides
78
import dagger.hilt.InstallIn
@@ -57,4 +58,11 @@ object RemoteDataSourceModule {
5758
alarmCenterService: AlarmCenterService
5859
): AlarmCenterDataSource =
5960
AlarmCenterDataSourceImpl(alarmCenterService)
61+
62+
@Provides
63+
@Singleton
64+
fun provideHabitRoomTimeLineDataSource(
65+
habitRoomTimeLineService: HabitRoomTimeLineService
66+
): HabitRoomTimeLineDataSource =
67+
HabitRoomTImeLineDataSourceImpl(habitRoomTimeLineService)
6068
}

0 commit comments

Comments
 (0)