Skip to content

Commit c450522

Browse files
authored
Merge pull request #166 from boostcampwm-2024/refactor/#165-improve-fetch-picks-in-bound
[refactor] 지도 화면 영역의 픽 목록을 가져오는 시점 변경
2 parents a73e936 + 8e2caea commit c450522

File tree

2 files changed

+61
-38
lines changed

2 files changed

+61
-38
lines changed

app/src/main/java/com/squirtles/musicroad/map/MapViewModel.kt

+32-25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.squirtles.musicroad.map
22

33
import android.content.Context
44
import android.location.Location
5+
import android.util.Log
56
import androidx.lifecycle.ViewModel
67
import androidx.lifecycle.viewModelScope
78
import com.naver.maps.geometry.LatLng
@@ -35,6 +36,9 @@ class MapViewModel @Inject constructor(
3536
private val getCurrentUserUseCase: GetCurrentUserUseCase
3637
) : ViewModel() {
3738

39+
private val _centerLatLng: MutableStateFlow<LatLng?> = MutableStateFlow(null)
40+
val centerLatLng = _centerLatLng.asStateFlow()
41+
3842
private var _lastCameraPosition: CameraPosition? = null
3943
val lastCameraPosition get() = _lastCameraPosition
4044

@@ -97,6 +101,11 @@ class MapViewModel @Inject constructor(
97101
} ?: -1.0
98102
}
99103

