Skip to content

Commit

Permalink
feat: 상품 URL 이미지 추출 API 연결 (#180)
Browse files Browse the repository at this point in the history
* refactor: 사용하지 않는 파일 제거

* refactor: 가시성 변경

* feat: api service 구현

* feat: datasource 구현

* refactor: repository 네이밍 수정 (offeringsRepository -> offeringRepository)

* feat: 사진 업로드 관련 리소스 파일 추가

* feat: repository 및 model 구현

* feat: 이미지 링크를 통한 크롤링 이미지 불러오는 api 연결 및 이미지 삭제 로직 구현

* style: ktlint 적용

* refactor: 이미지 prefix 추가 및 에러 메시지 수정

* refactor: build 오류 수정

* fix: git conflict 해결
  • Loading branch information
chaehyuns authored Aug 6, 2024
1 parent dcf87c1 commit 85ffd4c
Show file tree
Hide file tree
Showing 22 changed files with 235 additions and 68 deletions.
8 changes: 4 additions & 4 deletions android/app/src/main/java/com/zzang/chongdae/ChongdaeApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import com.zzang.chongdae.data.remote.source.OfferingRemoteDataSourceImpl
import com.zzang.chongdae.data.repository.CommentDetailRepositoryImpl
import com.zzang.chongdae.data.repository.CommentRoomsRepositoryImpl
import com.zzang.chongdae.data.repository.OfferingDetailRepositoryImpl
import com.zzang.chongdae.data.repository.OfferingsRepositoryImpl
import com.zzang.chongdae.data.repository.OfferingRepositoryImpl
import com.zzang.chongdae.domain.repository.CommentDetailRepository
import com.zzang.chongdae.domain.repository.CommentRoomsRepository
import com.zzang.chongdae.domain.repository.OfferingDetailRepository
import com.zzang.chongdae.domain.repository.OfferingsRepository
import com.zzang.chongdae.domain.repository.OfferingRepository

class ChongdaeApp : Application() {
private val appDatabase: AppDatabase by lazy { AppDatabase.getInstance(this) }
Expand All @@ -25,8 +25,8 @@ class ChongdaeApp : Application() {
private val offeringDao by lazy { appDatabase.offeringDao() }
private val commentDao by lazy { appDatabase.commentDao() }

val offeringRepository: OfferingsRepository by lazy {
OfferingsRepositoryImpl(
val offeringRepository: OfferingRepository by lazy {
OfferingRepositoryImpl(
offeringLocalDataSource = OfferingLocalDataSourceImpl(offeringDao),
offeringRemoteDataSource = OfferingRemoteDataSourceImpl(networkManager.offeringService()),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.zzang.chongdae.data.mapper

import com.zzang.chongdae.data.remote.dto.request.ProductUrlRequest
import com.zzang.chongdae.data.remote.dto.response.ProductUrlResponse
import com.zzang.chongdae.domain.model.ProductUrl

fun ProductUrlResponse.toDomain(): ProductUrl {
return ProductUrl(
imageUrl = this.imageUrl,
)
}

fun String.toProductUrlRequest(): ProductUrlRequest {
return ProductUrlRequest(
productUrl = this,
)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.zzang.chongdae.data.remote.api

import com.zzang.chongdae.data.remote.dto.request.OfferingWriteRequest
import com.zzang.chongdae.data.remote.dto.request.ProductUrlRequest
import com.zzang.chongdae.data.remote.dto.response.MeetingsResponse
import com.zzang.chongdae.data.remote.dto.response.OfferingDetailResponse
import com.zzang.chongdae.data.remote.dto.response.OfferingsResponse
import com.zzang.chongdae.data.remote.dto.response.ProductUrlResponse
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
Expand Down Expand Up @@ -33,4 +35,9 @@ interface OfferingApiService {
suspend fun postOfferingWrite(
@Body offeringWriteRequest: OfferingWriteRequest,
): Response<Unit>

@POST("/offerings/product-images/og")
suspend fun postProductImageOg(
@Body productUrl: ProductUrlRequest,
): Response<ProductUrlResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.zzang.chongdae.data.remote.dto.request

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ProductUrlRequest(
@SerialName("productUrl") val productUrl: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.zzang.chongdae.data.remote.dto.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ProductUrlResponse(
@SerialName("imageUrl")
val imageUrl: String,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.zzang.chongdae.data.remote.source

import com.zzang.chongdae.data.mapper.toProductUrlRequest
import com.zzang.chongdae.data.remote.api.OfferingApiService
import com.zzang.chongdae.data.remote.dto.request.OfferingWriteRequest
import com.zzang.chongdae.data.remote.dto.response.OfferingsResponse
import com.zzang.chongdae.data.remote.dto.response.ProductUrlResponse
import com.zzang.chongdae.data.source.offering.OfferingRemoteDataSource
import retrofit2.Response

class OfferingRemoteDataSourceImpl(
private val service: OfferingApiService,
Expand All @@ -26,4 +29,15 @@ class OfferingRemoteDataSourceImpl(
}
}
}

override suspend fun saveProductImageOg(productUrl: String): Result<ProductUrlResponse> {
return runCatching {
val response: Response<ProductUrlResponse> = service.postProductImageOg(productUrl.toProductUrlRequest())
if (response.isSuccessful) {
response.body() ?: error("에러 발생: null")
} else {
error("에러 발생: ${response.code()}")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import com.zzang.chongdae.data.remote.dto.request.OfferingWriteRequest
import com.zzang.chongdae.data.source.offering.OfferingLocalDataSource
import com.zzang.chongdae.data.source.offering.OfferingRemoteDataSource
import com.zzang.chongdae.domain.model.Offering
import com.zzang.chongdae.domain.repository.OfferingsRepository
import com.zzang.chongdae.domain.model.ProductUrl
import com.zzang.chongdae.domain.repository.OfferingRepository
import com.zzang.chongdae.presentation.view.write.OfferingWriteUiModel

class OfferingsRepositoryImpl(
class OfferingRepositoryImpl(
private val offeringLocalDataSource: OfferingLocalDataSource,
private val offeringRemoteDataSource: OfferingRemoteDataSource,
) : OfferingsRepository {
) : OfferingRepository {
override suspend fun fetchOfferings(
lastOfferingId: Long,
pageSize: Int,
Expand Down Expand Up @@ -40,4 +41,10 @@ class OfferingsRepositoryImpl(
),
)
}

override suspend fun saveProductImageOg(productUrl: String): Result<ProductUrl> {
return offeringRemoteDataSource.saveProductImageOg(productUrl).mapCatching {
it.toDomain()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.zzang.chongdae.data.source.offering

import com.zzang.chongdae.data.remote.dto.request.OfferingWriteRequest
import com.zzang.chongdae.data.remote.dto.response.OfferingsResponse
import com.zzang.chongdae.data.remote.dto.response.ProductUrlResponse

interface OfferingRemoteDataSource {
suspend fun fetchOfferings(
Expand All @@ -10,4 +11,6 @@ interface OfferingRemoteDataSource {
): Result<OfferingsResponse>

suspend fun saveOffering(offeringWriteRequest: OfferingWriteRequest): Result<Unit>

suspend fun saveProductImageOg(productUrl: String): Result<ProductUrlResponse>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ data class Price(val amount: Int) {
}

companion object {
const val ERROR_INTEGER_FORMAT = -1
private const val ERROR_INTEGER_FORMAT = -1

fun fromString(value: String?): Price {
val intValue = value?.toIntOrNull() ?: ERROR_INTEGER_FORMAT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.zzang.chongdae.domain.model

data class ProductUrl(
val imageUrl: String,
)
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.zzang.chongdae.domain.repository

import com.zzang.chongdae.domain.model.Offering
import com.zzang.chongdae.domain.model.ProductUrl
import com.zzang.chongdae.presentation.view.write.OfferingWriteUiModel

interface OfferingsRepository {
interface OfferingRepository {
suspend fun fetchOfferings(
lastOfferingId: Long,
pageSize: Int,
): List<Offering>

suspend fun saveOffering(uiModel: OfferingWriteUiModel): Result<Unit>

suspend fun saveProductImageOg(productUrl: String): Result<ProductUrl>
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fun TextView.setHyperlink(url: String?) {

@BindingAdapter("detailProductImageUrl")
fun ImageView.setImageResource(imageUrl: String?) {
imageUrl.let {
imageUrl?.let {
Glide.with(context)
.load(it)
.error(R.drawable.img_detail_product_default)
Expand All @@ -41,6 +41,15 @@ fun ImageView.setImageResource(imageUrl: String?) {
}
}

@BindingAdapter("importProductImageUrl")
fun ImageView.importProductImageUrl(imageUrl: String?) {
Glide.with(context)
.load(imageUrl)
.placeholder(R.drawable.btn_upload_photo)
.error(R.drawable.btn_upload_photo)
.into(this)
}

@BindingAdapter("offeringsProductImageUrl")
fun ImageView.setOfferingsProductImageResource(imageUrl: String?) {
imageUrl.let {
Expand Down Expand Up @@ -85,7 +94,7 @@ private fun OfferingCondition.toOfferingComment(
)
}

@BindingAdapter("conditionText:offeringCondition") // 추후 condition추가(마감임박)에 따른 API변경있으면 수정 예정
@BindingAdapter("offeringCondition") // 추후 condition추가(마감임박)에 따른 API변경있으면 수정 예정
fun TextView.bindConditionText(offeringCondition: OfferingCondition?) {
offeringCondition?.toStyle()?.let {
this.setTextAppearance(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import androidx.paging.cachedIn
import androidx.paging.liveData
import com.zzang.chongdae.domain.model.Offering
import com.zzang.chongdae.domain.paging.OfferingPagingSource
import com.zzang.chongdae.domain.repository.OfferingsRepository
import com.zzang.chongdae.domain.repository.OfferingRepository

class OfferingViewModel(
private val offeringsRepository: OfferingsRepository,
private val offeringRepository: OfferingRepository,
) : ViewModel() {
lateinit var offerings: LiveData<PagingData<Offering>>
private set
Expand All @@ -28,15 +28,15 @@ class OfferingViewModel(
offerings =
Pager(
config = PagingConfig(pageSize = PAGE_SIZE, enablePlaceholders = false),
pagingSourceFactory = { OfferingPagingSource(fetchOfferings = offeringsRepository::fetchOfferings) },
pagingSourceFactory = { OfferingPagingSource(fetchOfferings = offeringRepository::fetchOfferings) },
).liveData.cachedIn(viewModelScope)
}

companion object {
private const val PAGE_SIZE = 10

@Suppress("UNCHECKED_CAST")
fun getFactory(offeringRepository: OfferingsRepository) =
fun getFactory(offeringRepository: OfferingRepository) =
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(
modelClass: Class<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class OfferingWriteFragment : Fragment(), OnOfferingWriteClickListener {

private val viewModel: OfferingWriteViewModel by viewModels {
OfferingWriteViewModel.getFactory(
offeringsRepository = (requireActivity().application as ChongdaeApp).offeringRepository,
offeringRepository = (requireActivity().application as ChongdaeApp).offeringRepository,
)
}

Expand Down Expand Up @@ -162,6 +162,9 @@ class OfferingWriteFragment : Fragment(), OnOfferingWriteClickListener {
viewModel.invalidEachPriceEvent.observe(viewLifecycleOwner) {
showToast(R.string.write_invalid_each_price)
}
viewModel.errorEvent.observe(viewLifecycleOwner) {
showToast(it)
}
}

private fun observeFinishEvent() {
Expand Down

This file was deleted.

Loading

0 comments on commit 85ffd4c

Please sign in to comment.