@react-native-kakao/map 2.2.6 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +5 -38
- package/RNCKakaoMap.podspec +16 -52
- package/android/build.gradle +12 -107
- package/android/consumer-rules.pro +2 -0
- package/android/src/main/AndroidManifest.xml +3 -1
- package/android/src/main/java/net/mjstudio/rnkakao/map/CameraOptions.kt +61 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/KakaoMapModule.kt +131 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/KakaoMapView.kt +1257 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapCameraCommands.kt +306 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapDimScreen.kt +431 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapGui.kt +899 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapImageLoader.kt +232 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapLabels.kt +1572 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapOptions.kt +360 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapRoutes.kt +805 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapShapes.kt +1096 -0
- package/android/src/main/java/net/mjstudio/rnkakao/map/MapUtilities.kt +495 -0
- package/expo-module.config.json +5 -0
- package/ios/CameraOptions.swift +41 -0
- package/ios/KakaoMapModule.swift +204 -0
- package/ios/KakaoMapView.swift +1018 -0
- package/ios/MapCameraCommands.swift +451 -0
- package/ios/MapDimScreen.swift +463 -0
- package/ios/MapGui.swift +1099 -0
- package/ios/MapImageLoader.swift +177 -0
- package/ios/MapLabels.swift +1676 -0
- package/ios/MapOptions.swift +374 -0
- package/ios/MapRoutes.swift +903 -0
- package/ios/MapShapes.swift +1294 -0
- package/ios/MapUnits.swift +20 -0
- package/ios/MapUtilities.swift +365 -0
- package/lib/commonjs/index.js +180 -29
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +18 -0
- package/lib/commonjs/index.web.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types-assets.js +2 -0
- package/lib/commonjs/types-assets.js.map +1 -0
- package/lib/commonjs/types-camera.js +6 -0
- package/lib/commonjs/types-camera.js.map +1 -0
- package/lib/commonjs/types-dim.js +6 -0
- package/lib/commonjs/types-dim.js.map +1 -0
- package/lib/commonjs/types-gui.js +6 -0
- package/lib/commonjs/types-gui.js.map +1 -0
- package/lib/commonjs/types-labels.js +6 -0
- package/lib/commonjs/types-labels.js.map +1 -0
- package/lib/commonjs/types-routes.js +6 -0
- package/lib/commonjs/types-routes.js.map +1 -0
- package/lib/commonjs/types-shapes.js +6 -0
- package/lib/commonjs/types-shapes.js.map +1 -0
- package/lib/commonjs/types-utilities.js +6 -0
- package/lib/commonjs/types-utilities.js.map +1 -0
- package/lib/commonjs/types.js +6 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/index.js +180 -22
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +13 -0
- package/lib/module/index.web.js.map +1 -0
- package/lib/module/types-assets.js +2 -0
- package/lib/module/types-assets.js.map +1 -0
- package/lib/module/types-camera.js +4 -0
- package/lib/module/types-camera.js.map +1 -0
- package/lib/module/types-dim.js +4 -0
- package/lib/module/types-dim.js.map +1 -0
- package/lib/module/types-gui.js +4 -0
- package/lib/module/types-gui.js.map +1 -0
- package/lib/module/types-labels.js +4 -0
- package/lib/module/types-labels.js.map +1 -0
- package/lib/module/types-routes.js +4 -0
- package/lib/module/types-routes.js.map +1 -0
- package/lib/module/types-shapes.js +4 -0
- package/lib/module/types-shapes.js.map +1 -0
- package/lib/module/types-utilities.js +4 -0
- package/lib/module/types-utilities.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/src/index.d.ts +59 -9
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types-assets.d.ts +9 -0
- package/lib/typescript/src/types-assets.d.ts.map +1 -0
- package/lib/typescript/src/types-camera.d.ts +123 -0
- package/lib/typescript/src/types-camera.d.ts.map +1 -0
- package/lib/typescript/src/types-dim.d.ts +54 -0
- package/lib/typescript/src/types-dim.d.ts.map +1 -0
- package/lib/typescript/src/types-gui.d.ts +189 -0
- package/lib/typescript/src/types-gui.d.ts.map +1 -0
- package/lib/typescript/src/types-labels.d.ts +246 -0
- package/lib/typescript/src/types-labels.d.ts.map +1 -0
- package/lib/typescript/src/types-routes.d.ts +162 -0
- package/lib/typescript/src/types-routes.d.ts.map +1 -0
- package/lib/typescript/src/types-shapes.d.ts +253 -0
- package/lib/typescript/src/types-shapes.d.ts.map +1 -0
- package/lib/typescript/src/types-utilities.d.ts +130 -0
- package/lib/typescript/src/types-utilities.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +222 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +24 -77
- package/src/index.tsx +322 -0
- package/src/index.web.tsx +46 -0
- package/src/types-assets.ts +8 -0
- package/src/types-camera.ts +97 -0
- package/src/types-dim.ts +54 -0
- package/src/types-gui.ts +171 -0
- package/src/types-labels.ts +207 -0
- package/src/types-routes.ts +118 -0
- package/src/types-shapes.ts +244 -0
- package/src/types-utilities.ts +115 -0
- package/src/types.ts +223 -0
- package/android/gradle.properties +0 -1
- package/android/src/main/AndroidManifestNew.xml +0 -2
- package/android/src/main/java/net/mjstudio/rnkakao/map/RNCKakaoMapModule.kt +0 -25
- package/android/src/main/java/net/mjstudio/rnkakao/map/RNCKakaoMapPackage.kt +0 -35
- package/android/src/newarch/KakaoMapSpec.kt +0 -7
- package/android/src/oldarch/KakaoMapSpec.kt +0 -14
- package/ios/Component/Map/RNCKakaoMapView.h +0 -23
- package/ios/Component/Map/RNCKakaoMapView.mm +0 -209
- package/ios/Component/Map/RNCKakaoMapViewManager.mm +0 -19
- package/ios/NativeModule/RNCKakaoMap.h +0 -7
- package/ios/NativeModule/RNCKakaoMap.mm +0 -19
- package/ios/NativeModule/RNCKakaoMapManager.swift +0 -7
- package/ios/Util/Util.h +0 -97
- package/lib/commonjs/component/KakaoMapView.js +0 -54
- package/lib/commonjs/component/KakaoMapView.js.map +0 -1
- package/lib/commonjs/spec/NativeKakaoMap.js +0 -9
- package/lib/commonjs/spec/NativeKakaoMap.js.map +0 -1
- package/lib/commonjs/spec/RNCKakaoMapViewNativeComponent.js +0 -15
- package/lib/commonjs/spec/RNCKakaoMapViewNativeComponent.js.map +0 -1
- package/lib/commonjs/type/type.js +0 -2
- package/lib/commonjs/type/type.js.map +0 -1
- package/lib/commonjs/util/Const.js +0 -14
- package/lib/commonjs/util/Const.js.map +0 -1
- package/lib/commonjs/util/Util.js +0 -15
- package/lib/commonjs/util/Util.js.map +0 -1
- package/lib/module/component/KakaoMapView.js +0 -48
- package/lib/module/component/KakaoMapView.js.map +0 -1
- package/lib/module/spec/NativeKakaoMap.js +0 -3
- package/lib/module/spec/NativeKakaoMap.js.map +0 -1
- package/lib/module/spec/RNCKakaoMapViewNativeComponent.js +0 -10
- package/lib/module/spec/RNCKakaoMapViewNativeComponent.js.map +0 -1
- package/lib/module/type/type.js +0 -2
- package/lib/module/type/type.js.map +0 -1
- package/lib/module/util/Const.js +0 -8
- package/lib/module/util/Const.js.map +0 -1
- package/lib/module/util/Util.js +0 -9
- package/lib/module/util/Util.js.map +0 -1
- package/lib/typescript/src/component/KakaoMapView.d.ts +0 -25
- package/lib/typescript/src/component/KakaoMapView.d.ts.map +0 -1
- package/lib/typescript/src/spec/NativeKakaoMap.d.ts +0 -7
- package/lib/typescript/src/spec/NativeKakaoMap.d.ts.map +0 -1
- package/lib/typescript/src/spec/RNCKakaoMapViewNativeComponent.d.ts +0 -32
- package/lib/typescript/src/spec/RNCKakaoMapViewNativeComponent.d.ts.map +0 -1
- package/lib/typescript/src/type/type.d.ts +0 -8
- package/lib/typescript/src/type/type.d.ts.map +0 -1
- package/lib/typescript/src/util/Const.d.ts +0 -8
- package/lib/typescript/src/util/Const.d.ts.map +0 -1
- package/lib/typescript/src/util/Util.d.ts +0 -3
- package/lib/typescript/src/util/Util.d.ts.map +0 -1
- package/src/component/KakaoMapView.tsx +0 -82
- package/src/index.ts +0 -43
- package/src/spec/NativeKakaoMap.ts +0 -8
- package/src/spec/RNCKakaoMapViewNativeComponent.ts +0 -38
- package/src/type/type.ts +0 -7
- package/src/util/Const.ts +0 -7
- package/src/util/Util.ts +0 -11
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
package net.mjstudio.rnkakao.map
|
|
2
|
+
|
|
3
|
+
import android.os.Looper
|
|
4
|
+
import com.kakao.vectormap.GestureType
|
|
5
|
+
import com.kakao.vectormap.KakaoMap
|
|
6
|
+
import com.kakao.vectormap.LatLng
|
|
7
|
+
import com.kakao.vectormap.camera.CameraAnimation
|
|
8
|
+
import com.kakao.vectormap.camera.CameraPosition
|
|
9
|
+
import com.kakao.vectormap.camera.CameraUpdate
|
|
10
|
+
import com.kakao.vectormap.camera.CameraUpdateFactory
|
|
11
|
+
import expo.modules.kotlin.exception.CodedException
|
|
12
|
+
import kotlin.math.roundToInt
|
|
13
|
+
|
|
14
|
+
private const val CAMERA_UNSUPPORTED = "ERR_KAKAO_MAP_UNSUPPORTED_PLATFORM_FEATURE"
|
|
15
|
+
private const val CAMERA_DESTROYED = "ERR_KAKAO_MAP_VIEW_DESTROYED"
|
|
16
|
+
|
|
17
|
+
internal class MapCameraCommands(
|
|
18
|
+
map: KakaoMap,
|
|
19
|
+
private val density: Float,
|
|
20
|
+
) {
|
|
21
|
+
private var map: KakaoMap? = map
|
|
22
|
+
|
|
23
|
+
fun command(command: Map<String, Any?>): Map<String, Any?> {
|
|
24
|
+
requireMainThread()
|
|
25
|
+
val type = command.string("type")
|
|
26
|
+
return when (type) {
|
|
27
|
+
"getCapabilities" -> {
|
|
28
|
+
capabilities()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
"getState" -> {
|
|
32
|
+
throw CodedException(
|
|
33
|
+
"ERR_KAKAO_MAP_CAMERA_ASYNC_REQUIRED",
|
|
34
|
+
"Android camera state must be read through KakaoMap.getCameraPosition(listener).",
|
|
35
|
+
null,
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
"moveToHeight" -> {
|
|
40
|
+
moveToHeight(command)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
"transform" -> {
|
|
44
|
+
unsupported("Camera transforms are not exposed by Kakao Maps Android SDK 2.15.2.")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
"fit" -> {
|
|
48
|
+
fit(command)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
"canShow" -> {
|
|
52
|
+
canShow(command)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
"heightAtLevel" -> {
|
|
56
|
+
unsupported("Height conversion by zoom level is not exposed by Kakao Maps Android SDK 2.15.2.")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
"resetOrientation" -> {
|
|
60
|
+
unsupported("Orientation reset is not exposed by Kakao Maps Android SDK 2.15.2.")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
"setBackToNorthDuringAutoElevation" -> {
|
|
64
|
+
unsupported(
|
|
65
|
+
"Back-to-north during auto elevation is not exposed by Kakao Maps Android SDK 2.15.2.",
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
"setReferencePointLock" -> {
|
|
70
|
+
setReferencePointLock(command)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
else -> {
|
|
74
|
+
invalid("Unsupported advanced camera command: $type.")
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fun dispose() {
|
|
80
|
+
requireMainThread()
|
|
81
|
+
map = null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fun stateResult(position: CameraPosition): Map<String, Any?> {
|
|
85
|
+
requireMainThread()
|
|
86
|
+
requireMap()
|
|
87
|
+
return mapOf("type" to "state", "camera" to position.advancedPayload())
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private fun moveToHeight(command: Map<String, Any?>): Map<String, Any?> {
|
|
91
|
+
rejectOperationId(command)
|
|
92
|
+
val camera = command.objectValue("camera")
|
|
93
|
+
val latitude = camera.finiteNumber("latitude")
|
|
94
|
+
val longitude = camera.finiteNumber("longitude")
|
|
95
|
+
val height = camera.finiteNumber("height")
|
|
96
|
+
val tilt = camera.finiteNumber("tilt")
|
|
97
|
+
val rotation = camera.finiteNumber("rotation")
|
|
98
|
+
requireCoordinate(latitude, longitude)
|
|
99
|
+
if (height <= 0.0 || tilt !in 0.0..90.0) {
|
|
100
|
+
invalid("Camera height must be positive and tilt must be between 0 and 90 degrees.")
|
|
101
|
+
}
|
|
102
|
+
val position =
|
|
103
|
+
CameraPosition.from(
|
|
104
|
+
latitude,
|
|
105
|
+
longitude,
|
|
106
|
+
-1,
|
|
107
|
+
Math.toRadians(tilt),
|
|
108
|
+
rotation.toNativeCameraRotation(),
|
|
109
|
+
height,
|
|
110
|
+
)
|
|
111
|
+
dispatch(CameraUpdateFactory.newCameraPosition(position), command.animation())
|
|
112
|
+
return dispatched()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private fun fit(command: Map<String, Any?>): Map<String, Any?> {
|
|
116
|
+
rejectOperationId(command)
|
|
117
|
+
val points = command.coordinates("coordinates")
|
|
118
|
+
val paddingDp = command.optionalFiniteNumber("padding") ?: 0.0
|
|
119
|
+
if (paddingDp < 0.0) invalid("Camera fit padding must be non-negative.")
|
|
120
|
+
val paddingPx = checkedPixel(paddingDp)
|
|
121
|
+
val levelLimit = command.optionalInteger("levelLimit")
|
|
122
|
+
val map = requireMap()
|
|
123
|
+
if (levelLimit != null && levelLimit !in map.cameraMinLevel..map.cameraMaxLevel) {
|
|
124
|
+
invalid("Camera fit levelLimit is outside the configured camera range.")
|
|
125
|
+
}
|
|
126
|
+
val update =
|
|
127
|
+
if (levelLimit == null) {
|
|
128
|
+
CameraUpdateFactory.fitMapPoints(points, paddingPx)
|
|
129
|
+
} else {
|
|
130
|
+
CameraUpdateFactory.fitMapPoints(points, paddingPx, levelLimit)
|
|
131
|
+
}
|
|
132
|
+
dispatch(update, command.animation())
|
|
133
|
+
return dispatched()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private fun canShow(command: Map<String, Any?>): Map<String, Any?> {
|
|
137
|
+
val rotation = command.optionalFiniteNumber("rotation") ?: 0.0
|
|
138
|
+
val weight = command.optionalFiniteNumber("weight") ?: 1.0
|
|
139
|
+
if (rotation != 0.0 || weight != 1.0 || command["rect"] != null) {
|
|
140
|
+
unsupported("Android canShow supports only coordinates and zoomLevel.")
|
|
141
|
+
}
|
|
142
|
+
val map = requireMap()
|
|
143
|
+
val zoomLevel = command.integer("zoomLevel")
|
|
144
|
+
if (zoomLevel !in map.cameraMinLevel..map.cameraMaxLevel) {
|
|
145
|
+
invalid("canShow zoomLevel is outside the configured camera range.")
|
|
146
|
+
}
|
|
147
|
+
return mapOf("type" to "canShow", "value" to map.canShowMapPoints(zoomLevel, *command.coordinates("coordinates")))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private fun setReferencePointLock(command: Map<String, Any?>): Map<String, Any?> {
|
|
151
|
+
val gesture = referenceGesture(command.string("gesture"))
|
|
152
|
+
requireMap().setFixedCenter(command.boolean("locked"), gesture)
|
|
153
|
+
return mapOf("type" to "applied")
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private fun dispatch(
|
|
157
|
+
update: CameraUpdate,
|
|
158
|
+
animation: CameraAnimation?,
|
|
159
|
+
) {
|
|
160
|
+
val map = requireMap()
|
|
161
|
+
if (animation == null) map.moveCamera(update) else map.moveCamera(update, animation)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private fun Map<String, Any?>.animation(): CameraAnimation? {
|
|
165
|
+
if (!containsKey("animation")) return null
|
|
166
|
+
val raw = this["animation"]
|
|
167
|
+
val animation = raw as? Map<*, *> ?: invalid("animation must be an object.")
|
|
168
|
+
val normalized = animation.stringKeys("animation")
|
|
169
|
+
val duration = normalized.integer("duration")
|
|
170
|
+
if (duration < 0) invalid("Animation duration must be non-negative.")
|
|
171
|
+
val autoElevation = normalized.optionalBoolean("autoElevation") ?: false
|
|
172
|
+
val consecutive = normalized.optionalBoolean("consecutive") ?: false
|
|
173
|
+
if (duration == 0) return null
|
|
174
|
+
return CameraAnimation.from(
|
|
175
|
+
duration,
|
|
176
|
+
autoElevation,
|
|
177
|
+
consecutive,
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private fun capabilities() =
|
|
182
|
+
mapOf(
|
|
183
|
+
"type" to "capabilities",
|
|
184
|
+
"capabilities" to
|
|
185
|
+
mapOf(
|
|
186
|
+
"transform" to false,
|
|
187
|
+
"absoluteHeight" to true,
|
|
188
|
+
"heightAtLevel" to false,
|
|
189
|
+
"fit" to mapOf("padding" to true, "levelLimit" to true),
|
|
190
|
+
"canShow" to mapOf("basic" to true, "rotation" to false, "weight" to false, "rect" to false),
|
|
191
|
+
"resetOrientation" to false,
|
|
192
|
+
"backToNorthDuringAutoElevation" to false,
|
|
193
|
+
"animation" to mapOf("autoElevation" to true, "consecutive" to true, "operationCompletion" to false),
|
|
194
|
+
"referencePoint" to mapOf("supported" to true, "gestures" to REFERENCE_GESTURES),
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
private fun requireMap() = map ?: throw CodedException(CAMERA_DESTROYED, "The map view was destroyed.", null)
|
|
199
|
+
|
|
200
|
+
private fun rejectOperationId(command: Map<String, Any?>) {
|
|
201
|
+
if (command["operationId"] != null) {
|
|
202
|
+
unsupported("Android SDK 2.15.2 does not expose per-camera-operation completion callbacks.")
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private fun checkedPixel(value: Double): Int {
|
|
207
|
+
val pixels = value * density
|
|
208
|
+
if (!pixels.isFinite() || pixels > Int.MAX_VALUE) invalid("Camera fit padding exceeds the supported pixel range.")
|
|
209
|
+
return pixels.roundToInt()
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private val REFERENCE_GESTURES = listOf("rotate", "zoom", "tilt", "rotateZoom", "oneFingerZoom")
|
|
214
|
+
|
|
215
|
+
private fun referenceGesture(value: String) =
|
|
216
|
+
when (value) {
|
|
217
|
+
"rotate" -> GestureType.Rotate
|
|
218
|
+
"zoom" -> GestureType.Zoom
|
|
219
|
+
"tilt" -> GestureType.Tilt
|
|
220
|
+
"rotateZoom" -> GestureType.RotateZoom
|
|
221
|
+
"oneFingerZoom" -> GestureType.OneFingerZoom
|
|
222
|
+
else -> invalid("Unsupported reference-point gesture: $value.")
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private fun CameraPosition.advancedPayload() =
|
|
226
|
+
mapOf(
|
|
227
|
+
"latitude" to position.latitude,
|
|
228
|
+
"longitude" to position.longitude,
|
|
229
|
+
"zoomLevel" to zoomLevel,
|
|
230
|
+
"height" to height,
|
|
231
|
+
"tilt" to Math.toDegrees(tiltAngle),
|
|
232
|
+
"rotation" to Math.toDegrees(rotationAngle).normalizedCameraDegrees(),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
private fun dispatched() = mapOf("type" to "dispatched")
|
|
236
|
+
|
|
237
|
+
private fun Map<String, Any?>.coordinates(name: String): Array<LatLng> {
|
|
238
|
+
val values = this[name] as? List<*> ?: invalid("$name must be an array.")
|
|
239
|
+
if (values.isEmpty()) invalid("$name must contain at least one coordinate.")
|
|
240
|
+
return values
|
|
241
|
+
.mapIndexed { index, value ->
|
|
242
|
+
val coordinate =
|
|
243
|
+
(value as? Map<*, *>)?.stringKeys("$name[$index]")
|
|
244
|
+
?: invalid("$name[$index] must be an object.")
|
|
245
|
+
val latitude = coordinate.finiteNumber("latitude")
|
|
246
|
+
val longitude = coordinate.finiteNumber("longitude")
|
|
247
|
+
requireCoordinate(latitude, longitude)
|
|
248
|
+
LatLng.from(latitude, longitude)
|
|
249
|
+
}.toTypedArray()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private fun Map<String, Any?>.objectValue(name: String): Map<String, Any?> =
|
|
253
|
+
(this[name] as? Map<*, *>)?.stringKeys(name) ?: invalid("$name must be an object.")
|
|
254
|
+
|
|
255
|
+
private fun Map<*, *>.stringKeys(path: String): Map<String, Any?> =
|
|
256
|
+
entries.associate { (key, value) ->
|
|
257
|
+
val stringKey = key as? String ?: invalid("$path must use string object keys.")
|
|
258
|
+
stringKey to value
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private fun Map<String, Any?>.string(name: String) = this[name] as? String ?: invalid("$name must be a string.")
|
|
262
|
+
|
|
263
|
+
private fun Map<String, Any?>.boolean(name: String) = this[name] as? Boolean ?: invalid("$name must be a boolean.")
|
|
264
|
+
|
|
265
|
+
private fun Map<String, Any?>.optionalBoolean(name: String): Boolean? {
|
|
266
|
+
if (!containsKey(name)) return null
|
|
267
|
+
val value = this[name]
|
|
268
|
+
return value as? Boolean ?: invalid("$name must be a boolean.")
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private fun Map<String, Any?>.finiteNumber(name: String): Double = optionalFiniteNumber(name) ?: invalid("$name must be a finite number.")
|
|
272
|
+
|
|
273
|
+
private fun Map<String, Any?>.optionalFiniteNumber(name: String): Double? {
|
|
274
|
+
if (!containsKey(name)) return null
|
|
275
|
+
val value = this[name]
|
|
276
|
+
val number = (value as? Number)?.toDouble() ?: invalid("$name must be a finite number.")
|
|
277
|
+
if (!number.isFinite()) invalid("$name must be a finite number.")
|
|
278
|
+
return number
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private fun Map<String, Any?>.integer(name: String): Int = optionalInteger(name) ?: invalid("$name must be an integer.")
|
|
282
|
+
|
|
283
|
+
private fun Map<String, Any?>.optionalInteger(name: String): Int? {
|
|
284
|
+
val number = optionalFiniteNumber(name) ?: return null
|
|
285
|
+
if (number % 1.0 != 0.0 || number < Int.MIN_VALUE || number > Int.MAX_VALUE) invalid("$name must be an integer.")
|
|
286
|
+
return number.toInt()
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private fun requireCoordinate(
|
|
290
|
+
latitude: Double,
|
|
291
|
+
longitude: Double,
|
|
292
|
+
) {
|
|
293
|
+
if (latitude !in -90.0..90.0 || longitude !in -180.0..180.0) {
|
|
294
|
+
invalid("Coordinate latitude or longitude is outside its valid range.")
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private fun requireMainThread() {
|
|
299
|
+
if (Looper.myLooper() != Looper.getMainLooper()) {
|
|
300
|
+
throw CodedException("ERR_KAKAO_MAP_WRONG_THREAD", "Advanced camera commands must run on the main thread.", null)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private fun invalid(message: String): Nothing = throw CodedException(INVALID_ARGUMENT, message, null)
|
|
305
|
+
|
|
306
|
+
private fun unsupported(message: String): Nothing = throw CodedException(CAMERA_UNSUPPORTED, message, null)
|