104+
fun updateCenterLatLng(latLng: LatLng) {
105+
_centerLatLng.value = latLng
106+
}
107+
108+
// FIXME: 인자로 Context 받는 것 수정하기
100109
fun setClickedMarker(context: Context, marker: Marker) {
101110
viewModelScope.launch {
102111
marker.toggleSizeByClick(context, true)
@@ -129,34 +138,32 @@ class MapViewModel @Inject constructor(
129138
}
130139
}
131140

132-
fun fetchPicksInBounds(leftTop: LatLng, rightBottom: LatLng, clusterer: Clusterer<MarkerKey>?) {
141+
fun fetchPicksInBounds(leftTop: LatLng, clusterer: Clusterer<MarkerKey>?) {
133142
viewModelScope.launch {
134-
val center = LatLng(
135-
(leftTop.latitude + rightBottom.latitude) / 2,
136-
(leftTop.longitude + rightBottom.longitude) / 2
137-
)
138-
val radiusInM = leftTop.distanceTo(rightBottom)
139-
val fetchPicks = fetchPickInAreaUseCase(center.latitude, center.longitude, radiusInM)
140-
141-
fetchPicks.onSuccess { pickList ->
142-
val newKeyTagMap: MutableMap<MarkerKey, String> = mutableMapOf()
143-
pickList.forEach { pick ->
144-
newKeyTagMap[MarkerKey(pick)] = pick.id
145-
_picks[pick.id] = pick
146-
}
147-
_clickedMarkerState.value.clusterPickList?.let { clusterPickList -> // 클러스터 마커가 선택되어 있는 경우
148-
val updatedPickList = mutableListOf<Pick>()
149-
clusterPickList.forEach { pick ->
150-
_picks[pick.id]?.let { updatedPick ->
151-
updatedPickList.add(updatedPick)
143+
_centerLatLng.value?.run {
144+
val radiusInM = leftTop.distanceTo(this)
145+
fetchPickInAreaUseCase(this.latitude, this.longitude, radiusInM)
146+
.onSuccess { pickList ->
147+
val newKeyTagMap: MutableMap<MarkerKey, String> = mutableMapOf()
148+
pickList.forEach { pick ->
149+
newKeyTagMap[MarkerKey(pick)] = pick.id
150+
_picks[pick.id] = pick
152151
}
152+
_clickedMarkerState.value.clusterPickList?.let { clusterPickList -> // 클러스터 마커가 선택되어 있는 경우
153+
val updatedPickList = mutableListOf<Pick>()
154+
clusterPickList.forEach { pick ->
155+
_picks[pick.id]?.let { updatedPick ->
156+
updatedPickList.add(updatedPick)
157+
}
158+
}
159+
_clickedMarkerState.emit(_clickedMarkerState.value.copy(clusterPickList = updatedPickList.toList())) // 최신 픽 정보로 clusterPickList 업데이트
160+
}
161+
clusterer?.addAll(newKeyTagMap)
162+
}
163+
.onFailure {
164+
// TODO: NoSuchPickInRadiusException일 때
165+
Log.e("MapViewModel", "${it.message}")
153166
}
154-
_clickedMarkerState.emit(_clickedMarkerState.value.copy(clusterPickList = updatedPickList.toList())) // 최신 픽 정보로 clusterPickList 업데이트
155-
}
156-
clusterer?.addAll(newKeyTagMap)
157-
}
158-
fetchPicks.onFailure {
159-
// TODO: NoSuchPickInRadiusException일 때
160167
}
161168
}
162169
}

app/src/main/java/com/squirtles/musicroad/map/NaverMap.kt

+29-13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import androidx.core.content.PermissionChecker
2424
import androidx.lifecycle.Lifecycle
2525
import androidx.lifecycle.LifecycleEventObserver
2626
import androidx.lifecycle.compose.LocalLifecycleOwner
27+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2728
import com.google.android.gms.location.FusedLocationProviderClient
2829
import com.google.android.gms.location.LocationServices
2930
import com.naver.maps.geometry.LatLng
@@ -68,13 +69,24 @@ fun NaverMap(
6869
val lifecycleOwner = LocalLifecycleOwner.current
6970
val coroutineScope = rememberCoroutineScope()
7071

72+
val centerLatLng by mapViewModel.centerLatLng.collectAsStateWithLifecycle()
73+
7174
LaunchedEffect(lastLocation) {
7275
// 현재 위치와 마지막 위치가 5미터 이상 차이가 날때만 현위치 기준 반경 100m 픽 정보 개수 불러오기
7376
lastLocation?.let {
7477
mapViewModel.requestPickNotificationArea(lastLocation, CIRCLE_RADIUS_METER)
7578
}
7679
}
7780

81+
LaunchedEffect(centerLatLng) {
82+
naverMap.value?.projection?.fromScreenLocation(PointF(0F, 0F))?.run {
83+
mapViewModel.fetchPicksInBounds(
84+
leftTop = this,
85+
clusterer = clusterer
86+
)
87+
}
88+
}
89+
7890
DisposableEffect(Unit) {
7991
clusterer = buildClusterer(context, mapViewModel)
8092

@@ -121,16 +133,21 @@ fun NaverMap(
121133
mapType = NaverMap.MapType.Navi
122134
initMapSettings()
123135
initDeviceLocation(
124-
context,
125-
circleOverlay,
126-
fusedLocationClient,
127-
mapViewModel.lastCameraPosition
128-
)
136+
context = context,
137+
circleOverlay = circleOverlay,
138+
fusedLocationClient = fusedLocationClient,
139+
lastCameraPosition = mapViewModel.lastCameraPosition
140+
) {
141+
mapViewModel.fetchPicksInBounds(
142+
leftTop = this.projection.fromScreenLocation(PointF(0F, 0F)),
143+
clusterer = clusterer
144+
)
145+
}
129146
initLocationOverlay(locationSource, locationOverlay)
130147
setLocationChangeListener(circleOverlay, mapViewModel)
131148
setMapClickListener { mapViewModel.resetClickedMarkerState(context) }
132-
setCameraIdleListener { leftTop, rightBottom ->
133-
mapViewModel.fetchPicksInBounds(leftTop, rightBottom, clusterer)
149+
setCameraIdleListener { centerLatLng ->
150+
mapViewModel.updateCenterLatLng(centerLatLng)
134151
}
135152
clusterer?.map = this
136153
}
@@ -172,7 +189,8 @@ private fun NaverMap.initDeviceLocation(
172189
context: Context,
173190
circleOverlay: CircleOverlay,
174191
fusedLocationClient: FusedLocationProviderClient,
175-
lastCameraPosition: CameraPosition?
192+
lastCameraPosition: CameraPosition?,
193+
fetchPicksInBounds: () -> Unit,
176194
) {
177195
if (checkSelfPermission(context)) {
178196
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
@@ -181,6 +199,7 @@ private fun NaverMap.initDeviceLocation(
181199
setCircleOverlay(circleOverlay, location)
182200
lastCameraPosition?.let {
183201
moveCamera(CameraUpdate.toCameraPosition(it))
202+
fetchPicksInBounds()
184203
} ?: run {
185204
moveCamera(CameraUpdate.scrollTo(LatLng(location)))
186205
moveCamera(CameraUpdate.zoomTo(INITIAL_CAMERA_ZOOM))
@@ -237,13 +256,10 @@ private fun NaverMap.setMapClickListener(
237256

238257
// 카메라 대기 이벤트 설정
239258
private fun NaverMap.setCameraIdleListener(
240-
fetchPicksInBounds: (LatLng, LatLng) -> Unit
259+
updateCenterLatLng: (LatLng) -> Unit
241260
) {
242261
addOnCameraIdleListener {
243-
val leftTop = projection.fromScreenLocation(PointF(0f, 0f))
244-
val rightBottom =
245-
projection.fromScreenLocation(PointF(contentWidth.toFloat(), contentHeight.toFloat()))
246-
fetchPicksInBounds(leftTop, rightBottom)
262+
updateCenterLatLng(cameraPosition.target)
247263
}
248264
}
249265

0 commit comments

Comments
 (0)