Skip to content

Commit

Permalink
Small fix-ups to make callouts more like iOS
Browse files Browse the repository at this point in the history
- Remove distance from intersection description
- Add POI category earcons
  • Loading branch information
davecraig committed Feb 6, 2025
1 parent 0eacc20 commit 95c0bfe
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -405,5 +405,6 @@ class NativeAudioEngine @Inject constructor(): AudioEngine, TextToSpeech.OnInitL
const val EARCON_SENSE_MOBILITY = "file:///android_asset/earcons/sense_mobility.wav"
const val EARCON_SENSE_POI = "file:///android_asset/earcons/sense_poi.wav"
const val EARCON_SENSE_SAFETY = "file:///android_asset/earcons/sense_safety.wav"
const val EARCON_INFORMATION_ALERT = "file:///android_asset/earcons/information_alert.wav"
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package org.scottishtecharmy.soundscape.components

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material.icons.rounded.LocationOn
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
Expand All @@ -29,54 +29,83 @@ import org.scottishtecharmy.soundscape.ui.theme.Foreground2
import org.scottishtecharmy.soundscape.ui.theme.IntroductionTheme
import org.scottishtecharmy.soundscape.ui.theme.PaleBlue

data class EnabledFunction(
var enabled: Boolean = false,
var function: (String) -> Unit = {}
)
data class LocationItemDecoration(
val location: Boolean = false,
val addToRoute:EnabledFunction = EnabledFunction(),
val removeFromRoute:EnabledFunction = EnabledFunction()
)

