Skip to content

Commit

Permalink
Merge pull request #44 from Team-BuddyCon/feat/available-gifticon
Browse files Browse the repository at this point in the history
네트워크 통신 플로우 세팅 & 사용 가능 기프티콘 조회 api test
  • Loading branch information
hanchang97 authored Jan 24, 2024
2 parents 5244c00 + f95e9f6 commit d3fc91e
Show file tree
Hide file tree
Showing 19 changed files with 325 additions and 2 deletions.
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.BuddyCon"
tools:targetApi="31">
tools:targetApi="31"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
Expand Down
19 changes: 19 additions & 0 deletions data/src/main/java/com/yapp/buddycon/data/api/GiftiConService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.yapp.buddycon.data.api

import com.yapp.buddycon.data.model.response.AvailableGifticonResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

interface GiftiConService {
@GET("api/v1/gifticons/available")
suspend fun requestGiftiConDetail(
@Header("Authorization") token: String = "Bearer " +
"eyJhbGciOiJIUzUxMiJ9.eyJpZCI6MiwiaWF0IjoxNzAyNzg5NDc2LCJleHAiOjE3MDg4Mzc0NzZ9." +
"8YPrIlLexzGiqHwE1T_n2E-hCYbsNqJA5kUPWwgD0H8GmrGGsMgexme4NnNzBgsiHWG2uGtDLZL9fDCdiyZNUw",
@Query("pageNumber") pageNumber: Int, // page
@Query("gifticonStoreCategory") gifticonStoreCategory: String?, // 기프티콘 가게 카테고리
@Query("rowCount") rowCount: Int = 20 // page 당 요청 데이터 개수
): Response<AvailableGifticonResponse>
}
23 changes: 23 additions & 0 deletions data/src/main/java/com/yapp/buddycon/data/di/InterceptorModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.yapp.buddycon.data.di

import com.yapp.buddycon.data.BuildConfig
import com.yapp.buddycon.data.di.qualifiers.HttpLoggingInterceptorQualifier
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.logging.HttpLoggingInterceptor
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object InterceptorModule {
@HttpLoggingInterceptorQualifier
@Provides
@Singleton
fun provideHttpLoggingInterceptor(): Interceptor =
HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}
}
54 changes: 54 additions & 0 deletions data/src/main/java/com/yapp/buddycon/data/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.yapp.buddycon.data.di

import com.yapp.buddycon.data.api.GiftiConService
import com.yapp.buddycon.data.di.qualifiers.BuddyConClient
import com.yapp.buddycon.data.di.qualifiers.BuddyConRetrofit
import com.yapp.buddycon.data.di.qualifiers.HttpLoggingInterceptorQualifier
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
private const val BASE_URL = "http://43.202.14.1:8080/"

@BuddyConClient
@Provides
@Singleton
fun provideBuddyConClient(
@HttpLoggingInterceptorQualifier httpLoggingInterceptor: Interceptor,
// @BuddyConInterceptorQualifier buddyConInterceptor: Interceptor
): OkHttpClient =
OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
// .addInterceptor(buddyConInterceptor)
.build()

@BuddyConRetrofit
@Provides
@Singleton
fun provideBuddyConRetrofit(
@BuddyConClient okHttpClient: OkHttpClient
): Retrofit =
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()

/** api service */
@Provides
@Singleton
fun provideGiftiConService(
@BuddyConRetrofit retrofit: Retrofit
): GiftiConService =
retrofit.create()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.yapp.buddycon.data.di

