Skip to content

Commit 58ecf35

Browse files
committed
Refactor api
1 parent ea9bf1f commit 58ecf35

File tree

16 files changed

+165
-128
lines changed

16 files changed

+165
-128
lines changed

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt

+39-12
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package net.mullvad.mullvadvpn.compose.screen
33
import android.content.Intent
44
import android.net.Uri
55
import androidx.compose.animation.animateContentSize
6+
import androidx.compose.animation.core.animateFloatAsState
7+
import androidx.compose.animation.core.tween
68
import androidx.compose.foundation.layout.Arrangement
7-
import androidx.compose.foundation.layout.Box
89
import androidx.compose.foundation.layout.Column
910
import androidx.compose.foundation.layout.Spacer
1011
import androidx.compose.foundation.layout.defaultMinSize
@@ -19,6 +20,7 @@ import androidx.compose.material3.Text
1920
import androidx.compose.runtime.Composable
2021
import androidx.compose.runtime.LaunchedEffect
2122
import androidx.compose.runtime.collectAsState
23+
import androidx.compose.runtime.derivedStateOf
2224
import androidx.compose.runtime.getValue
2325
import androidx.compose.runtime.mutableFloatStateOf
2426
import androidx.compose.runtime.mutableLongStateOf
@@ -61,8 +63,14 @@ import net.mullvad.mullvadvpn.compose.test.RECONNECT_BUTTON_TEST_TAG
6163
import net.mullvad.mullvadvpn.compose.test.SCROLLABLE_COLUMN_TEST_TAG
6264
import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_BUTTON_TEST_TAG
6365
import net.mullvad.mullvadvpn.compose.transitions.HomeTransition
66+
import net.mullvad.mullvadvpn.constant.SECURE_ZOOM
67+
import net.mullvad.mullvadvpn.constant.SECURE_ZOOM_ANIMATION_MILLIS
68+
import net.mullvad.mullvadvpn.constant.UNSECURE_ZOOM
6469
import net.mullvad.mullvadvpn.lib.common.util.openAccountPageInBrowser
65-
import net.mullvad.mullvadvpn.lib.map.Map
70+
import net.mullvad.mullvadvpn.lib.map.AnimatedMap
71+
import net.mullvad.mullvadvpn.lib.map.data.GlobeColors
72+
import net.mullvad.mullvadvpn.lib.map.data.LocationMarkerColors
73+
import net.mullvad.mullvadvpn.lib.map.data.Marker
6674
import net.mullvad.mullvadvpn.lib.theme.AppTheme
6775
import net.mullvad.mullvadvpn.lib.theme.Dimens
6876
import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar
@@ -194,12 +202,29 @@ fun ConnectScreen(
194202
) {
195203
var progressIndicatorBias by remember { mutableFloatStateOf(0f) }
196204

197-
Map(
205+
// Distance to marker when secure/unsecure
206+
val baseZoom =
207+
animateFloatAsState(
208+
targetValue =
209+
if (uiState.tunnelRealState is TunnelState.Connected) SECURE_ZOOM
210+
else UNSECURE_ZOOM,
211+
animationSpec = tween(SECURE_ZOOM_ANIMATION_MILLIS)
212+
)
213+
214+
val markers = uiState.tunnelRealState.toMarker(uiState.location)?.let { listOf(it) }
215+
?: emptyList()
216+
217+
AnimatedMap(
198218
modifier = Modifier.padding(top = it.calculateTopPadding()),
199-
uiState.animateMap,
200-
uiState.location?.toLatLong() ?: gothenburgLatLong,
201-
marker = uiState.tunnelRealState.toMarker(uiState.location),
202-
progressIndicatorBias,
219+
cameraLocation = uiState.location?.toLatLong() ?: gothenburgLatLong,
220+
cameraBaseZoom = baseZoom.value,
221+
cameraVerticalBias = progressIndicatorBias,
222+
markers = markers,
223+
globeColors =
224+
GlobeColors(
225+
landColor = MaterialTheme.colorScheme.primary,
226+
oceanColor = MaterialTheme.colorScheme.secondary,
227+
)
203228
)
204229

205230
NotificationBanner(
@@ -317,19 +342,21 @@ fun ConnectScreen(
317342
}
318343
}
319344

320-
fun TunnelState.toMarker(location: GeoIpLocation?): net.mullvad.mullvadvpn.lib.map.data.Marker? {
345+
@Composable
346+
fun TunnelState.toMarker(location: GeoIpLocation?): Marker? {
321347
if (location == null) return null
322348
return when (this) {
323349
is TunnelState.Connected ->
324-
net.mullvad.mullvadvpn.lib.map.data.Marker(
350+
Marker(
325351
location.toLatLong(),
326-
net.mullvad.mullvadvpn.lib.map.data.MarkerType.SECURE
352+
colors =
353+
LocationMarkerColors(centerColor = MaterialTheme.colorScheme.inversePrimary),
327354
)
328355
is TunnelState.Connecting -> null
329356
is TunnelState.Disconnected ->
330-
net.mullvad.mullvadvpn.lib.map.data.Marker(
357+
Marker(
331358
location.toLatLong(),
332-
net.mullvad.mullvadvpn.lib.map.data.MarkerType.UNSECURE
359+
colors = LocationMarkerColors(centerColor = MaterialTheme.colorScheme.error)
333360
)
334361
is TunnelState.Disconnecting -> null
335362
is TunnelState.Error -> null

android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/AnimationConstant.kt

+4
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ const val SCREEN_ANIMATION_TIME_MILLIS = Spring.StiffnessMediumLow.toInt()
99
const val HORIZONTAL_SLIDE_FACTOR = 1 / 3f
1010

1111
fun Int.withHorizontalScalingFactor(): Int = (this * HORIZONTAL_SLIDE_FACTOR).toInt()
12+
13+
const val SECURE_ZOOM = 1.15f
14+
const val UNSECURE_ZOOM = 1.20f
15+
const val SECURE_ZOOM_ANIMATION_MILLIS = 2000

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/CameraAnimation.kt

+14-20
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,27 @@ import androidx.compose.runtime.LaunchedEffect
99
import androidx.compose.runtime.remember
1010
import kotlinx.coroutines.launch
1111
import net.mullvad.mullvadvpn.lib.map.data.CameraPosition
12-
import net.mullvad.mullvadvpn.lib.map.data.Marker
13-
import net.mullvad.mullvadvpn.lib.map.data.MarkerType
12+
import net.mullvad.mullvadvpn.lib.map.internal.DISTANCE_DURATION_SCALE_FACTOR
13+
import net.mullvad.mullvadvpn.lib.map.internal.FAR_ANIMATION_MAX_ZOOM_MULTIPLIER
14+
import net.mullvad.mullvadvpn.lib.map.internal.MAX_ANIMATION_MILLIS
15+
import net.mullvad.mullvadvpn.lib.map.internal.MAX_MULTIPLIER_PEAK_TIMING
16+
import net.mullvad.mullvadvpn.lib.map.internal.MIN_ANIMATION_MILLIS
17+
import net.mullvad.mullvadvpn.lib.map.internal.SHORT_ANIMATION_CUTOFF_MILLIS
1418
import net.mullvad.mullvadvpn.model.LatLong
1519
import net.mullvad.mullvadvpn.model.Latitude
1620
import net.mullvad.mullvadvpn.model.Longitude
1721

1822
@Composable
1923
fun animatedCameraPosition(
24+
baseZoom: Float,
2025
targetCameraLocation: LatLong,
21-
marker: Marker?,
22-
percent: Float,
26+
cameraVerticalBias: Float,
2327
): CameraPosition {
24-
val tempPreviousLocation =
28+
val previousLocation =
2529
rememberPrevious(
2630
current = targetCameraLocation,
2731
shouldUpdate = { prev, curr -> prev != curr }
2832
) ?: targetCameraLocation
29-
val previousLocation = remember(targetCameraLocation) { tempPreviousLocation }
3033

3134
val distance =
3235
remember(targetCameraLocation) { targetCameraLocation.distanceTo(previousLocation).toInt() }
@@ -35,9 +38,6 @@ fun animatedCameraPosition(
3538
val longitudeAnimation = remember { Animatable(targetCameraLocation.longitude.value) }
3639

3740
val latitudeAnimation = remember { Animatable(targetCameraLocation.latitude.value) }
38-
val secureZoomAnimation = remember {
39-
Animatable(if (marker?.type == MarkerType.SECURE) SECURE_ZOOM else UNSECURE_ZOOM)
40-
}
4141
val zoomOutMultiplier = remember { Animatable(1f) }
4242

4343
LaunchedEffect(targetCameraLocation) {
@@ -80,22 +80,16 @@ fun animatedCameraPosition(
8080
}
8181
}
8282

83-
LaunchedEffect(marker?.type) {
84-
launch {
85-
secureZoomAnimation.animateTo(
86-
targetValue = marker?.type.toZoom(),
87-
tween(SECURE_ZOOM_ANIMATION_MILLIS)
88-
)
89-
}
90-
}
91-
9283
return CameraPosition(
93-
zoom = secureZoomAnimation.value * zoomOutMultiplier.value,
84+
zoom = baseZoom * zoomOutMultiplier.value,
9485
latLong =
9586
LatLong(
9687
Latitude(latitudeAnimation.value),
9788
Longitude.fromFloat(longitudeAnimation.value)
9889
),
99-
bias = percent
90+
bias = cameraVerticalBias
10091
)
10192
}
93+
94+
private fun Int.toAnimationDuration() =
95+
(this * DISTANCE_DURATION_SCALE_FACTOR).coerceIn(MIN_ANIMATION_MILLIS, MAX_ANIMATION_MILLIS)

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/Map.kt

+29-45
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,45 @@ import androidx.compose.ui.viewinterop.AndroidView
99
import androidx.lifecycle.Lifecycle
1010
import androidx.lifecycle.LifecycleEventObserver
1111
import net.mullvad.mullvadvpn.lib.map.data.CameraPosition
12-
import net.mullvad.mullvadvpn.lib.map.data.MapConfig
12+
import net.mullvad.mullvadvpn.lib.map.data.GlobeColors
1313
import net.mullvad.mullvadvpn.lib.map.data.MapViewState
1414
import net.mullvad.mullvadvpn.lib.map.data.Marker
15-
import net.mullvad.mullvadvpn.lib.map.data.MarkerType
1615
import net.mullvad.mullvadvpn.lib.map.internal.MapGLSurfaceView
1716
import net.mullvad.mullvadvpn.model.LatLong
1817

1918
@Composable
2019
fun Map(
2120
modifier: Modifier,
22-
animateCameraMovement: Boolean,
23-
cameraLocation: LatLong,
24-
marker: Marker?,
25-
percent: Float,
21+
cameraLocation: CameraPosition,
22+
markers: List<Marker>,
23+
globeColors: GlobeColors,
2624
) {
27-
val mapViewState =
28-
if (animateCameraMovement) {
29-
MapViewState(marker, animatedCameraPosition(cameraLocation, marker, percent))
30-
} else {
31-
MapViewState(marker, CameraPosition(cameraLocation, marker?.type.toZoom(), percent))
32-
}
25+
val mapViewState = MapViewState(cameraLocation, markers, globeColors)
3326
Map(modifier = modifier, mapViewState = mapViewState)
3427
}
3528

29+
@Composable
30+
fun AnimatedMap(
31+
modifier: Modifier,
32+
cameraLocation: LatLong,
33+
cameraBaseZoom: Float,
34+
cameraVerticalBias: Float,
35+
markers: List<Marker>,
36+
globeColors: GlobeColors
37+
) {
38+
Map(
39+
modifier = modifier,
40+
cameraLocation =
41+
animatedCameraPosition(
42+
baseZoom = cameraBaseZoom,
43+
targetCameraLocation = cameraLocation,
44+
cameraVerticalBias = cameraVerticalBias
45+
),
46+
markers = markers,
47+
globeColors
48+
)
49+
}
50+
3651
@Composable
3752
internal fun Map(modifier: Modifier = Modifier, mapViewState: MapViewState) {
3853

@@ -47,7 +62,7 @@ internal fun Map(modifier: Modifier = Modifier, mapViewState: MapViewState) {
4762
view?.onResume()
4863
}
4964
Lifecycle.Event.ON_PAUSE -> {
50-
view?.onPause()
65+
view?.onPause()
5166
}
5267
else -> {}
5368
}
@@ -61,39 +76,8 @@ internal fun Map(modifier: Modifier = Modifier, mapViewState: MapViewState) {
6176
}
6277
}
6378

64-
// TODO how to handle mapConfig changes? Can we recreate the view? make them recomposable?
65-
AndroidView(modifier = modifier, factory = { MapGLSurfaceView(it, mapConfig = MapConfig()) }) {
66-
glSurfaceView ->
79+
AndroidView(modifier = modifier, factory = { MapGLSurfaceView(it) }) { glSurfaceView ->
6780
view = glSurfaceView
6881
glSurfaceView.setData(mapViewState)
6982
}
7083
}
71-
72-
fun MarkerType?.toZoom() =
73-
when (this) {
74-
MarkerType.SECURE -> SECURE_ZOOM
75-
MarkerType.UNSECURE,
76-
null -> UNSECURE_ZOOM
77-
}
78-
79-
fun Int.toAnimationDuration() =
80-
(this * DISTANCE_DURATION_SCALE_FACTOR).coerceIn(MIN_ANIMATION_MILLIS, MAX_ANIMATION_MILLIS)
81-
82-
// Distance to marker when secure/unsecure
83-
const val SECURE_ZOOM = 1.15f
84-
const val UNSECURE_ZOOM = 1.20f
85-
const val SECURE_ZOOM_ANIMATION_MILLIS = 2000
86-
87-
// Constant what will talk the distance in LatLng multiply it to determine the animation duration,
88-
// the result is then confined to the MIN_ANIMATION_MILLIS and MAX_ANIMATION_MILLIS
89-
const val DISTANCE_DURATION_SCALE_FACTOR = 20
90-
const val MIN_ANIMATION_MILLIS = 1300
91-
const val MAX_ANIMATION_MILLIS = 2500
92-
// The cut off where we go from a short animation (camera pans) to a far animation (camera pans +
93-
// zoom out)
94-
const val SHORT_ANIMATION_CUTOFF_MILLIS = 1700
95-
96-
// Multiplier for the zoom out animation
97-
const val FAR_ANIMATION_MAX_ZOOM_MULTIPLIER = 1.30f
98-
// When in the far animation we reach the MAX_ZOOM_MULTIPLIER, value is between 0 and 1
99-
const val MAX_MULTIPLIER_PEAK_TIMING = .35f
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package net.mullvad.mullvadvpn.lib.map.data
2+
3+
import androidx.compose.runtime.Immutable
4+
import net.mullvad.mullvadvpn.model.LatLong
5+
6+
@Immutable data class CameraPosition(val latLong: LatLong, val zoom: Float, val bias: Float)

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/data/GlobeColors.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package net.mullvad.mullvadvpn.lib.map.data
22

3+
import androidx.compose.runtime.Immutable
34
import androidx.compose.ui.graphics.Color
45
import net.mullvad.mullvadvpn.lib.map.internal.toFloatArray
56

7+
@Immutable
68
data class GlobeColors(
79
val landColor: Color,
810
val oceanColor: Color,
9-
val contourColor: Color,
11+
val contourColor: Color = oceanColor,
1012
) {
1113
val landColorArray = landColor.toFloatArray()
1214
val oceanColorArray = oceanColor.toFloatArray()

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/data/LocationMarkerColors.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package net.mullvad.mullvadvpn.lib.map.data
22

3+
import androidx.compose.runtime.Immutable
34
import androidx.compose.ui.graphics.Color
45

6+
@Immutable
57
data class LocationMarkerColors(
68
val centerColor: Color,
79
val ringBorderColor: Color = Color.White,

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/data/MapConfig.kt

-16
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package net.mullvad.mullvadvpn.lib.map.data
22

3-
import net.mullvad.mullvadvpn.model.LatLong
3+
import androidx.compose.runtime.Immutable
44

5-
class MapViewState(val locationMarker: Marker?, val cameraPosition: CameraPosition)
6-
7-
data class CameraPosition(val latLong: LatLong, val zoom: Float, val bias: Float)
5+
@Immutable
6+
class MapViewState(
7+
val cameraPosition: CameraPosition,
8+
val locationMarker: List<Marker>,
9+
val globeColors: GlobeColors
10+
)
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package net.mullvad.mullvadvpn.lib.map.data
22

3+
import androidx.compose.runtime.Immutable
34
import net.mullvad.mullvadvpn.model.LatLong
45

5-
data class Marker(val latLong: LatLong, val type: MarkerType, val size: Float = 0.02f)
6-
7-
enum class MarkerType {
8-
SECURE,
9-
UNSECURE
10-
}
6+
@Immutable
7+
data class Marker(val latLong: LatLong, val size: Float = 0.02f, val colors: LocationMarkerColors)

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/internal/Constants.kt

+14
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ package net.mullvad.mullvadvpn.lib.map.internal
33
internal const val VERTEX_COMPONENT_SIZE = 3
44
internal const val COLOR_COMPONENT_SIZE = 4
55
internal const val MATRIX_SIZE = 16
6+
7+
// Constant what will talk the distance in LatLng multiply it to determine the animation duration,
8+
// the result is then confined to the MIN_ANIMATION_MILLIS and MAX_ANIMATION_MILLIS
9+
const val DISTANCE_DURATION_SCALE_FACTOR = 20
10+
const val MIN_ANIMATION_MILLIS = 1300
11+
const val MAX_ANIMATION_MILLIS = 2500
12+
// The cut off where we go from a short animation (camera pans) to a far animation (camera pans +
13+
// zoom out)
14+
const val SHORT_ANIMATION_CUTOFF_MILLIS = 1700
15+
16+
// Multiplier for the zoom out animation
17+
const val FAR_ANIMATION_MAX_ZOOM_MULTIPLIER = 1.30f
18+
// When in the far animation we reach the MAX_ZOOM_MULTIPLIER, value is between 0 and 1
19+
const val MAX_MULTIPLIER_PEAK_TIMING = .35f

android/lib/map/src/main/kotlin/net/mullvad/mullvadvpn/lib/map/internal/GLHelper.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,4 @@ internal fun newIdentityMatrix(): FloatArray =
105105

106106
internal fun Color.toFloatArray(): FloatArray {
107107
return floatArrayOf(red, green, blue, alpha)
108-
}
108+
}

0 commit comments

Comments
 (0)