Skip to content

Commit 098aa93

Browse files
committed
[NDGL-49] feature: TravelMap 컴포넌트 추가 및 Google Map 관련 의존성 추가
1 parent ead7f08 commit 098aa93

5 files changed

Lines changed: 193 additions & 0 deletions

File tree

app/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import java.util.Properties
2+
13
plugins {
24
id("ndgl.application")
35
alias(libs.plugins.google.services)
@@ -7,6 +9,14 @@ plugins {
79
android {
810
namespace = Configuration.APPLICATION_ID
911

12+
defaultConfig {
13+
val localProperties = Properties().apply {
14+
load(rootProject.file("local.properties").bufferedReader())
15+
}
16+
17+
manifestPlaceholders["MAPS_API_KEY"] = localProperties.getProperty("MAPS_API_KEY", "")
18+
}
19+
1020
buildFeatures {
1121
buildConfig = true
1222
}

app/src/main/AndroidManifest.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
android:roundIcon="@mipmap/ic_launcher_round"
1313
android:supportsRtl="true"
1414
android:theme="@style/Theme.NDGL">
15+
16+
<meta-data
17+
android:name="com.google.android.geo.API_KEY"
18+
android:value="${MAPS_API_KEY}" />
19+
1520
<activity
1621
android:name=".MainActivity"
1722
android:exported="true"

feature/travel/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ android {
88

99
dependencies {
1010
implementation(project(":data:travel"))
11+
implementation(libs.maps.compose)
12+
implementation(libs.play.services.maps)
13+
implementation(libs.coil.compose)
1114
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package com.yapp.ndgl.feature.travel.followtravel.component
2+
3+
import android.view.MotionEvent
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.height
8+
import androidx.compose.foundation.layout.size
9+
import androidx.compose.foundation.shape.CircleShape
10+
import androidx.compose.foundation.shape.RoundedCornerShape
11+
import androidx.compose.material3.Text
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.LaunchedEffect
14+
import androidx.compose.runtime.remember
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.draw.clip
18+
import androidx.compose.ui.geometry.Offset
19+
import androidx.compose.ui.graphics.Color
20+
import androidx.compose.ui.input.pointer.motionEventSpy
21+
import androidx.compose.ui.unit.dp
22+
import com.google.android.gms.maps.CameraUpdateFactory
23+
import com.google.android.gms.maps.model.CameraPosition
24+
import com.google.android.gms.maps.model.Dash
25+
import com.google.android.gms.maps.model.Gap
26+
import com.google.android.gms.maps.model.LatLng
27+
import com.google.android.gms.maps.model.LatLngBounds
28+
import com.google.android.gms.maps.model.RoundCap
29+
import com.google.maps.android.compose.GoogleMap
30+
import com.google.maps.android.compose.MapUiSettings
31+
import com.google.maps.android.compose.MarkerComposable
32+
import com.google.maps.android.compose.MarkerState
33+
import com.google.maps.android.compose.Polyline
34+
import com.google.maps.android.compose.rememberCameraPositionState
35+
import com.yapp.ndgl.core.ui.theme.NDGLTheme
36+
import com.yapp.ndgl.core.ui.util.dropShadow
37+
import com.yapp.ndgl.feature.travel.followtravel.PlaceType
38+
import com.yapp.ndgl.feature.travel.followtravel.TravelPlace
39+
40+
@Composable
41+
internal fun TravelMap(
42+
places: List<TravelPlace>,
43+
onScrollEnabledChange: (Boolean) -> Unit,
44+
) {
45+
val routePoints = remember(places) {
46+
places.map { place ->
47+
LatLng(place.latitude, place.longitude)
48+
}
49+
}
50+
51+
val dashedPattern = remember {
52+
listOf(
53+
Dash(20f),
54+
Gap(30f),
55+
)
56+
}
57+
58+
val initialPosition = CameraPosition.fromLatLngZoom(
59+
LatLng(places[0].latitude, places[0].longitude),
60+
6f,
61+
)
62+
63+
val cameraPositionState = rememberCameraPositionState {
64+
position = initialPosition
65+
}
66+
67+
LaunchedEffect(places) {
68+
if (places.size > 1) {
69+
val boundsBuilder = LatLngBounds.Builder()
70+
places.forEach { place ->
71+
boundsBuilder.include(LatLng(place.latitude, place.longitude))
72+
}
73+
val bounds = boundsBuilder.build()
74+
val padding = 100
75+
cameraPositionState.animate(CameraUpdateFactory.newLatLngBounds(bounds, padding))
76+
}
77+
}
78+
79+
Box(
80+
modifier = Modifier
81+
.fillMaxWidth()
82+
.height(150.dp),
83+
) {
84+
GoogleMap(
85+
modifier = Modifier
86+
.fillMaxWidth()
87+
.height(150.dp)
88+
.clip(RoundedCornerShape(12.dp))
89+
.motionEventSpy {
90+
when (it.action) {
91+
MotionEvent.ACTION_DOWN -> onScrollEnabledChange(false)
92+
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> onScrollEnabledChange(true)
93+
}
94+
},
95+
cameraPositionState = cameraPositionState,
96+
uiSettings = MapUiSettings(
97+
mapToolbarEnabled = false,
98+
zoomControlsEnabled = false,
99+
scrollGesturesEnabled = true,
100+
zoomGesturesEnabled = true,
101+
tiltGesturesEnabled = false,
102+
rotationGesturesEnabled = false,
103+
scrollGesturesEnabledDuringRotateOrZoom = false,
104+
compassEnabled = false,
105+
myLocationButtonEnabled = false,
106+
),
107+
) {
108+
Polyline(
109+
points = routePoints,
110+
color = NDGLTheme.colors.black400,
111+
width = 10f,
112+
pattern = dashedPattern,
113+
startCap = RoundCap(),
114+
endCap = RoundCap(),
115+
)
116+
117+
places.forEach { place ->
118+
PlaceMarker(place = place)
119+
}
120+
}
121+
}
122+
}
123+
124+
@Composable
125+
private fun PlaceMarker(
126+
place: TravelPlace,
127+
) {
128+
val markerColor = when (place.placeType) {
129+
PlaceType.ACCOMMODATION -> NDGLTheme.colors.etcPurple
130+
PlaceType.RESTAURANT -> NDGLTheme.colors.etcOrange
131+
PlaceType.ATTRACTION -> NDGLTheme.colors.etcGreen
132+
PlaceType.CAFE -> NDGLTheme.colors.etcOrange
133+
PlaceType.TRANSPORT -> NDGLTheme.colors.etcGray
134+
}
135+
136+
val markerState = remember { MarkerState(position = LatLng(place.latitude, place.longitude)) }
137+
138+
MarkerComposable(
139+
state = markerState,
140+
anchor = Offset(0.5f, 0.5f),
141+
) {
142+
Box(
143+
modifier = Modifier
144+
.size(24.dp)
145+
.dropShadow(
146+
shape = CircleShape,
147+
color = Color.Black.copy(alpha = 0.3f),
148+
offsetY = 1.dp,
149+
blur = 2.dp,
150+
)
151+
.background(color = markerColor, shape = CircleShape),
152+
contentAlignment = Alignment.Center,
153+
) {
154+
Text(
155+
place.sequence.toString(),
156+
color = NDGLTheme.colors.white,
157+
style = NDGLTheme.typography.bodyMdSemiBold,
158+
)
159+
}
160+
}
161+
}

gradle/libs.versions.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ firebaseBom = "34.5.0"
4242
googleServices = "4.4.4"
4343
firebaseCrashlytics = "3.0.6"
4444

45+
# Google Maps
46+
mapsCompose = "6.4.1"
47+
playServicesMaps = "19.1.0"
48+
49+
# Coil
50+
coil = "2.7.0"
51+
4552
# Other
4653
timber = "5.0.1"
4754
desugarJdkLibs = "2.1.5"
@@ -111,6 +118,13 @@ firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics
111118
firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" }
112119
firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" }
113120

121+
# Google Maps
122+
maps-compose = { group = "com.google.maps.android", name = "maps-compose", version.ref = "mapsCompose" }
123+
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
124+
125+
# Coil
126+
coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" }
127+
114128
# Other
115129
timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" }
116130
android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugarJdkLibs" }

0 commit comments

Comments
 (0)