Skip to content

Commit fc7f374

Browse files
Merge pull request #68 from what3words/task/MT-6872-Recall-button
Optimize computing recall button, refactor code
2 parents e8af5ca + 361ae57 commit fc7f374

File tree

7 files changed

+121
-91
lines changed

7 files changed

+121
-91
lines changed

lib-compose/src/main/java/com/what3words/components/compose/maps/W3WMapComponent.kt

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -247,15 +247,17 @@ internal fun W3WMapContent(
247247
// Handles check location permissions, if isMyLocationEnabled enable
248248
MapPermissionsHandler(mapState = mapState, onError = onError) {
249249

250-
var bounds by remember { mutableStateOf<Rect?>(null) }
250+
var bounds by remember { mutableStateOf(Rect.Zero) }
251251

252252
// Fetch current location when launch
253253
LaunchedEffect(Unit) {
254254
if (mapState.isMyLocationEnabled) {
255255
onMyLocationClicked.invoke()
256256
}
257-
// TODO: Implement logic with the padding of other elements (action panel, search bar, etc)
258-
bounds?.let {
257+
}
258+
259+
LaunchedEffect(bounds) {
260+
bounds.let {
259261
val leftTop = PointF(it.left, it.top)
260262
val rightTop = PointF(it.right, it.top)
261263
val rightBottom = PointF(it.right, it.bottom)
@@ -266,9 +268,7 @@ internal fun W3WMapContent(
266268

267269
Box(modifier = modifier
268270
.onGloballyPositioned { coordinates ->
269-
if (bounds == null) {
270-
bounds = coordinates.boundsInParent()
271-
}
271+
bounds = coordinates.boundsInParent()
272272
}
273273
) {
274274
W3WMapView(
@@ -288,16 +288,13 @@ internal fun W3WMapContent(
288288
modifier = Modifier
289289
.align(Alignment.BottomEnd)
290290
.padding(layoutConfig.contentPadding),
291-
onMyLocationClicked = onMyLocationClicked,
292-
mapConfig = mapConfig,
291+
buttonConfig = mapConfig.buttonConfig,
292+
buttonState = buttonState,
293+
isLocationEnabled = mapState.isMyLocationEnabled,
293294
onMapTypeClicked = onMapTypeClicked,
295+
onMyLocationClicked = onMyLocationClicked,
294296
onRecallClicked = onRecallClicked,
295-
rotation = buttonState.rotationDegree,
296297
onRecallButtonPositionProvided = onRecallButtonPositionProvided,
297-
isLocationEnabled = mapState.isMyLocationEnabled,
298-
accuracyDistance = buttonState.accuracyDistance,
299-
isLocationActive = buttonState.isLocationActive,
300-
isRecallButtonVisible = buttonState.isRecallButtonVisible,
301298
)
302299
}
303300
}

lib-compose/src/main/java/com/what3words/components/compose/maps/W3WMapManager.kt

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.what3words.components.compose.maps
33
import android.annotation.SuppressLint
44
import android.graphics.PointF
55
import androidx.annotation.RequiresPermission
6+
import androidx.compose.ui.graphics.Color
67
import com.google.android.gms.maps.model.CameraPosition
78
import com.google.maps.android.compose.CameraPositionState
89
import com.mapbox.geojson.Point
@@ -446,47 +447,61 @@ class W3WMapManager(
446447
private suspend fun updateSelectedScreenLocation() {
447448
withContext(dispatcher) {
448449
val selectedAddress = mapState.value.selectedAddress?.latLng
450+
val mapProjection = buttonState.value.mapProjection
449451
val selectedScreenLocation =
450-
selectedAddress?.let { buttonState.value.mapProjection?.toScreenLocation(it) }
452+
selectedAddress?.let { mapProjection?.toScreenLocation(it) }
451453
_buttonState.update {
452-
it.copy(selectedScreenLocation = selectedScreenLocation)
454+
it.copy(
455+
selectedScreenLocation = selectedScreenLocation,
456+
)
457+
}
458+
}
459+
}
460+
461+
private suspend fun updateRecallButtonColor() {
462+
withContext(dispatcher) {
463+
val markerSlashColor = mapState.value.selectedAddress?.color?.slash
464+
val markerBackgroundColor = mapState.value.selectedAddress?.color?.background
465+
_buttonState.update {
466+
it.copy(
467+
recallArrowColor = markerSlashColor ?: Color.White,
468+
recallBackgroundColor = markerBackgroundColor ?: Color(0xFFE11F26), // TODO: Define name for this color
469+
)
453470
}
454471
}
455472
}
456473

457-
// TODO: Update recall button color according to marker
458474
private suspend fun handleRecallButton() {
459475
updateSelectedScreenLocation()
460-
val selectedScreenLocation = buttonState.value.selectedScreenLocation
461-
val recallButtonViewport = buttonState.value.recallButtonViewPort
462-
val mapProjection = buttonState.value.mapProjection
463-
val recallButtonPosition = buttonState.value.recallButtonPosition
464-
val shouldShowRecallButton = mapProjection?.let {
465-
selectedScreenLocation?.let {
466-
// Check if the selected screen location is within the recall button viewport
467-
recallButtonViewport?.containsPoint(it) == false
468-
}
469-
} ?: false
470-
val rotationDegree =
471-
computeRecallButtonRotation(selectedScreenLocation, recallButtonPosition)
476+
updateRecallButtonColor()
477+
478+
val buttonState = buttonState.value
479+
val selectedScreenLocation = buttonState.selectedScreenLocation
480+
val recallButtonViewport = buttonState.recallButtonViewPort
481+
val mapProjection = buttonState.mapProjection
482+
val recallButtonPosition = buttonState.recallButtonPosition
483+
484+
// Early return if necessary data is null
485+
if (mapProjection == null || selectedScreenLocation == null) return
486+
487+
val shouldShowRecallButton = recallButtonViewport?.containsPoint(selectedScreenLocation) == false
488+
val rotationDegree = computeRecallButtonRotation(selectedScreenLocation, recallButtonPosition)
489+
472490
_buttonState.update {
473491
it.copy(
474-
rotationDegree = rotationDegree ?: 0F,
492+
recallRotationDegree = rotationDegree,
475493
isRecallButtonVisible = shouldShowRecallButton,
476494
)
477495
}
478496
}
479497

480498
private fun computeRecallButtonRotation(
481-
selectedScreenLocation: PointF?,
499+
selectedScreenLocation: PointF,
482500
recallButtonPosition: PointF
483-
) =
484-
selectedScreenLocation?.let {
485-
angleOfPoints(recallButtonPosition, selectedScreenLocation).let { alpha ->
486-
// add 180 degrees to computed value to compensate arrow rotation
487-
(180 + alpha) * -1
488-
}
489-
}
501+
) = angleOfPoints(recallButtonPosition, selectedScreenLocation).let { alpha ->
502+
// add 180 degrees to computed value to compensate arrow rotation
503+
(180 + alpha) * -1
504+
}
490505

491506
private fun addMarker(
492507
marker: W3WMarker

lib-compose/src/main/java/com/what3words/components/compose/maps/buttons/mapswitch/W3WMapSwitchButton.kt renamed to lib-compose/src/main/java/com/what3words/components/compose/maps/buttons/MapSwitchButton.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.what3words.components.compose.maps.buttons.mapswitch
1+
package com.what3words.components.compose.maps.buttons
22

33
import androidx.compose.foundation.Image
44
import androidx.compose.foundation.layout.padding
@@ -27,7 +27,7 @@ import com.what3words.map.components.compose.R
2727
* @param onMapTypeChange The callback function to be invoked when the map type is changed.
2828
*/
2929
@Composable
30-
fun W3WMapSwitchButton(
30+
fun MapSwitchButton(
3131
modifier: Modifier = Modifier,
3232
w3wMapType: W3WMapType = W3WMapType.NORMAL,
3333
onMapTypeChange: (W3WMapType) -> Unit
@@ -63,11 +63,11 @@ fun W3WMapSwitchButton(
6363
@Preview
6464
@Composable
6565
fun MapNormalPreview() {
66-
W3WMapSwitchButton(w3wMapType = W3WMapType.NORMAL) {}
66+
MapSwitchButton(w3wMapType = W3WMapType.NORMAL) {}
6767
}
6868

6969
@Preview
7070
@Composable
7171
fun MapTypeSwitcherPreview() {
72-
W3WMapSwitchButton(w3wMapType = W3WMapType.SATELLITE) {}
72+
MapSwitchButton(w3wMapType = W3WMapType.SATELLITE) {}
7373
}

lib-compose/src/main/java/com/what3words/components/compose/maps/buttons/findmylocation/W3WFindMyLocationButton.kt renamed to lib-compose/src/main/java/com/what3words/components/compose/maps/buttons/MyLocationButton.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.what3words.components.compose.maps.buttons.findmylocation
1+
package com.what3words.components.compose.maps.buttons
22

33
import androidx.compose.animation.AnimatedVisibility
44
import androidx.compose.foundation.background
@@ -33,7 +33,6 @@ import androidx.compose.ui.draw.shadow
3333
import androidx.compose.ui.graphics.Color
3434
import androidx.compose.ui.tooling.preview.Preview
3535
import androidx.compose.ui.unit.dp
36-
import com.what3words.components.compose.maps.buttons.W3WMapButtonsDefault
3736
import com.what3words.design.library.ui.theme.W3WTheme
3837
import com.what3words.design.library.ui.theme.w3wColorScheme
3938
import kotlinx.coroutines.delay
@@ -57,7 +56,7 @@ const val VISIBLE_TIME = 2000L
5756
* @param onMyLocationClicked The callback when the button is clicked.
5857
*/
5958
@Composable
60-
fun W3WFindMyLocationButton(
59+
fun MyLocationButton(
6160
modifier: Modifier = Modifier,
6261
accuracyDistance: Int,
6362
isLocationEnabled: Boolean,
@@ -162,7 +161,7 @@ fun W3WFindMyLocationButton(
162161
@Composable
163162
private fun A1() {
164163
W3WTheme {
165-
W3WFindMyLocationButton(
164+
MyLocationButton(
166165
modifier = Modifier,
167166
onMyLocationClicked = {},
168167
accuracyDistance = 0,
@@ -178,7 +177,7 @@ private fun A1() {
178177
@Composable
179178
private fun A2() {
180179
W3WTheme {
181-
W3WFindMyLocationButton(
180+
MyLocationButton(
182181
modifier = Modifier,
183182
onMyLocationClicked = {},
184183
accuracyDistance = 0,
@@ -193,7 +192,7 @@ private fun A2() {
193192
@Composable
194193
private fun A3() {
195194
W3WTheme {
196-
W3WFindMyLocationButton(
195+
MyLocationButton(
197196
modifier = Modifier,
198197
onMyLocationClicked = {},
199198
accuracyDistance = 110,
@@ -208,7 +207,7 @@ private fun A3() {
208207
@Composable
209208
private fun A4() {
210209
W3WTheme {
211-
W3WFindMyLocationButton(
210+
MyLocationButton(
212211
modifier = Modifier,
213212
onMyLocationClicked = {},
214213
accuracyDistance = 220,
@@ -223,7 +222,7 @@ private fun A4() {
223222
@Composable
224223
private fun A5() {
225224
W3WTheme {
226-
W3WFindMyLocationButton(
225+
MyLocationButton(
227226
modifier = Modifier,
228227
onMyLocationClicked = {},
229228
accuracyDistance = 220,

lib-compose/src/main/java/com/what3words/components/compose/maps/buttons/recall/W3WRecallButton.kt renamed to lib-compose/src/main/java/com/what3words/components/compose/maps/buttons/RecallButton.kt

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
package com.what3words.components.compose.maps.buttons.recall
1+
package com.what3words.components.compose.maps.buttons
22

33
import android.graphics.PointF
4-
import android.util.Log
54
import androidx.compose.foundation.background
65
import androidx.compose.foundation.layout.offset
76
import androidx.compose.foundation.layout.padding
@@ -23,35 +22,52 @@ import androidx.compose.ui.draw.shadow
2322
import androidx.compose.ui.geometry.Offset
2423
import androidx.compose.ui.graphics.Color
2524
import androidx.compose.ui.layout.onGloballyPositioned
25+
import androidx.compose.ui.layout.positionInWindow
2626
import androidx.compose.ui.tooling.preview.Preview
2727
import androidx.compose.ui.unit.dp
2828

29+
/**
30+
* A composable function to display a recall button.
31+
*
32+
* @param modifier The modifier for the button.
33+
* @param rotation The rotation angle for the button in degrees.
34+
* @param backgroundColor The background color of the button.
35+
* @param arrowColor The color of the arrow icon.
36+
* @param isVisible Whether the button is visible or not.
37+
* @param onRecallClicked The callback when the button is clicked.
38+
* @param onRecallButtonPositionProvided The callback providing the button's position as a PointF.
39+
*/
2940
@Composable
30-
fun W3WRecallButton(
41+
fun RecallButton(
3142
modifier: Modifier = Modifier,
3243
rotation: Float = 0F,
3344
backgroundColor: Color = Color(0xFFE11F26),
3445
arrowColor: Color = Color.White,
46+
isVisible: Boolean = false,
3547
onRecallClicked: () -> Unit,
36-
onRecallPositionProvided: (PointF) -> Unit,
48+
onRecallButtonPositionProvided: (PointF) -> Unit,
3749
) {
3850

39-
var position: Offset? by remember { mutableStateOf(null) }
51+
var position: Offset by remember { mutableStateOf(Offset.Zero) }
4052

4153
IconButton(
4254
onClick = { onRecallClicked() },
4355
modifier = modifier
56+
.alpha(if (isVisible) 1f else 0f)
4457
.rotate(rotation)
4558
.shadow(elevation = 3.dp, shape = CircleShape)
4659
.size(50.dp)
4760
.background(backgroundColor)
4861
.onGloballyPositioned { coordinate ->
49-
if (position == null) {
50-
position = coordinate.localToWindow(Offset.Zero)
51-
val point = PointF(position!!.x, position!!.y)
52-
onRecallPositionProvided.invoke(point)
62+
// Only trigger one time when the button is initialized
63+
// The coordinate is affected by the rotation
64+
if (position == Offset.Zero) {
65+
position = coordinate.positionInWindow()
66+
val point = PointF(position.x, position.y)
67+
onRecallButtonPositionProvided.invoke(point)
5368
}
5469
},
70+
enabled = isVisible
5571
) {
5672
Icon(
5773
modifier = Modifier
@@ -68,64 +84,69 @@ fun W3WRecallButton(
6884
@Preview
6985
@Composable
7086
private fun A1() {
71-
W3WRecallButton(
87+
RecallButton(
7288
modifier = Modifier,
7389
rotation = 0f,
7490
backgroundColor = Color(0xFFE11F26),
7591
arrowColor = Color.White,
92+
isVisible = true,
7693
onRecallClicked = {},
77-
onRecallPositionProvided = {}
94+
onRecallButtonPositionProvided = {}
7895
)
7996
}
8097

8198
@Preview
8299
@Composable
83100
private fun A2() {
84-
W3WRecallButton(
101+
RecallButton(
85102
modifier = Modifier,
86103
rotation = 45f,
87104
backgroundColor = Color(0xFFE11F26),
88105
arrowColor = Color.White,
106+
isVisible = true,
89107
onRecallClicked = {},
90-
onRecallPositionProvided = {}
108+
onRecallButtonPositionProvided = {}
91109
)
92110
}
93111

94112
@Preview
95113
@Composable
96114
private fun A3() {
97-
W3WRecallButton(
115+
RecallButton(
98116
modifier = Modifier,
99117
rotation = 90f,
100118
backgroundColor = Color(0xFFE11F26),
101119
arrowColor = Color.White,
120+
isVisible = true,
102121
onRecallClicked = {},
103-
onRecallPositionProvided = {}
122+
onRecallButtonPositionProvided = {}
104123
)
105124
}
106125

107126
@Preview
108127
@Composable
109128
private fun A4() {
110-
W3WRecallButton(
129+
RecallButton(
111130
modifier = Modifier,
112131
rotation = 135f,
113132
backgroundColor = Color(0xFFE11F26),
114133
arrowColor = Color.White,
134+
isVisible = true,
115135
onRecallClicked = {},
116-
onRecallPositionProvided = {}
136+
onRecallButtonPositionProvided = {}
117137
)
118138
}
119139

120140
@Preview
121141
@Composable
122142
private fun A5() {
123-
W3WRecallButton(
143+
RecallButton(
124144
modifier = Modifier,
125145
rotation = 180f,
126146
backgroundColor = Color(0xFFE11F26),
127147
arrowColor = Color.White,
148+
isVisible = true,
128149
onRecallClicked = {},
129-
onRecallPositionProvided = {}
150+
onRecallButtonPositionProvided = {}
130151
)
131152
}

0 commit comments

Comments
 (0)