@Composable
fun LocationItem(
item: LocationDescription,
onClick: () -> Unit,
modifier: Modifier = Modifier,
decoration: LocationItemDecoration = LocationItemDecoration(),
) {
Button(
onClick = onClick,
shape = RoundedCornerShape(0),
colors =
ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.tertiary,
),
Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
if(decoration.location) {
Icon(
Icons.Rounded.LocationOn,
contentDescription = null,
tint = Color.White,
)
Column(
modifier = Modifier.padding(start = 18.dp),
verticalArrangement = Arrangement.spacedBy(5.dp),
}
Column(
modifier = Modifier.padding(start = 18.dp),
verticalArrangement = Arrangement.spacedBy(5.dp),
) {
item.addressName?.let {
Text(
text = it,
fontWeight = FontWeight(700),
fontSize = 22.sp,
color = Color.White,
)
}
item.distance?.let {
Text(
text = it,
color = Foreground2,
fontWeight = FontWeight(450),
)
}
item.fullAddress?.let {
Text(
text = it,
fontWeight = FontWeight(400),
fontSize = 18.sp,
color = PaleBlue,
)
}
}
if(decoration.addToRoute.enabled or decoration.removeFromRoute.enabled) {
Button(
onClick = {
if(decoration.addToRoute.enabled) {
decoration.addToRoute.function(item.addressName!!)
} else if(decoration.removeFromRoute.enabled) {
decoration.removeFromRoute.function(item.addressName!!)
}
},
) {
item.addressName?.let {
Text(
text = it,
fontWeight = FontWeight(700),
fontSize = 22.sp,
color = Color.White,
if(decoration.addToRoute.enabled) {
Icon(
Icons.Rounded.Add,
contentDescription = null,
tint = Color.White,
)
}
item.distance?.let {
Text(
text = it,
color = Foreground2,
fontWeight = FontWeight(450),
)
}
item.fullAddress?.let {
Text(
text = it,
fontWeight = FontWeight(400),
fontSize = 18.sp,
color = PaleBlue,
} else if(decoration.removeFromRoute.enabled) {
Icon(
Icons.Rounded.Delete,
contentDescription = null,
tint = Color.Red,
)
}
}
Expand Down Expand Up @@ -106,7 +135,12 @@ fun PreviewSearchItemButton() {
LocationItem(
item = test,
onClick = {},
Modifier.width(200.dp),
decoration = LocationItemDecoration(
location = true,
addToRoute = EnabledFunction(true, {}),
removeFromRoute = EnabledFunction(false, {}),
),
modifier = Modifier.width(200.dp),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class GeoEngine {
autoCallout.updateLocation(getCurrentUserGeometry(UserGeometry.HeadingMode.Auto), gridState)
if (callouts.isNotEmpty()) {
// Tell the service that we've got some callouts to tell the user about
soundscapeService.speakCallout(callouts)
soundscapeService.speakCallout(callouts, false)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,14 @@ class AutoCallout(
userGeometry,
ComplexIntersectionApproach.NEAREST_NON_TRIVIAL_INTERSECTION)

// Don't describe the road we're on if there's an intersection
if(roadsDescription.intersection != null) roadsDescription.nearestRoad = null

addIntersectionCalloutFromDescription(roadsDescription,
localizedContext,
results,
intersectionCalloutHistory)
intersectionCalloutHistory
)

return results
}
Expand Down Expand Up @@ -133,11 +137,17 @@ class AutoCallout(
if (!uniquelyNamedPOIs.containsKey(name.text)) {
// Don't filter out
uniquelyNamedPOIs[name.text] = feature
val earcon = when(feature.foreign?.get("category")) {
"information" -> NativeAudioEngine.EARCON_INFORMATION_ALERT
"safety" -> NativeAudioEngine.EARCON_SENSE_SAFETY
"mobility" -> NativeAudioEngine.EARCON_SENSE_MOBILITY
else -> NativeAudioEngine.EARCON_SENSE_POI
}
results.add(
PositionedString(
name.text,
nearestPoint.point,
NativeAudioEngine.EARCON_SENSE_POI,
earcon
),
)
poiCalloutHistory.add(callout)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.scottishtecharmy.soundscape.geoengine.callouts

import android.content.Context
import org.scottishtecharmy.soundscape.R
import org.scottishtecharmy.soundscape.audio.NativeAudioEngine
import org.scottishtecharmy.soundscape.geoengine.TreeId
import org.scottishtecharmy.soundscape.geoengine.GridState
import org.scottishtecharmy.soundscape.geoengine.PositionedString
Expand Down Expand Up @@ -30,7 +31,7 @@ enum class ComplexIntersectionApproach {
NEAREST_NON_TRIVIAL_INTERSECTION
}

data class RoadsDescription(val nearestRoad: Feature? = null,
data class RoadsDescription(var nearestRoad: Feature? = null,
val userGeometry: UserGeometry = UserGeometry(),
val intersection: Feature? = null,
val intersectionRoads: FeatureCollection = FeatureCollection())
Expand Down Expand Up @@ -157,10 +158,9 @@ fun addIntersectionCalloutFromDescription(
) {

// Report nearby road
if(description.nearestRoad != null) {

if (description.nearestRoad.properties?.get("name") != null) {
val calloutText = "${localizedContext.getString(R.string.directions_direction_ahead)} ${description.nearestRoad.properties!!["name"]}"
description.nearestRoad?.let { nearestRoad ->
if (nearestRoad.properties?.get("name") != null) {
val calloutText = "${localizedContext.getString(R.string.directions_direction_ahead)} ${nearestRoad.properties!!["name"]}"
var skip = false
calloutHistory?.checkAndAdd(TrackedCallout(calloutText,
LngLatAlt(),
Expand All @@ -169,7 +169,10 @@ fun addIntersectionCalloutFromDescription(
))?.let { newCallout ->
if(!newCallout) skip = true
}
if(!skip) results.add(PositionedString(calloutText))
if(skip) {
} else {
results.add(PositionedString(calloutText))
}
} else {
// we are detecting an unnamed road here but pretending there is nothing here
results.add(
Expand Down Expand Up @@ -199,16 +202,12 @@ fun addIntersectionCalloutFromDescription(
if(!success) return
}

// Report distance to intersection
// Report intersection is coming up
results.add(
PositionedString(
"${localizedContext.getString(R.string.intersection_approaching_intersection)} ${
localizedContext.getString(
R.string.distance_format_meters,
description.userGeometry.location.distance(intersectionLocation).toInt().toString(),
)
}",
),
localizedContext.getString(R.string.intersection_approaching_intersection),
null,
NativeAudioEngine.EARCON_SENSE_POI)
)

// Report roads that join the intersection
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.scottishtecharmy.soundscape.screens.markers_routes.screens.markersscreen

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import org.scottishtecharmy.soundscape.components.LocationItem
import org.scottishtecharmy.soundscape.screens.home.locationDetails.generateLocationDetailsRoute
import org.scottishtecharmy.soundscape.screens.markers_routes.navigation.ScreensForMarkersAndRoutes

@Composable
fun MarkersEditList(
uiState: MarkersUiEditState,
navController: NavController,
) {
LazyColumn(
modifier = Modifier.fillMaxWidth().heightIn(max = 470.dp),
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
items(uiState.route) { locationDescription ->
LocationItem(
item = locationDescription,
onClick = {

},
)
}
items(uiState.markers) { locationDescription ->
LocationItem(
item = locationDescription,
onClick = {
},
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.scottishtecharmy.soundscape.screens.markers_routes.screens.markersscreen

import org.scottishtecharmy.soundscape.screens.home.data.LocationDescription

data class MarkersUiEditState(
val markers: List<LocationDescription> = emptyList(),
val route: List<LocationDescription> = emptyList(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ class SoundscapeService : MediaSessionService() {
coroutineScope.launch {
audioEngine.clearTextToSpeechQueue()
val results = geoEngine.myLocation()
speakCallout(results)
speakCallout(results, true)
}
}

Expand All @@ -355,15 +355,15 @@ class SoundscapeService : MediaSessionService() {
coroutineScope.launch {
audioEngine.clearTextToSpeechQueue()
val results = geoEngine.whatsAroundMe()
speakCallout(results)
speakCallout(results, true)
}
}

fun aheadOfMe() {
coroutineScope.launch {
audioEngine.clearTextToSpeechQueue()
val results = geoEngine.aheadOfMe()
speakCallout(results)
speakCallout(results, true)
}
}

Expand All @@ -387,8 +387,8 @@ class SoundscapeService : MediaSessionService() {
return (depth > 1)
}

fun speakCallout(callouts: List<PositionedString>) {
audioEngine.createEarcon(NativeAudioEngine.EARCON_MODE_ENTER)
fun speakCallout(callouts: List<PositionedString>, includeMode: Boolean = false) {
if(includeMode) audioEngine.createEarcon(NativeAudioEngine.EARCON_MODE_ENTER)
for(result in callouts) {
if(result.location == null) {
if(result.earcon != null) {
Expand All @@ -409,7 +409,7 @@ class SoundscapeService : MediaSessionService() {
)
}
}
audioEngine.createEarcon(NativeAudioEngine.EARCON_MODE_EXIT)
if(includeMode) audioEngine.createEarcon(NativeAudioEngine.EARCON_MODE_EXIT)
}

/**
Expand Down

0 comments on commit 95c0bfe

Please sign in to comment.