Skip to content

Commit 2c9f37d

Browse files
RD-1145: Add MTLineLayer
1 parent e6bc71b commit 2c9f37d

File tree

3 files changed

+453
-33
lines changed

3 files changed

+453
-33
lines changed

.github/copilot-instructions.md

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ MUST follow this end-to-end flow when wrapping a JS API into Kotlin:
6767
- If a new return shape is required, extend `MTBridgeReturnType` in a focused change with tests.
6868

6969
5) Public API surface
70-
- Add a thin convenience method on `MTMapViewController` (or appropriate worker/service) that:
70+
- Add a thin convenience method on appropriate worker (NavigableWorker, ZoomableWorker etc.) and update `MTMapViewController` that uses it or StylableWorker and update MTStyle class that uses it:
7171
- Ensures the map/style are ready (`ON_READY`).
7272
- Validates inputs and applies sensible defaults.
7373
- Launches on the appropriate coroutine scope and calls the bridge.
74-
- Uses `suspend` functions for getters and `Result`/exceptions for failures where appropriate.
74+
- Uses `suspend` functions for getters only and `Result`/exceptions for failures where appropriate.
7575

7676
6) Threading and lifecycle
7777
- MUST execute JS on the main thread. `WebViewExecutor` already enforces `Dispatchers.Main`; do not bypass it.
@@ -84,32 +84,72 @@ MUST follow this end-to-end flow when wrapping a JS API into Kotlin:
8484
Example skeleton:
8585

8686
```kotlin
87-
@Serializable
88-
private data class RotateToOptions(
89-
val bearing: Double,
90-
val duration: Double? = null,
91-
)
92-
93-
internal data class RotateTo(
94-
private val bearing: Double,
95-
private val durationMs: Double? = null,
87+
internal data class FlyTo(
88+
val cameraOptions: MTCameraOptions,
89+
val flyToOptions: MTFlyToOptions? = null,
9690
) : MTCommand {
9791
override val isPrimitiveReturnType: Boolean = false
9892

99-
override fun toJS(): JSString {
100-
val opts = RotateToOptions(bearing = bearing, duration = durationMs)
101-
val json = JsonConfig.json.encodeToString(opts)
102-
return "${MTBridge.MAP_OBJECT}.rotateTo($json);"
93+
override fun toJS(): String {
94+
val surrogate = getSurrogate(cameraOptions, flyToOptions)
95+
val flyToString: JSString = JsonConfig.json.encodeToString(surrogate)
96+
97+
return "${MTBridge.MAP_OBJECT}.flyTo($flyToString);"
10398
}
99+
100+
private fun getSurrogate(
101+
cameraOptions: MTCameraOptions,
102+
flyToOptions: MTFlyToOptions?,
103+
): FlyToSurrogate =
104+
FlyToSurrogate(
105+
cameraOptions.center,
106+
cameraOptions.zoom,
107+
cameraOptions.bearing,
108+
cameraOptions.pitch,
109+
flyToOptions?.curve,
110+
flyToOptions?.minZoom,
111+
flyToOptions?.speed,
112+
flyToOptions?.screenSpeed,
113+
flyToOptions?.maxDuration,
114+
)
104115
}
105116

106-
// Controller convenience API
107-
fun MTMapViewController.setBearing(
108-
bearing: Double,
109-
durationMs: Double? = null,
110-
) {
111-
val clamped = ((bearing % 360 + 360) % 360)
112-
coroutineScope?.launch { bridge?.execute(RotateTo(clamped, durationMs)) }
117+
@Serializable
118+
private data class FlyToSurrogate(
119+
val center: LngLat,
120+
val zoom: Double?,
121+
val bearing: Double?,
122+
val pitch: Double?,
123+
val curve: Double?,
124+
val minZoom: Double?,
125+
val speed: Double?,
126+
val screenSpeed: Double?,
127+
val maxDuration: Double?,
128+
)
129+
130+
// NavigableWorker
131+
override fun flyTo(
132+
cameraOptions: MTCameraOptions,
133+
flyToOptions: MTFlyToOptions?,
134+
) {
135+
scope.launch {
136+
bridge.execute(
137+
FlyTo(cameraOptions, flyToOptions),
138+
)
139+
}
140+
}
141+
142+
// MTMapViewController
143+
/**
144+
* Changes any combination of center, zoom, bearing, and pitch, animating the transition along a curve that evokes flight.
145+
*
146+
* @param cameraOptions Options for controlling the desired location, zoom, bearing, and pitch of the camera.
147+
* @param flyToOptions Options describing the destination and animation of the transition.
148+
*/
149+
override fun flyTo(
150+
cameraOptions: MTCameraOptions,
151+
flyToOptions: MTFlyToOptions?,
152+
) = navigableWorker.flyTo(cameraOptions, flyToOptions)
113153
}
114154
```
115155

