@@ -11,6 +11,8 @@ import androidx.compose.foundation.background
1111import androidx.compose.foundation.gestures.detectTapGestures
1212import androidx.compose.foundation.gestures.rememberTransformableState
1313import androidx.compose.foundation.gestures.transformable
14+ import androidx.compose.foundation.layout.Arrangement
15+ import androidx.compose.foundation.layout.Box
1416import androidx.compose.foundation.layout.Column
1517import androidx.compose.foundation.layout.fillMaxSize
1618import androidx.compose.foundation.layout.padding
@@ -24,6 +26,7 @@ import androidx.compose.runtime.saveable.Saver
2426import androidx.compose.runtime.saveable.SaverScope
2527import androidx.compose.runtime.saveable.rememberSaveable
2628import androidx.compose.runtime.setValue
29+ import androidx.compose.ui.Alignment
2730import androidx.compose.ui.Modifier
2831import androidx.compose.ui.draw.clipToBounds
2932import androidx.compose.ui.geometry.Offset
@@ -40,11 +43,17 @@ import org.jetbrains.compose.resources.StringResource
4043import org.jetbrains.compose.resources.stringResource
4144import org.jetbrains.kotlinconf.generated.resources.Res
4245import org.jetbrains.kotlinconf.generated.resources.arrow_left_24
46+ import org.jetbrains.kotlinconf.generated.resources.bookmark_24
4347import org.jetbrains.kotlinconf.generated.resources.map_first_floor
4448import org.jetbrains.kotlinconf.generated.resources.map_ground_floor
4549import org.jetbrains.kotlinconf.generated.resources.map_title
50+ import org.jetbrains.kotlinconf.generated.resources.map_zoom_in
51+ import org.jetbrains.kotlinconf.generated.resources.map_zoom_out
52+ import org.jetbrains.kotlinconf.generated.resources.minus_24
4653import org.jetbrains.kotlinconf.generated.resources.navigate_back
54+ import org.jetbrains.kotlinconf.generated.resources.plus_24
4755import org.jetbrains.kotlinconf.ui.components.Divider
56+ import org.jetbrains.kotlinconf.ui.components.IconButton
4857import org.jetbrains.kotlinconf.ui.components.MainHeaderTitleBar
4958import org.jetbrains.kotlinconf.ui.components.Switcher
5059import org.jetbrains.kotlinconf.ui.components.TopMenuButton
@@ -206,6 +215,8 @@ private fun Map(
206215 val validOffsetX = (- svg.width * 0.5f ).. (svg.width * 0.5f )
207216 val validOffsetY = (- svg.height * 0.5f ).. (svg.height * 0.5f )
208217
218+ val spec = tween<Float >(500 , easing = EaseOutCubic )
219+
209220 val interactiveModifiers = if (! interactive) {
210221 Modifier
211222 } else {
@@ -224,8 +235,6 @@ private fun Map(
224235
225236 detectTapGestures(
226237 onDoubleTap = { tapOffset ->
227- val spec = tween<Float >(500 , easing = EaseOutCubic )
228-
229238 if (scale.value >= zoomRange.endInclusive - 0.1f ) {
230239 scope.launch { scale.animateTo(initialZoom, spec) }
231240 } else {
@@ -247,23 +256,58 @@ private fun Map(
247256 }
248257 }
249258
250- Canvas (
251- modifier
252- .clipToBounds()
253- .fillMaxSize()
254- .then(interactiveModifiers)
255- ) {
256- translate(
257- left = offsetX.value + (size.width - svg.width) / 2 ,
258- top = offsetY.value + (size.height - svg.height) / 2 ,
259+ Box (Modifier .fillMaxSize()) {
260+ Canvas (
261+ modifier
262+ .clipToBounds()
263+ .fillMaxSize()
264+ .then(interactiveModifiers)
259265 ) {
260- scale (
261- scale = scale .value,
262- pivot = Offset (svg.width / 2 - offsetX.value, svg.height / 2 - offsetY.value) ,
266+ translate (
267+ left = offsetX .value + (size.width - svg.width) / 2 ,
268+ top = offsetY.value + (size.height - svg.height) / 2 ,
263269 ) {
264- svg.renderTo(this )
270+ scale(
271+ scale = scale.value,
272+ pivot = Offset (svg.width / 2 - offsetX.value, svg.height / 2 - offsetY.value),
273+ ) {
274+ svg.renderTo(this )
275+ }
265276 }
266277 }
278+ Column (
279+ modifier = Modifier
280+ .align(Alignment .BottomEnd )
281+ .padding(bottom = 24 .dp, end = 12 .dp),
282+ verticalArrangement = Arrangement .spacedBy(16 .dp)
283+ ) {
284+ IconButton (
285+ icon = Res .drawable.plus_24,
286+ enabled = scale.targetValue < zoomRange.endInclusive,
287+ onClick = {
288+ scope.launch {
289+ scale.animateTo(
290+ targetValue = (scale.value * 2f ).coerceIn(zoomRange),
291+ animationSpec = spec,
292+ )
293+ }
294+ },
295+ contentDescription = stringResource(Res .string.map_zoom_in),
296+ )
297+ IconButton (
298+ icon = Res .drawable.minus_24,
299+ enabled = scale.targetValue > zoomRange.start,
300+ onClick = {
301+ scope.launch {
302+ scale.animateTo(
303+ targetValue = (scale.value / 2f ).coerceIn(zoomRange),
304+ animationSpec = spec,
305+ )
306+ }
307+ },
308+ contentDescription = stringResource(Res .string.map_zoom_out),
309+ )
310+ }
267311 }
268312}
269313
0 commit comments