import com.yapp.buddycon.data.repository.AuthRepositoryImpl
import com.yapp.buddycon.data.repository.TokenRepositoryImpl
import com.yapp.buddycon.data.repository.remote.AvailableGifticonRepositoryImpl
import com.yapp.buddycon.domain.repository.AuthRepository
import com.yapp.buddycon.domain.repository.AvailableGifticonRepository
import com.yapp.buddycon.domain.repository.TokenRepository
import dagger.Binds
import dagger.Module
Expand All @@ -24,4 +26,10 @@ interface RepositoryModule {
fun bindAuthRepository(
authRepositoryImpl: AuthRepositoryImpl
): AuthRepository

@Binds
@Singleton
fun bindAvailableGifticonRepository(
availableGifticonRepositoryImpl: AvailableGifticonRepositoryImpl
): AvailableGifticonRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.yapp.buddycon.data.di.qualifiers

import javax.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class HttpLoggingInterceptorQualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BuddyConInterceptorQualifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.yapp.buddycon.data.di.qualifiers

import javax.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class LoginClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BuddyConClient
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.yapp.buddycon.data.di.qualifiers

import javax.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class LoginRetrofit

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BuddyConRetrofit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package com.yapp.buddycon.data.model.request
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.yapp.buddycon.data.model.response

import com.google.gson.annotations.SerializedName
import com.yapp.buddycon.domain.model.gifticon.AvailableGifticon

data class AvailableGifticonResponse(
@SerializedName("body")
val body: Body,
@SerializedName("message")
val message: String,
@SerializedName("status")
val status: Int
)

data class Body(
val content: List<Content>,
val empty: Boolean,
val first: Boolean,
val last: Boolean,
val number: Int,
val numberOfElements: Int,
val pageable: Pageable,
val size: Int
) {
data class Content(
val expireDate: String,
val gifticonId: Int,
val gifticonStore: String,
val gifticonStoreCategory: String,
val imageUrl: String,
val memo: String,
val name: String
) {
fun mapToAvailableGifticonInfo() = AvailableGifticon.AvailableGifticonInfo(
imageUrl = this.imageUrl,
name = this.name,
expireDate = this.expireDate
// 가게, 메뉴 카테고리 정보 mapping 추가 예정
)
}

data class Pageable(
val pageNumber: Int,
val pageSize: Int,
val paged: Boolean,
val unpaged: Boolean
)

fun mapToAvailableGifticon() = AvailableGifticon(
availableGifticons = this.content.map { it.mapToAvailableGifticonInfo() },
isFirstPage = this.first,
isLastPage = this.last,
pageNumber = this.pageable.pageNumber
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package com.yapp.buddycon.data.repository.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.yapp.buddycon.data.repository.remote

import com.yapp.buddycon.data.api.GiftiConService
import com.yapp.buddycon.domain.repository.AvailableGifticonRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class AvailableGifticonRepositoryImpl @Inject constructor(
private val gifticonService: GiftiConService
) : AvailableGifticonRepository {
override fun getAvailableGifiticon() = flow {
emit(gifticonService.requestGiftiConDetail(pageNumber = 0, gifticonStoreCategory = null))
}.catch { error ->
throw Throwable("catch error!", error)
}.map { response ->
if (response.isSuccessful) {
(response.body() ?: throw NullPointerException("null response")).body.mapToAvailableGifticon()
} else {
throw Throwable("error.. msg : ${response.message()}")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.yapp.buddycon.domain.model.gifticon

import com.yapp.buddycon.domain.model.type.GifticonCategory
import com.yapp.buddycon.domain.model.type.GifticonStoreCategory

data class AvailableGifticon(
val availableGifticons: List<AvailableGifticonInfo>,
val isFirstPage: Boolean = false,
val isLastPage: Boolean = false,
val pageNumber: Int = 0,
) {
data class AvailableGifticonInfo(
val imageUrl: String = "",
val category: GifticonCategory = GifticonCategory.ETC,
val storeCategory: GifticonStoreCategory = GifticonStoreCategory.OTHERS,
val name: String = "",
val expireDate: String = "",
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.yapp.buddycon.domain.model.type

enum class GifticonStoreCategory(val value: String) {
CAFE("CAFE"),
CONVENIENCE_STORE("CONVENIENCE_STORE"),
OTHERS("OTHERS")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.yapp.buddycon.domain.repository

import com.yapp.buddycon.domain.model.gifticon.AvailableGifticon
import kotlinx.coroutines.flow.Flow

interface AvailableGifticonRepository {
fun getAvailableGifiticon(): Flow<AvailableGifticon> // todo - parameter 추가 예정
}
5 changes: 5 additions & 0 deletions feature/gifticon/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
alias libs.plugins.android.library
alias libs.plugins.kotlin.android
alias libs.plugins.hilt.android
alias libs.plugins.kotlin.kapt
}

android {
Expand Down Expand Up @@ -39,6 +41,9 @@ dependencies {
implementation project(":core:designsystem")
implementation project(":domain")

implementation libs.hilt.android
kapt libs.hilt.compiler

implementation libs.coil.compose
implementation libs.androidx.core.ktx
implementation libs.androidx.activity.compose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.yapp.buddycon.designsystem.R
import com.yapp.buddycon.designsystem.component.appbar.TopAppBarWithNotification
import com.yapp.buddycon.designsystem.component.button.FloatingActionButton
import com.yapp.buddycon.designsystem.theme.BuddyConTheme
import com.yapp.buddycon.gifticon.available.AvailabeGifticonScreen

@Composable
fun GifticonScreeen(
Expand All @@ -35,9 +36,10 @@ fun GifticonScreeen(
}

@Composable
private fun GifticonContent(
fun GifticonContent(
modifier: Modifier = Modifier
) {
Column(modifier) {
AvailabeGifticonScreen()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.yapp.buddycon.gifticon.available

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun AvailabeGifticonScreen(
availableGifticonViewModel: AvailableGifticonViewModel = hiltViewModel()
) {
Box(
modifier = Modifier.fillMaxSize().background(Color.LightGray)
) {
Button(
modifier = Modifier.align(Alignment.Center),
onClick = {
availableGifticonViewModel.getAvailableGifiticon()
}
) {
Text("test")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.yapp.buddycon.gifticon.available

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yapp.buddycon.domain.repository.AvailableGifticonRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class AvailableGifticonViewModel @Inject constructor(
private val availableGifticonRepository: AvailableGifticonRepository
) : ViewModel() {

fun getAvailableGifiticon() {
viewModelScope.launch {
availableGifticonRepository.getAvailableGifiticon()
.onStart {
// set loading state
Log.e("BuddyConTest", "loading...")
}.catch {
// error handling
Log.e("BuddyConTest", "catch error!")
}.collectLatest { availableGifticon ->
Log.e("BuddyConTest", "collect data : $availableGifticon")
}
}
}
}

0 comments on commit d3fc91e

Please sign in to comment.