Skip to content

Commit 194f14e

Browse files
authored
[Feat/#89] 등록 뷰모델 + API 연동
1 parent ad76809 commit 194f14e

File tree

21 files changed

+1023
-157
lines changed

21 files changed

+1023
-157
lines changed

app/src/main/java/com/poti/android/data/di/NetworkModule.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,9 @@ object NetworkModule {
6969
.client(okHttpClient)
7070
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
7171
.build()
72+
73+
@S3UploadClient
74+
@Provides
75+
@Singleton
76+
fun provideOkHttpClientForS3(): OkHttpClient = OkHttpClient.Builder().build()
7277
}

app/src/main/java/com/poti/android/data/di/RepositoryModule.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import com.poti.android.data.repository.HomeRepositoryImpl
66
import com.poti.android.data.repository.ImageRepositoryImpl
77
import com.poti.android.data.repository.ParticipationRepositoryImpl
88
import com.poti.android.data.repository.PartyRepositoryImpl
9+
import com.poti.android.data.repository.S3RepositoryImpl
910
import com.poti.android.data.repository.UserRepositoryImpl
1011
import com.poti.android.domain.repository.ArtistRepository
1112
import com.poti.android.domain.repository.AuthRepository
1213
import com.poti.android.domain.repository.HomeRepository
1314
import com.poti.android.domain.repository.ImageRepository
1415
import com.poti.android.domain.repository.ParticipationRepository
1516
import com.poti.android.domain.repository.PartyRepository
17+
import com.poti.android.domain.repository.S3Repository
1618
import com.poti.android.domain.repository.UserRepository
1719
import dagger.Binds
1820
import dagger.Module
@@ -50,4 +52,8 @@ abstract class RepositoryModule {
5052
@Binds
5153
@Singleton
5254
abstract fun bindParticipationRepository(participationRepositoryImpl: ParticipationRepositoryImpl): ParticipationRepository
55+
56+
@Binds
57+
@Singleton
58+
abstract fun bindS3Repository(s3RepositoryImpl: S3RepositoryImpl): S3Repository
5359
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.poti.android.data.di
2+
3+
import javax.inject.Qualifier
4+
5+
@Qualifier
6+
@Retention(AnnotationRetention.BINARY)
7+
annotation class S3UploadClient

app/src/main/java/com/poti/android/data/remote/datasource/ImageRemoteDataSource.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class ImageRemoteDataSource @Inject constructor(
1010
) {
1111
suspend fun getPresignedUrls(
1212
type: String,
13-
count: Int,
14-
extension: String,
13+
extensions: List<String>,
1514
): BaseResponse<PresignedUrlListResponseDto> =
16-
imageService.getPresignedUrls(type, count, extension)
15+
imageService.getPresignedUrls(type, extensions)
1716
}

app/src/main/java/com/poti/android/data/remote/service/ImageService.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ interface ImageService {
99
@GET("/api/v1/images/presigned-url")
1010
suspend fun getPresignedUrls(
1111
@Query("type") type: String,
12-
@Query("count") count: Int,
13-
@Query("extension") extension: String,
12+
@Query("extensions") extensions: List<String>,
1413
): BaseResponse<PresignedUrlListResponseDto>
1514
}

app/src/main/java/com/poti/android/data/repository/ImageRepositoryImpl.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ class ImageRepositoryImpl @Inject constructor(
1414
) : ImageRepository {
1515
override suspend fun getPresignedUrls(
1616
type: String,
17-
count: Int,
18-
extension: String,
17+
extensions: List<String>,
1918
): Result<List<PresignedUploadInfo>> = httpResponseHandler.safeApiCall {
20-
imageRemoteDataSource.getPresignedUrls(type, count, extension)
19+
imageRemoteDataSource.getPresignedUrls(type, extensions)
2120
.handleApiResponse()
2221
.getOrThrow()
2322
.toDomain()
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.poti.android.data.repository
2+
3+
import com.poti.android.core.network.util.HttpResponseHandler
4+
import com.poti.android.data.di.S3UploadClient
5+
import com.poti.android.domain.model.image.PresignedUploadInfo
6+
import com.poti.android.domain.repository.S3Repository
7+
import okhttp3.MediaType.Companion.toMediaType
8+
import okhttp3.OkHttpClient
9+
import okhttp3.Request
10+
import okhttp3.RequestBody.Companion.asRequestBody
11+
import java.io.File
12+
import javax.inject.Inject
13+
14+
class S3RepositoryImpl @Inject constructor(
15+
private val httpResponseHandler: HttpResponseHandler,
16+
@param:S3UploadClient private val okHttpClient: OkHttpClient,
17+
) : S3Repository {
18+
override suspend fun uploadImages(
19+
uploadInfos: List<PresignedUploadInfo>,
20+
files: List<File>,
21+
extensions: List<String>,
22+
): Result<Unit> = httpResponseHandler.safeApiCall {
23+
uploadInfos
24+
.zip(files.zip(extensions))
25+
.forEach { (info, pair) ->
26+
val (file, extension) = pair
27+
uploadSingleImageInternal(
28+
presignedUrl = info.url,
29+
file = file,
30+
extension = extension,
31+
)
32+
}
33+
}
34+
35+
override suspend fun uploadSingleImage(
36+
presignedUrl: String,
37+
file: File,
38+
extension: String,
39+
): Result<Unit> = httpResponseHandler.safeApiCall {
40+
uploadSingleImageInternal(
41+
presignedUrl = presignedUrl,
42+
file = file,
43+
extension = extension,
44+
)
45+
}
46+
47+
private fun uploadSingleImageInternal(
48+
presignedUrl: String,
49+
file: File,
50+
extension: String,
51+
) {
52+
val contentType = extension.toContentType()
53+
val requestBody = file.asRequestBody(contentType.toMediaType())
54+
55+
val request = Request.Builder()
56+
.url(presignedUrl)
57+
.put(requestBody)
58+
.header("Content-Type", contentType)
59+
.build()
60+
61+
okHttpClient.newCall(request).execute().use { response ->
62+
if (!response.isSuccessful) {
63+
throw IllegalStateException(
64+
"S3 upload failed: ${response.code}",
65+
)
66+
}
67+
}
68+
}
69+
}
70+
71+
private fun String.toContentType(): String =
72+
when (lowercase()) {
73+
"jpg", "jpeg" -> "image/jpeg"
74+
"png" -> "image/png"
75+
"webp" -> "image/webp"
76+
else -> "application/octet-stream"
77+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
11
package com.poti.android.domain.model.image
2+
3+
import java.io.File
4+
5+
data class ImageInfoForPresigned(
6+
val file: File,
7+
val extension: String,
8+
)

app/src/main/java/com/poti/android/domain/repository/ImageRepository.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import com.poti.android.domain.model.image.PresignedUploadInfo
55
interface ImageRepository {
66
suspend fun getPresignedUrls(
77
type: String,
8-
count: Int,
9-
extension: String,
8+
extensions: List<String>,
109
): Result<List<PresignedUploadInfo>>
1110
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.poti.android.domain.repository
2+
3+
import com.poti.android.domain.model.image.PresignedUploadInfo
4+
import java.io.File
5+
6+
interface S3Repository {
7+
suspend fun uploadImages(
8+
uploadInfos: List<PresignedUploadInfo>,
9+
files: List<File>,
10+
extensions: List<String>,
11+
): Result<Unit>
12+
13+
suspend fun uploadSingleImage(
14+
presignedUrl: String,
15+
file: File,
16+
extension: String,
17+
): Result<Unit>
18+
}

0 commit comments

Comments
 (0)