Skip to content

Commit

Permalink
Merge pull request #14 from f-lab-edu/feature/13
Browse files Browse the repository at this point in the history
[#13] FestivalScreen / MoreScreen 구현
  • Loading branch information
ksw4015 authored Oct 21, 2024
2 parents 60afd7e + 1e0f5fd commit c324b71
Show file tree
Hide file tree
Showing 42 changed files with 1,385 additions and 63 deletions.
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
</activity>

<activity android:name=".presentation.main.MainActivity"/>
<activity android:name=".presentation.more.MoreActivity"/>
</application>

</manifest>
13 changes: 13 additions & 0 deletions app/src/main/java/kr/ksw/visitkorea/data/di/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import kr.ksw.visitkorea.data.local.databases.AreaCodeDatabase
import kr.ksw.visitkorea.data.remote.api.AreaCodeApi
import kr.ksw.visitkorea.data.remote.api.LocationBasedListApi
import kr.ksw.visitkorea.data.remote.api.RetrofitInterceptor
import kr.ksw.visitkorea.data.remote.api.SearchFestivalApi
import kr.ksw.visitkorea.data.repository.AreaCodeRepository
import kr.ksw.visitkorea.data.repository.AreaCodeRepositoryImpl
import kr.ksw.visitkorea.data.repository.LocationBasedListRepository
import kr.ksw.visitkorea.data.repository.LocationBasedListRepositoryImpl
import kr.ksw.visitkorea.data.repository.SearchFestivalRepository
import kr.ksw.visitkorea.data.repository.SearchFestivalRepositoryImpl
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
Expand Down Expand Up @@ -72,4 +75,14 @@ object DataModule {
fun provideLocationBasedListRepository(locationBasedListApi: LocationBasedListApi): LocationBasedListRepository {
return LocationBasedListRepositoryImpl(locationBasedListApi)
}

@Provides
@Singleton
fun provideSearchFestivalApi(retrofit: Retrofit): SearchFestivalApi = retrofit.create(SearchFestivalApi::class.java)

@Provides
@Singleton
fun provideSearchFestivalRepository(searchFestivalApi: SearchFestivalApi): SearchFestivalRepository {
return SearchFestivalRepositoryImpl(searchFestivalApi)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,21 @@ class LocationBasedPagingSource (
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, LocationBasedDTO> {
val page = params.key ?: 1
val loadSize = params.loadSize
val response = locationBasedListApi.getLocationBasedListByContentType(
numOfRows = loadSize,
pageNo = page,
mapX = mapX,
mapY = mapY,
contentTypeId = contentTypeId
)
val data = response.toItems()
val data = try {
locationBasedListApi.getLocationBasedListByContentType(
numOfRows = loadSize,
pageNo = page,
mapX = mapX,
mapY = mapY,
contentTypeId = contentTypeId
).toItems()
} catch (e: Exception) {
emptyList()
}
return LoadResult.Page(
data = data,
prevKey = if(page == 1) null else page - 1,
nextKey = if(data.size == loadSize) page + 1 else null
prevKey = if(page == 1 || data.isEmpty()) null else page - 1,
nextKey = if(data.size == loadSize && data.isNotEmpty()) page + 1 else null
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package kr.ksw.visitkorea.data.paging.source

import androidx.paging.PagingSource
import androidx.paging.PagingState
import kr.ksw.visitkorea.data.mapper.toItems
import kr.ksw.visitkorea.data.remote.api.SearchFestivalApi
import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO

class SearchFestivalPagingSource(
private val searchFestivalApi: SearchFestivalApi,
private val eventStartDate: String,
private val eventEndDate: String,
private val areaCode: String?,
private val sigunguCode: String?
) : PagingSource<Int, SearchFestivalDTO>() {

override fun getRefreshKey(state: PagingState<Int, SearchFestivalDTO>): Int? {
return state.anchorPosition?.let { anchor ->
val anchorPage = state.closestPageToPosition(anchor)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, SearchFestivalDTO> {
val page = params.key ?: 1
val loadSize = params.loadSize
val response = searchFestivalApi.searchFestival(
numOfRows = loadSize,
pageNo = page,
eventStartDate = eventStartDate,
eventEndDate = eventEndDate,
areaCode = areaCode,
sigunguCode = sigunguCode
)
val data = response.toItems()
return LoadResult.Page(
data = data,
prevKey = if(page == 1) null else page - 1,
nextKey = if(data.size == loadSize)
page + 1
else null
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package kr.ksw.visitkorea.data.remote.api

import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO
import kr.ksw.visitkorea.data.remote.model.ApiResponse
import retrofit2.http.GET
import retrofit2.http.Query

interface SearchFestivalApi {
@GET("searchFestival1")
suspend fun searchFestival(
@Query("arrange") arrange: String = "S",
@Query("numOfRows") numOfRows: Int,
@Query("pageNo") pageNo: Int,
@Query("eventStartDate") eventStartDate: String,
@Query("eventEndDate") eventEndDate: String,
@Query("areaCode") areaCode: String? = null,
@Query("sigunguCode") sigunguCode: String? = null
): ApiResponse<SearchFestivalDTO>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package kr.ksw.visitkorea.data.remote.dto

import com.google.gson.annotations.SerializedName

data class SearchFestivalDTO(
@SerializedName("addr1")
val address: String,
@SerializedName("areacode")
val areaCode: String,
@SerializedName("sigungucode")
val sigunguCode: String,
@SerializedName("contentid")
val contentId: String,
@SerializedName("contenttypeid")
val contentTypeId: String,
@SerializedName("eventstartdate")
val eventStartDate: String,
@SerializedName("eventenddate")
val eventEndDate: String,
@SerializedName("firstimage")
val firstImage: String,
@SerializedName("firstimage2")
val firstImage2: String,
@SerializedName("mapx")
val mapX: String,
@SerializedName("mapy")
val mapY: String,
val cat3: String,
val tel: String,
val title: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package kr.ksw.visitkorea.data.repository

import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO

interface SearchFestivalRepository {
suspend operator fun invoke(
numOfRows: Int,
pageNo: Int,
eventStartDate: String,
eventEndDate: String,
areaCode: String? = null,
sigunguCode: String? = null
): Result<List<SearchFestivalDTO>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package kr.ksw.visitkorea.data.repository

import kr.ksw.visitkorea.data.mapper.toItems
import kr.ksw.visitkorea.data.remote.api.SearchFestivalApi
import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO
import javax.inject.Inject

class SearchFestivalRepositoryImpl @Inject constructor(
private val searchFestivalApi: SearchFestivalApi
): SearchFestivalRepository {
override suspend fun invoke(
numOfRows: Int,
pageNo: Int,
eventStartDate: String,
eventEndDate: String,
areaCode: String?,
sigunguCode: String?
): Result<List<SearchFestivalDTO>> = runCatching {
searchFestivalApi.searchFestival(
numOfRows = numOfRows,
pageNo = pageNo,
eventStartDate = eventStartDate,
eventEndDate = eventEndDate,
areaCode = areaCode,
sigunguCode = sigunguCode
).toItems()
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/kr/ksw/visitkorea/domain/di/FestivalModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kr.ksw.visitkorea.domain.di

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import kr.ksw.visitkorea.domain.usecase.festival.GetFestivalListUseCase
import kr.ksw.visitkorea.domain.usecase.festival.GetFestivalListUseCaseImpl

@Module
@InstallIn(ActivityRetainedComponent::class)
abstract class FestivalModule {
@Binds
abstract fun bindGetFestivalListUseCase(getFestivalListUseCase: GetFestivalListUseCaseImpl): GetFestivalListUseCase
}
17 changes: 17 additions & 0 deletions app/src/main/java/kr/ksw/visitkorea/domain/di/MoreModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kr.ksw.visitkorea.domain.di

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import kr.ksw.visitkorea.domain.usecase.more.GetMoreListUseCase
import kr.ksw.visitkorea.domain.usecase.more.GetMoreListUseCaseImpl

@Module
@InstallIn(ActivityRetainedComponent::class)
abstract class MoreModule {
@Binds
abstract fun bindGetMoreListUseCase(
getMoreListUseCase: GetMoreListUseCaseImpl
): GetMoreListUseCase
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kr.ksw.visitkorea.domain.usecase.festival

import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO

interface GetFestivalListUseCase {
suspend operator fun invoke(
forceFetch: Boolean,
eventStartDate: String,
eventEndDate: String,
areaCode: String?,
sigunguCode: String?
) : Result<Flow<PagingData<SearchFestivalDTO>>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package kr.ksw.visitkorea.domain.usecase.festival

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow
import kr.ksw.visitkorea.data.paging.source.SearchFestivalPagingSource
import kr.ksw.visitkorea.data.remote.api.SearchFestivalApi
import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO
import javax.inject.Inject

class GetFestivalListUseCaseImpl @Inject constructor(
private val searchFestivalApi: SearchFestivalApi
) : GetFestivalListUseCase {
private var pagingSource: PagingSource<Int, SearchFestivalDTO>? = null

override suspend fun invoke(
forceFetch: Boolean,
eventStartDate: String,
eventEndDate: String,
areaCode: String?,
sigunguCode: String?
): Result<Flow<PagingData<SearchFestivalDTO>>> = runCatching {
if(forceFetch &&
pagingSource != null &&
pagingSource?.invalid != true) {
pagingSource?.invalidate()
}
Pager(
config = PagingConfig(
pageSize = 20,
initialLoadSize = 20
),
pagingSourceFactory = {
SearchFestivalPagingSource(
searchFestivalApi,
eventStartDate,
eventEndDate,
areaCode,
sigunguCode
).also {
pagingSource = it
}
}
).flow
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class GetHotelListUseCaseImpl @Inject constructor(
}
Pager(
config = PagingConfig(
pageSize = 10,
initialLoadSize = 10
pageSize = 30,
initialLoadSize = 30
),
pagingSourceFactory = {
LocationBasedPagingSource(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package kr.ksw.visitkorea.domain.usecase.mapper

import kr.ksw.visitkorea.data.remote.dto.LocationBasedDTO
import kr.ksw.visitkorea.data.remote.dto.SearchFestivalDTO
import kr.ksw.visitkorea.domain.usecase.model.CommonCardModel
import kr.ksw.visitkorea.domain.usecase.model.Festival
import kr.ksw.visitkorea.domain.usecase.model.MoreCardModel
import kr.ksw.visitkorea.domain.usecase.model.Restaurant
import kr.ksw.visitkorea.domain.usecase.model.TouristSpot
import kr.ksw.visitkorea.domain.usecase.util.toDateString
import kr.ksw.visitkorea.domain.usecase.util.toDistForUi
import kr.ksw.visitkorea.domain.usecase.util.toImageUrl

Expand All @@ -23,6 +27,15 @@ fun LocationBasedDTO.toCommonCardModel(): CommonCardModel = CommonCardModel(
contentId
)

fun SearchFestivalDTO.toFestival(): Festival = Festival(
address,
firstImage.toImageUrl(),
title,
contentId,
eventStartDate.toDateString(),
eventEndDate.toDateString()
)

val restaurantMap = mapOf(
"A05020100" to "한식",
"A05020200" to "서양식",
Expand All @@ -39,4 +52,13 @@ fun LocationBasedDTO.toRestaurantModel(): Restaurant = Restaurant(
firstImage.toImageUrl(),
title,
restaurantMap[category] ?: ""
)

fun LocationBasedDTO.toMoreCardModel(): MoreCardModel = MoreCardModel(
address,
firstImage.toImageUrl(),
title,
dist.toDistForUi(),
contentId,
restaurantMap[category]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package kr.ksw.visitkorea.domain.usecase.model

data class Festival(
val address: String = "",
val firstImage: String = "",
val title: String = "",
val contentId: String = "",
val eventStartDate: String = "",
val eventEndDate: String = ""
)
Loading

0 comments on commit c324b71

Please sign in to comment.