Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package com.gdg.data.datasource
import com.gdg.data.dto.BaseResponse
import com.gdg.data.dto.response.AssemblyResponseDto
import com.gdg.data.dto.response.CongestionResponseDto
import com.gdg.data.dto.response.RoadResponseDto
import com.gdg.data.dto.response.WeatherResponseDto

interface CrowdZeroDataSource {
suspend fun getWeather(areaId: Int): BaseResponse<WeatherResponseDto>
suspend fun getCongestion(areaId: Int): BaseResponse<CongestionResponseDto>
suspend fun getRoad(areaId: Int): BaseResponse<List<RoadResponseDto>>
suspend fun getAssembly(date: String): BaseResponse<List<AssemblyResponseDto>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.gdg.data.datasource.CrowdZeroDataSource
import com.gdg.data.dto.BaseResponse
import com.gdg.data.dto.response.AssemblyResponseDto
import com.gdg.data.dto.response.CongestionResponseDto
import com.gdg.data.dto.response.RoadResponseDto
import com.gdg.data.dto.response.WeatherResponseDto
import com.gdg.data.service.CrowdZeroService
import javax.inject.Inject
Expand All @@ -19,6 +20,10 @@ class CrowdZeroDataSourceImpl @Inject constructor(
return crowdZeroApiService.getCongestion(areaId)
}

override suspend fun getRoad(areaId: Int): BaseResponse<List<RoadResponseDto>> {
return crowdZeroApiService.getRoad(areaId)
}

override suspend fun getAssembly(date: String): BaseResponse<List<AssemblyResponseDto>> {
return crowdZeroApiService.getAssembly(date)
}
Expand Down
16 changes: 16 additions & 0 deletions data/src/main/java/com/gdg/data/dto/response/RoadResponseDto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.gdg.data.dto.response

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

@Serializable
data class RoadResponseDto(
@SerialName("id") val id: Long,
@SerialName("acdntOccrDt") val acdntOccrDt: String,
@SerialName("expClrDt") val expClrDt: String,
@SerialName("acdntInfo") val acdntInfo: String,
@SerialName("acdntX") val acdntX: Double,
@SerialName("acdntY") val acdntY: Double,
@SerialName("acdntTime") val acdntTime: String,
@SerialName("areaId") val areaId: Int
)
14 changes: 14 additions & 0 deletions data/src/main/java/com/gdg/data/mapper/ResponseRoadDtoMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.gdg.data.mapper

import com.gdg.data.dto.response.RoadResponseDto
import com.gdg.domain.entity.RoadEntity

fun RoadResponseDto.toRoadEntity() = RoadEntity(
areaId = id.toInt(),
acdntOccrDt = acdntOccrDt,
expClrDt = expClrDt,
acdntInfo = acdntInfo,
acdntX = acdntX,
acdntY = acdntY,
acdntTime = acdntTime
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package com.gdg.data.repositoryimpl

import com.gdg.data.datasource.CrowdZeroDataSource
import com.gdg.data.mapper.toCongestionEntity
import com.gdg.data.mapper.toExampleEntity
import com.gdg.data.mapper.toScheduleEntity
import com.gdg.data.mapper.toWeatherEntity
import com.gdg.data.mapper.toRoadEntity
import com.gdg.domain.entity.CongestionEntity
import com.gdg.domain.entity.RoadEntity
import com.gdg.domain.entity.ScheduleEntity
import com.gdg.domain.entity.WeatherEntity
import com.gdg.domain.repository.CrowdZeroRepository
Expand All @@ -27,9 +30,16 @@ class CrowdZeroRepositoryImpl @Inject constructor(
}
}

override suspend fun getRoad(areaId: Int): Result<List<RoadEntity>> {
return runCatching {
crowdZeroDataSource.getRoad(areaId).data?.map { it.toRoadEntity() } ?: emptyList()
}
}

}
override suspend fun getAssembly(date: String): Result<List<ScheduleEntity>> {
return runCatching {
crowdZeroDataSource.getAssembly(date).data?.map { it.toScheduleEntity() } ?: emptyList()
}
}
}
}
7 changes: 7 additions & 0 deletions data/src/main/java/com/gdg/data/service/CrowdZeroService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package com.gdg.data.service
import com.gdg.data.dto.BaseResponse
import com.gdg.data.dto.response.AssemblyResponseDto
import com.gdg.data.dto.response.CongestionResponseDto
import com.gdg.data.dto.response.RoadResponseDto
import com.gdg.data.dto.response.WeatherResponseDto
import com.gdg.data.service.ApiKeyStorage.ACDNT
import com.gdg.data.service.ApiKeyStorage.API
import com.gdg.data.service.ApiKeyStorage.AREA_ID
import com.gdg.data.service.ApiKeyStorage.ASSEMBLY
Expand All @@ -24,6 +26,11 @@ interface CrowdZeroService {
@Path(AREA_ID) areaId: Int
): BaseResponse<CongestionResponseDto>