@@ -163,9 +203,8 @@ override fun onDestroy() {
163203
## ktlint Compliance (MANDATORY)
164204
- ALWAYS follow the rules enforced by the `org.jlleitschuh.gradle.ktlint` plugin.
165205
- Key rules: spacing, imports order, trailing newline, indentation, annotation/kdoc formatting, no wildcard imports.
166-
- Pre-commit: a Git hook runs `./gradlew ktlintCheck`. Ensure zero violations before committing.
206+
- Pre-commit: a Git hook runs `./gradlew ktlintCheck`. Ensure zero violations before committing by running ./gradlew ktlintFormat
167207
- CI/Local requirement: run `./gradlew ktlintCheck` and ensure zero warnings/errors. PRs must be lint-clean.
168-
- Formatting: the project disables `ktlintFormat` by default; fix violations manually or enable formatting locally if needed.
169208

170209
## Development Best Practices
171210

@@ -257,11 +296,10 @@ MUST wait for `ON_READY` before mutating style or layers. Changing the reference
257296

258297
## Tests
259298

260-
- Before you make the Pull Request ALWAYS run unit tests to validate the code and fix potential issues.
261-
- Commands:
299+
- Before you make the Pull Request ALWAYS run linter and unit tests to validate the code and fix potential issues.
300+
- Commands (MUST run):
301+
- `./gradlew ktlintFormat`
262302
- `./gradlew ktlintCheck`
263-
- `./gradlew :MapTilerSDK:test`
264-
- Optional: `./gradlew :MapTilerSDK:dokkaHtml` to validate docs generation
265303
- Add or update unit tests as required (encoding, clamping, `toJS()` contract), but leave full execution to the user/CI.
266304
- Prefer small, focused tests near the code you change; avoid introducing unrelated tests.
267305

MapTilerSDK/src/main/java/com/maptiler/maptilersdk/map/style/layer/fill/MTFillLayer.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class MTFillLayer : MTLayer {
165165

166166
@Suppress("PropertyName")
167167
@SerialName("paint")
168-
private var _paint: MTPaintLayout = MTPaintLayout()
168+
private var _paint: MTFillPaint = MTFillPaint()
169169

170170
constructor(
171171
identifier: String,
@@ -181,7 +181,7 @@ class MTFillLayer : MTLayer {
181181
this.sourceLayer = sourceLayer
182182

183183
this._layout = MTFillLayout(visibility)
184-
this._paint = MTPaintLayout(color, shouldBeAntialised, opacity, outlineColor, translate, translateAnchor)
184+
this._paint = MTFillPaint(color, shouldBeAntialised, opacity, outlineColor, translate, translateAnchor)
185185
}
186186

187187
constructor(
@@ -192,7 +192,7 @@ class MTFillLayer : MTLayer {
192192
this.sourceIdentifier = sourceIdentifier
193193

194194
this._layout = MTFillLayout(visibility)
195-
this._paint = MTPaintLayout(color, shouldBeAntialised, opacity, outlineColor, translate, translateAnchor)
195+
this._paint = MTFillPaint(color, shouldBeAntialised, opacity, outlineColor, translate, translateAnchor)
196196
}
197197

198198
constructor(
@@ -226,7 +226,7 @@ class MTFillLayer : MTLayer {
226226
this.sortKey = sortKey
227227
this.visibility = visibility
228228
this._layout = MTFillLayout(visibility)
229-
this._paint = MTPaintLayout(color, shouldBeAntialised, opacity, outlineColor, translate, translateAnchor)
229+
this._paint = MTFillPaint(color, shouldBeAntialised, opacity, outlineColor, translate, translateAnchor)
230230
}
231231
}
232232

@@ -237,7 +237,7 @@ internal data class MTFillLayout(
237237
)
238238

239239
@Serializable
240-
internal data class MTPaintLayout(
240+
internal data class MTFillPaint(
241241
@Serializable(with = ColorAsHexSerializer::class)
242242
@SerialName("fill-color")
243243
var color: Int? = Color.BLACK,

0 commit comments

Comments
 (0)