Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ abstract class BaseVisualTest {
key
}

protected fun captureScreenshot(filename: String = "screenshot_${System.currentTimeMillis()}.png"): Bitmap {
protected fun captureScreenshot(
filename: String = "screenshot_${System.currentTimeMillis()}.png",
): Bitmap {
val screenshotFile = File(context.getExternalFilesDir(null), filename)
val screenshotTaken = uiDevice.takeScreenshot(screenshotFile)
assertTrue("Failed to take screenshot: $filename", screenshotTaken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,9 @@ class Maps3DVisualTest : BaseVisualTest() {

// Parse JSON and click
try {
val jsonStr = geminiResponse?.substringAfter("{")?.substringBeforeLast("}")?.let { "{$it}" } ?: ""
val jsonStr =
geminiResponse?.substringAfter("{")?.substringBeforeLast("}")?.let { "{$it}" }
?: ""
val json = org.json.JSONObject(jsonStr)
val x = json.getDouble("x")
val y = json.getDouble("y")
Expand All @@ -418,7 +420,9 @@ class Maps3DVisualTest : BaseVisualTest() {

uiDevice.click(clickX, clickY)
} catch (e: Exception) {
org.junit.Assert.fail("Failed to parse coordinates from Gemini response: $geminiResponse. Error: ${e.message}")
org.junit.Assert.fail(
"Failed to parse coordinates from Gemini response: $geminiResponse. Error: ${e.message}",
)
}

// Wait for UI to update
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,16 @@ fun CameraAnimationsScreen() {
}

// Helper extensions
suspend fun com.google.android.gms.maps3d.GoogleMap3D.awaitCameraAnimation() = suspendCancellableCoroutine { continuation ->
setCameraAnimationEndListener {
setCameraAnimationEndListener(null) // Cleanup
if (continuation.isActive) {
continuation.resume(Unit)
suspend fun com.google.android.gms.maps3d.GoogleMap3D.awaitCameraAnimation() =
suspendCancellableCoroutine { continuation ->
setCameraAnimationEndListener {
setCameraAnimationEndListener(null) // Cleanup
if (continuation.isActive) {
continuation.resume(Unit)
}
}
}

continuation.invokeOnCancellation {
setCameraAnimationEndListener(null)
continuation.invokeOnCancellation {
setCameraAnimationEndListener(null)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ fun MapInteractionsScreen() {
map3dInstance = instance
// Set up click listener directly on the instance
instance.setMap3DClickListener { location, placeId ->
Log.d("MapInteractionsActivity", "Map clicked at ${location.latitude}, ${location.longitude}")
Log.d(
"MapInteractionsActivity",
"Map clicked at ${location.latitude}, ${location.longitude}",
)
clickedInfo = if (placeId != null) {
"Clicked Place ID: $placeId\nAt: ${location.latitude}, ${location.longitude}"
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,16 @@ fun TiltScale(tilt: Float, modifier: Modifier = Modifier) {
)

if (isMajor) {
val measuredText = textMeasurer.measure(i.toString(), style = TextStyle(color = onPrimaryColor, fontSize = 12.sp))
val measuredText = textMeasurer.measure(
i.toString(),
style = TextStyle(color = onPrimaryColor, fontSize = 12.sp),
)
drawText(
textLayoutResult = measuredText,
topLeft = Offset(centerLineX + 20f, yPos - measuredText.size.height / 2f),
topLeft = Offset(
centerLineX + 20f,
yPos - measuredText.size.height / 2f,
),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.font.FontFamily
Expand Down Expand Up @@ -73,7 +76,9 @@ fun WhiskeyCompass(

showDegreeLabels: Boolean = true,
degreeLabelInterval: Int = 15,
degreeLabelTextStyle: TextStyle = MaterialTheme.typography.labelSmall.copy(textAlign = TextAlign.Center),
degreeLabelTextStyle: TextStyle = MaterialTheme.typography.labelSmall.copy(
textAlign = TextAlign.Center,
),
degreeLabelVerticalOffset: Dp = 4.dp,

showCardinalLabels: Boolean = true,
Expand Down Expand Up @@ -122,90 +127,32 @@ fun WhiskeyCompass(
) {
// Canvas 1: Scrolling Compass Strip (ticks, degree labels, cardinal labels)
Canvas(modifier = Modifier.matchParentSize()) {
val majorTickHeightPx = majorTickHeight.toPx()
val minorTickHeightPx = minorTickHeight.toPx()
val majorTickStrokeWidthPx = majorTickStrokeWidth.toPx()
val minorTickStrokeWidthPx = minorTickStrokeWidth.toPx()
val degreeLabelVerticalOffsetPx = degreeLabelVerticalOffset.toPx()
val cardinalLabelVerticalOffsetPx = cardinalLabelVerticalOffset.toPx()

val canvasWidth = size.width
val canvasCenterY = center.y
val params = CompassStripParams(
tickColor = tickColor,
majorTickHeightPx = majorTickHeight.toPx(),
minorTickHeightPx = minorTickHeight.toPx(),
majorTickStrokeWidthPx = majorTickStrokeWidth.toPx(),
minorTickStrokeWidthPx = minorTickStrokeWidth.toPx(),
showCardinalLabels = showCardinalLabels,
measuredCardinalLabels = measuredCardinalLabels,
cardinalLabelVerticalOffsetPx = cardinalLabelVerticalOffset.toPx(),
showDegreeLabels = showDegreeLabels,
degreeLabelInterval = degreeLabelInterval,
degreeLabelTextStyle = degreeLabelTextStyle,
degreeLabelVerticalOffsetPx = degreeLabelVerticalOffset.toPx(),
textMeasurer = textMeasurer,
)

val xOffset = center.x - (normalizedHeading * pixelsPerDegree)
val tickCenterY = canvasCenterY

translate(left = xOffset) {
for (repetition in -1..1) {
val repetitionBaseDegree = repetition * 360
for (degreeInRepetition in 0 until 360) {
val absoluteDegree = repetitionBaseDegree + degreeInRepetition
val xPos = absoluteDegree * pixelsPerDegree

if (xPos < -xOffset + canvasWidth + canvasWidth && xPos > -xOffset - canvasWidth) {
Comment thread
dkhawk marked this conversation as resolved.
val isMajorTickEquivalent = degreeInRepetition % 10 == 0
val isMinorTickEquivalent =
degreeInRepetition % 5 == 0 && !isMajorTickEquivalent

if (isMajorTickEquivalent) {
val tickTopY = tickCenterY - majorTickHeightPx / 2f
val tickBottomY = tickCenterY + majorTickHeightPx / 2f
drawLine(
color = tickColor,
start = Offset(x = xPos, y = tickTopY),
end = Offset(x = xPos, y = tickBottomY),
strokeWidth = majorTickStrokeWidthPx,
)

if (showCardinalLabels && measuredCardinalLabels.containsKey(
degreeInRepetition,
)
) {
val measuredText =
measuredCardinalLabels.getValue(degreeInRepetition)
drawText(
textLayoutResult = measuredText,
topLeft = Offset(
x = xPos - measuredText.size.width / 2f,
y = tickTopY - measuredText.size.height - cardinalLabelVerticalOffsetPx,
),
)
}
} else if (isMinorTickEquivalent) {
val tickTopY = tickCenterY - minorTickHeightPx / 2f
val tickBottomY = tickCenterY + minorTickHeightPx / 2f
drawLine(
color = tickColor,
start = Offset(x = xPos, y = tickTopY),
end = Offset(x = xPos, y = tickBottomY),
strokeWidth = minorTickStrokeWidthPx,
)
}

if (showDegreeLabels && degreeInRepetition % degreeLabelInterval == 0) {
val tickBottomY = tickCenterY + (
if (isMajorTickEquivalent) {
majorTickHeightPx
} else if (isMinorTickEquivalent) {
minorTickHeightPx
} else {
0f
}
) / 2f
val labelText = degreeInRepetition.toString()
val measuredText =
textMeasurer.measure(labelText, style = degreeLabelTextStyle)
drawText(
textLayoutResult = measuredText,
topLeft = Offset(
x = xPos - measuredText.size.width / 2f,
y = tickBottomY + degreeLabelVerticalOffsetPx,
),
)
}
}
}
}
drawCompassStrip(
params = params,
pixelsPerDegree = pixelsPerDegree,
xOffset = xOffset,
canvasWidth = size.width,
tickCenterY = center.y,
)
}
}

Expand All @@ -223,6 +170,139 @@ fun WhiskeyCompass(
}
}

private data class CompassStripParams(
val tickColor: Color,
val majorTickHeightPx: Float,
val minorTickHeightPx: Float,
val majorTickStrokeWidthPx: Float,
val minorTickStrokeWidthPx: Float,
val showCardinalLabels: Boolean,
val measuredCardinalLabels: Map<Int, TextLayoutResult>,
val cardinalLabelVerticalOffsetPx: Float,
val showDegreeLabels: Boolean,
val degreeLabelInterval: Int,
val degreeLabelTextStyle: TextStyle,
val degreeLabelVerticalOffsetPx: Float,
val textMeasurer: TextMeasurer,
)

private fun DrawScope.drawCompassStrip(
params: CompassStripParams,
pixelsPerDegree: Float,
xOffset: Float,
canvasWidth: Float,
tickCenterY: Float,
) {
for (repetition in -1..1) {
val repetitionBaseDegree = repetition * 360
for (degreeInRepetition in 0 until 360) {
val absoluteDegree = repetitionBaseDegree + degreeInRepetition
val xPos = absoluteDegree * pixelsPerDegree

if (xPos < -xOffset + 2 * canvasWidth && xPos > -xOffset - canvasWidth) {
drawDegreeTick(
degree = degreeInRepetition,
xPos = xPos,
tickCenterY = tickCenterY,
params = params,
)
}
}
}
}

private fun DrawScope.drawDegreeTick(
degree: Int,
xPos: Float,
tickCenterY: Float,
params: CompassStripParams,
) {
val isMajorTickEquivalent = degree % 10 == 0
val isMinorTickEquivalent = degree % 5 == 0 && !isMajorTickEquivalent

if (isMajorTickEquivalent) {
val tickTopY = tickCenterY - params.majorTickHeightPx / 2f
val tickBottomY = tickCenterY + params.majorTickHeightPx / 2f
drawLine(
color = params.tickColor,
start = Offset(x = xPos, y = tickTopY),
end = Offset(x = xPos, y = tickBottomY),
strokeWidth = params.majorTickStrokeWidthPx,
)

if (params.showCardinalLabels && params.measuredCardinalLabels.containsKey(degree)) {
val measuredText = params.measuredCardinalLabels.getValue(degree)
drawCardinalLabel(
xPos = xPos,
tickTopY = tickTopY,
measuredText = measuredText,
verticalOffsetPx = params.cardinalLabelVerticalOffsetPx,
)
}
} else if (isMinorTickEquivalent) {
val tickTopY = tickCenterY - params.minorTickHeightPx / 2f
val tickBottomY = tickCenterY + params.minorTickHeightPx / 2f
drawLine(
color = params.tickColor,
start = Offset(x = xPos, y = tickTopY),
end = Offset(x = xPos, y = tickBottomY),
strokeWidth = params.minorTickStrokeWidthPx,
)
}

if (params.showDegreeLabels && degree % params.degreeLabelInterval == 0) {
val tickHeightPx = when {
isMajorTickEquivalent -> params.majorTickHeightPx
isMinorTickEquivalent -> params.minorTickHeightPx
else -> 0f
}
val tickBottomY = tickCenterY + tickHeightPx / 2f
val labelText = degree.toString()
val measuredText = params.textMeasurer.measure(
labelText,
style = params.degreeLabelTextStyle,
)
drawDegreeLabel(
xPos = xPos,
tickBottomY = tickBottomY,
measuredText = measuredText,
verticalOffsetPx = params.degreeLabelVerticalOffsetPx,
)
}
}

private fun DrawScope.drawCardinalLabel(
xPos: Float,
tickTopY: Float,
measuredText: TextLayoutResult,
verticalOffsetPx: Float,
) {
val labelTopY = tickTopY - measuredText.size.height - verticalOffsetPx
drawText(
textLayoutResult = measuredText,
topLeft = Offset(
x = xPos - measuredText.size.width / 2f,
y = labelTopY,
),
)
}

private fun DrawScope.drawDegreeLabel(
xPos: Float,
tickBottomY: Float,
measuredText: TextLayoutResult,
verticalOffsetPx: Float,
) {
val labelTopY = tickBottomY + verticalOffsetPx
drawText(
textLayoutResult = measuredText,
topLeft = Offset(
x = xPos - measuredText.size.width / 2f,
y = labelTopY,
),
)
}

@Preview(showBackground = true, backgroundColor = 0xFF222222)
@Composable
private fun FlatWhiskeyCompassPreview() {
Expand Down Expand Up @@ -272,7 +352,9 @@ private fun FlatWhiskeyCompassPreview() {
lubberLineColor = Color(0xFFFFD600),
pixelsPerDegree = 12f,
degreeLabelInterval = 10,
degreeLabelTextStyle = MaterialTheme.typography.bodySmall.copy(color = Color(0xFF81D4FA)),
degreeLabelTextStyle = MaterialTheme.typography.bodySmall.copy(
color = Color(0xFF81D4FA),
),
cardinalLabelTextStyle = MaterialTheme.typography.labelLarge.copy(
color = Color.White,
fontWeight = FontWeight.Bold,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ fun GoogleMap3D(
minTilt = 0.0,
maxTilt = 90.0,
bounds = null,
mapMode = Map3DMode.SATELLITE, // using the class from com.google.android.gms.maps3d.model.Map3DMode
// Using Map3DMode constant
mapMode = Map3DMode.SATELLITE,
mapId = null,
minAltitude = 0.0,
maxAltitude = 1000000.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ sealed class CameraUpdate {

fun FlyToOptions.toCameraUpdate(): CameraUpdate = CameraUpdate.FlyTo(this.toValidFlyToOptions())

fun FlyAroundOptions.toCameraUpdate(): CameraUpdate = CameraUpdate.FlyAround(this.toValidFlyAroundOptions())
fun FlyAroundOptions.toCameraUpdate(): CameraUpdate =
CameraUpdate.FlyAround(this.toValidFlyAroundOptions())

fun FlyToOptions.toValidFlyToOptions(): FlyToOptions = this.copy(
endCamera = this.endCamera.toValidCamera(),
Expand Down
Loading
Loading