@GET("/$API/$ACDNT/{$AREA_ID}")
suspend fun getRoad(
@Path(AREA_ID) areaId: Int
): BaseResponse<List<RoadResponseDto>>

@GET("/$API/$ASSEMBLY/{$DATE}")
suspend fun getAssembly(
@Path(DATE) date: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.gdg.domain.repository

import com.gdg.domain.entity.CongestionEntity
import com.gdg.domain.entity.RoadEntity
import com.gdg.domain.entity.ScheduleEntity
import com.gdg.domain.entity.WeatherEntity

interface CrowdZeroRepository {
suspend fun getWeather(areaId: Int): Result<WeatherEntity>
suspend fun getCongestion(areaId: Int): Result<CongestionEntity>
suspend fun getRoad(areaId: Int): Result<List<RoadEntity>>
suspend fun getAssembly(date: String): Result<List<ScheduleEntity>>
}
51 changes: 24 additions & 27 deletions feature/src/main/java/com/gdg/feature/map/MapRoute.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ import timber.log.Timber

@Composable
fun MapRoute(
mapViewModel: MapViewModel = hiltViewModel(),
navigateToDetail: (Long) -> Unit
mapViewModel: MapViewModel = hiltViewModel(), navigateToDetail: (Long) -> Unit
) {
val mapProperties by remember {
mutableStateOf(
Expand All @@ -81,6 +80,11 @@ fun MapRoute(
}
val getCongestionState by mapViewModel.getCongestionState.collectAsStateWithLifecycle()
val context = LocalContext.current
val roads by mapViewModel.roads.collectAsStateWithLifecycle()

LaunchedEffect(Unit) {
mapViewModel.getRoads()
}

LaunchedEffect(key1 = mapViewModel.sideEffects) {
mapViewModel.sideEffects.collect { sideEffect ->
Expand All @@ -96,7 +100,7 @@ fun MapRoute(
mapUiSettings = mapUiSettings,
cameraPositionState = cameraPositionState,
locations = mapViewModel.locations,
roads = mapViewModel.mockRoadEntity,
roads = roads,
congestionState = getCongestionState,
getPlaceEntity = { id -> mapViewModel.getCongestion(id.toInt()) },
onButtonClick = mapViewModel::navigateToDetail
Expand Down Expand Up @@ -150,8 +154,7 @@ fun MapScreen(
}
if (roads.isNotEmpty()) {
roads.forEach { road ->
Marker(
width = 20.dp,
Marker(width = 20.dp,
height = 20.dp,
state = MarkerState(position = LatLng(road.acdntY, road.acdntX)),
icon = OverlayImage.fromResource(R.drawable.ic_ban_marker),
Expand All @@ -162,38 +165,32 @@ fun MapScreen(
sheetState.show()
}
true
}
)
})
}
}
}
LazyRow(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.TopCenter)
.padding(top = 110.dp, start = 10.dp, end = 10.dp),
state = listState
.padding(top = 110.dp, start = 10.dp, end = 10.dp), state = listState
) {
itemsIndexed(locations) { index, location ->
MapChip(
title = location,
isSelected = selectedLocation == location,
onClick = {
if (selectedLocation == location) {
selectedLocation = null
} else {
selectedLocation = location
getPlaceEntity(location.id)
cameraPositionState.move(
CameraUpdate.scrollAndZoomTo(location.latLng, 17.0)
.animate(CameraAnimation.Easing)
)
}
coroutineScope.launch {
listState.animateScrollToItem(index)
}
MapChip(title = location, isSelected = selectedLocation == location, onClick = {
if (selectedLocation == location) {
selectedLocation = null
} else {
selectedLocation = location
getPlaceEntity(location.id)
cameraPositionState.move(
CameraUpdate.scrollAndZoomTo(location.latLng, 17.0)
.animate(CameraAnimation.Easing)
)
}
)
coroutineScope.launch {
listState.animateScrollToItem(index)
}
})
}
}
selectedLocation?.let { location ->
Expand Down
71 changes: 30 additions & 41 deletions feature/src/main/java/com/gdg/feature/map/MapViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@ class MapViewModel @Inject constructor(
MutableStateFlow(UiState.Empty)
val getCongestionState: StateFlow<UiState<PlaceEntity>> get() = _getCongestionState

private val _getRoadState: MutableStateFlow<UiState<List<RoadEntity>>> =
MutableStateFlow(UiState.Empty)
val getRoadState: StateFlow<UiState<List<RoadEntity>>> get() = _getRoadState

private val _sideEffects: MutableSharedFlow<MapSideEffect> = MutableSharedFlow()
val sideEffects: SharedFlow<MapSideEffect> get() = _sideEffects

private val _roads = MutableStateFlow<List<RoadEntity>>(emptyList())
val roads: StateFlow<List<RoadEntity>> get() = _roads

fun getCongestion(areaId: Int) {
viewModelScope.launch {
_getCongestionState.emit(UiState.Loading)
Expand All @@ -51,6 +58,29 @@ class MapViewModel @Inject constructor(
}
}

fun getRoads() {
viewModelScope.launch {
_getRoadState.emit(UiState.Loading)
_roads.emit(emptyList())
(1..5).forEach { areaId ->
crowdZeroRepository.getRoad(areaId).fold(
onSuccess = {
_roads.emit(_roads.value + it)
},
onFailure = {
_getRoadState.emit(UiState.Failure(it.message.toString()))
}
)
}

if (_roads.value.isNotEmpty()) {
_getRoadState.emit(UiState.Success(_roads.value))
} else {
_getRoadState.emit(UiState.Failure("도로 정보를 가져오는 데 실패했습니다."))
}
}
}

@Stable
val locations = immutableListOf(
LocationType.GANGNAM_STATION,
Expand All @@ -60,51 +90,10 @@ class MapViewModel @Inject constructor(
LocationType.YEOUIDO
)

fun getPlaceEntity(id: Long): PlaceEntity? {
return mockPlaces.find { it.id == id }
}

fun navigateToDetail(id: Long) {
viewModelScope.launch {
_sideEffects.emit(MapSideEffect.NavigateToDetail(id))
}
}

private val mockPlaces = listOf(
PlaceEntity(1, "강남역", "보통", 100, 200),
PlaceEntity(2, "광화문 광장", "보통", 100, 200),
PlaceEntity(3, "삼각지역", "보통", 100, 200),
PlaceEntity(4, "서울역", "보통", 100, 200),
PlaceEntity(5, "여의도", "보통", 100, 200)
)

val mockRoadEntity = listOf(
RoadEntity(
1,
"2021-09-01 13:00",
"2021-09-01 13:00",
"사고1",
126.97719959199067,
37.57473917460146,
"2021-09-01 13:00"
),
RoadEntity(
2,
"2021-09-01 13:00",
"2021-09-01 13:00",
"사고2",
126.97724062015716,
37.57196573522649,
"2021-09-01 13:00"
),
RoadEntity(
3,
"2021-09-01 13:00",
"2021-09-01 13:00",
"사고3",
126.97681755577895,
37.56963658011575,
"2021-09-01 13:00"
)
)
}