Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
30b3f57
Update MapsScreen.kt
ChrisRoe2004 Mar 10, 2026
e19465d
Update UserPreferencesRepository.kt
ChrisRoe2004 Mar 24, 2026
bbf07d8
Update UserPreferencesRepository.kt
ChrisRoe2004 Mar 24, 2026
49e304b
Update UserPreferencesRepository.kt
ChrisRoe2004 Mar 24, 2026
5d67d7b
Update UserPreferencesRepository.kt
ChrisRoe2004 Mar 24, 2026
b1763d3
Update MapsViewModel.kt
ChrisRoe2004 Mar 27, 2026
6ad4242
Update MapsViewModel.kt
ChrisRoe2004 Mar 27, 2026
f9716e7
Update MapsViewModel.kt
ChrisRoe2004 Mar 27, 2026
9fa16ae
Update MapsScreen.kt
ChrisRoe2004 Mar 27, 2026
e3b1b61
Update MapsScreen.kt
ChrisRoe2004 Mar 27, 2026
62d233a
Update MapsScreen.kt
ChrisRoe2004 Mar 27, 2026
f023677
Update SettingsScreen.kt
ChrisRoe2004 Mar 27, 2026
5904612
Update SettingsScreen.kt
ChrisRoe2004 Mar 27, 2026
4c00494
Update SettingsScreen.kt
ChrisRoe2004 Mar 27, 2026
5e9b6d3
Update SettingsScreen.kt
ChrisRoe2004 Mar 27, 2026
a34ba65
Update SettingsScreen.kt
ChrisRoe2004 Mar 27, 2026
19a415e
Update VehicleLocation.kt
ChrisRoe2004 Apr 10, 2026
0e24b3d
Update UserPreferencesRepository.kt
ChrisRoe2004 Apr 10, 2026
37e7f00
Update UserPreferencesRepository.kt
ChrisRoe2004 Apr 10, 2026
87c0350
Update UserPreferencesRepository.kt
ChrisRoe2004 Apr 10, 2026
885161a
Update MapsViewModel.kt
ChrisRoe2004 Apr 10, 2026
dd7ab96
Update MapsViewModel.kt
ChrisRoe2004 Apr 10, 2026
51de378
Update MapsViewModel.kt
ChrisRoe2004 Apr 10, 2026
5689c9d
Update MapsScreen.kt
ChrisRoe2004 Apr 10, 2026
cef1ec7
Update MapsScreen.kt
ChrisRoe2004 Apr 10, 2026
01c5a4d
Update MapsScreen.kt
ChrisRoe2004 Apr 10, 2026
a9144d0
Update MapsScreen.kt
ChrisRoe2004 Apr 10, 2026
80c1f4c
Update DevMenuScreen.kt
ChrisRoe2004 Apr 10, 2026
1182d7c
Update DevMenuScreen.kt
ChrisRoe2004 Apr 10, 2026
82431dc
Update DevMenuScreen.kt
ChrisRoe2004 Apr 10, 2026
efd0056
Merge main
bryantran24 Apr 24, 2026
528eb00
Move options to settings
bryantran24 Apr 24, 2026
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 @@ -20,6 +20,7 @@ data class Vehicle(
val longitude: Double,
val speedMph: Double,
val timestamp: String,
val headingDegrees: Int?,
// from velocities
val routeName: String?,
val isAtStop: Boolean?,
Expand Down Expand Up @@ -70,6 +71,7 @@ data class VehicleLocation(
val longitude: Double,
@SerializedName("speed_mph") val speedMph: Double,
val timestamp: String,
@SerializedName("heading_degrees") val headingDegrees: Int?,
)

data class VehicleStopEta(
Expand Down Expand Up @@ -101,6 +103,7 @@ object VehicleMerger {
longitude = location.longitude,
speedMph = location.speedMph,
timestamp = location.timestamp,
headingDegrees = location.headingDegrees,
routeName = velocity?.routeName,
isAtStop = velocity?.isAtStop,
currentStop = velocity?.currentStop,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class UserPreferencesRepository
private val DEV_OPTIONS_ACTIVE = booleanPreferencesKey("dev_options_active")
private val THEME_MODE = stringPreferencesKey("theme_mode")
private val MAP_TYPE = stringPreferencesKey("map_type")
private val SHUTTLE_ANIMATIONS = booleanPreferencesKey("shuttle-animations")
private val SHUTTLE_ROTATION = booleanPreferencesKey("shuttle_rotation")
}

suspend fun getUserId(): String =
Expand Down Expand Up @@ -198,4 +200,27 @@ class UserPreferencesRepository
}
}
}

fun getShuttleAnimations(): Flow<Boolean> =
dataStore.data.map {
it[SHUTTLE_ANIMATIONS]
?: false
}

suspend fun saveShuttleAnimations(animationsEnable: Boolean) {
dataStore.edit {
it[SHUTTLE_ANIMATIONS] = animationsEnable
}
}

fun getShuttleRotation(): Flow<Boolean> =
dataStore.data.map {
it[SHUTTLE_ROTATION] ?: true
}

suspend fun saveShuttleRotations(rotationsEnable: Boolean) {
dataStore.edit {
it[SHUTTLE_ROTATION] = rotationsEnable
}
}
}
51 changes: 45 additions & 6 deletions app/src/main/java/edu/rpi/shuttletracker/ui/maps/MapsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package edu.rpi.shuttletracker.ui.maps
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand Down Expand Up @@ -206,6 +208,8 @@ private fun ShuttleMap(
mapsUiState.vehicles.forEach { vehicle ->
VehicleMarker(
vehicle = vehicle,
animationsEnabled = mapsUiState.shuttleAnimationsEnabled,
rotationEnabled = mapsUiState.shuttleRotationEnabled,
)
}

Expand Down Expand Up @@ -310,13 +314,47 @@ private fun StopMarker(
}

@Composable
private fun VehicleMarker(vehicle: Vehicle) {
private fun VehicleMarker(
vehicle: Vehicle,
animationsEnabled: Boolean,
rotationEnabled: Boolean,
) {
val context = LocalContext.current
val markerState = rememberUpdatedMarkerState(position = vehicle.latLng())
val target = vehicle.latLng()
val heading = vehicle.headingDegrees?.toFloat() ?: 0f

val lat = remember { Animatable(target.latitude.toFloat()) }
val lng = remember { Animatable(target.longitude.toFloat()) }

val markerState =
rememberUpdatedMarkerState(
position = LatLng(lat.value.toDouble(), lng.value.toDouble()),
)

// Animate movement
LaunchedEffect(target, animationsEnabled) {
if (animationsEnabled) {
launch {
lat.animateTo(
target.latitude.toFloat(),
animationSpec = tween(durationMillis = 2000),
)
}
launch {
lng.animateTo(
target.longitude.toFloat(),
animationSpec = tween(durationMillis = 2000),
)
}
} else {
lat.snapTo(target.latitude.toFloat())
lng.snapTo(target.longitude.toFloat())
}
}

// every time the vehicle changes, update the position of the marker
LaunchedEffect(vehicle) {
markerState.position = vehicle.latLng()
// Update marker position when animation values change
LaunchedEffect(lat.value, lng.value) {
markerState.position = LatLng(lat.value.toDouble(), lng.value.toDouble())
}

val resolvedColor =
Expand Down Expand Up @@ -346,7 +384,6 @@ private fun VehicleMarker(vehicle: Vehicle) {
getVehicleMarkerDescriptor(context, 25f, finalColor.toArgb())
}

// gets vehicle speed and last time it updated
val timeAgoFlow = remember(vehicle.timestamp) { vehicle.getTimeAgo() }
val lastUpdatedAgoText =
timeAgoFlow.collectAsStateWithLifecycle(initialValue = "").value
Expand All @@ -367,6 +404,8 @@ private fun VehicleMarker(vehicle: Vehicle) {
snippet = snippetText,
anchor = Offset(0.5f, 0.5f),
zIndex = 3f,
rotation = if (rotationEnabled) heading else 0f,
flat = rotationEnabled,
onClick = {
it.showInfoWindow()
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import javax.inject.Inject

@HiltViewModel
class MapsViewModel
// represents the ui state of the view
// represents the ui state of the view
@Inject
constructor(
private val apiRepository: ApiRepository,
Expand Down Expand Up @@ -135,6 +135,24 @@ class MapsViewModel
it.copy(mapType = mapType)
}
}.launchIn(viewModelScope)

userPreferencesRepository
.getShuttleAnimations()
.flowOn(Dispatchers.Default)
.onEach { animationsEnable ->
_mapsUiState.update {
it.copy(shuttleAnimationsEnabled = animationsEnable)
}
}.launchIn(viewModelScope)

userPreferencesRepository
.getShuttleRotation()
.flowOn(Dispatchers.Default)
.onEach { rotationEnable ->
_mapsUiState.update {
it.copy(shuttleRotationEnabled = rotationEnable)
}
}.launchIn(viewModelScope)
}

fun updateMapType(mapType: MapType) {
Expand All @@ -157,6 +175,21 @@ class MapsViewModel
updateMapType(next)
}

fun setShuttleAnimations(animationsEnable: Boolean) {
viewModelScope.launch {
userPreferencesRepository.saveShuttleAnimations(animationsEnable)
}
}

fun setShuttleRotation(rotationEnable: Boolean) {
viewModelScope.launch {
userPreferencesRepository.saveShuttleRotations(rotationEnable)
}
}

/**
* Reads the network response and maps it to correct place
* */
private fun <T> readApiResponse(
response: NetworkResponse<T, ErrorResponse>,
success: (body: T) -> Unit,
Expand Down Expand Up @@ -193,4 +226,6 @@ data class MapsUiState(
val totalAnnouncements: Int = -1,
val themeMode: ThemeMode = ThemeMode.System,
val mapType: MapType = MapType.NORMAL,
val shuttleAnimationsEnabled: Boolean = false,
val shuttleRotationEnabled: Boolean = true,
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.Contrast
import androidx.compose.material.icons.outlined.DirectionsBus
import androidx.compose.material.icons.outlined.Explore
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.RestartAlt
import androidx.compose.material.icons.outlined.Settings
Expand All @@ -24,6 +26,7 @@ import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
Expand Down Expand Up @@ -101,6 +104,32 @@ fun SettingsScreen(
)
}

item {
SettingsItem(
icon = Icons.Outlined.Explore,
title = stringResource(R.string.rotation),
description = stringResource(R.string.rotation_description),
) {
Switch(
checked = settingsUiState.rotationEnabled,
onCheckedChange = { viewModel.updateShuttleRotation(it) },
)
}
}

item {
SettingsItem(
icon = Icons.Outlined.DirectionsBus,
title = stringResource(R.string.animation),
description = stringResource(R.string.animation_description),
) {
Switch(
checked = settingsUiState.animationsEnabled,
onCheckedChange = { viewModel.updateShuttleAnimations(it) },
)
}
}

item {
SettingsItem(
Icons.Outlined.RestartAlt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ class SettingsViewModel
userPreferencesRepository.getColorBlindMode(),
userPreferencesRepository.getDevOptions(),
userPreferencesRepository.getThemeMode(),
) { colorBindMode, devOptionState, themeMode ->
userPreferencesRepository.getShuttleAnimations(),
userPreferencesRepository.getShuttleRotation(),
) { colorBindMode, devOptionState, themeMode, animationsEnabled, rotationEnabled ->
return@combine SettingsUiState(
colorBlindMode = colorBindMode,
devOptionState = devOptionState,
themeMode = themeMode,
animationsEnabled = animationsEnabled,
rotationEnabled = rotationEnabled,
)
}.stateIn(
scope = viewModelScope,
Expand All @@ -47,6 +51,18 @@ class SettingsViewModel
}
}

fun updateShuttleAnimations(enabled: Boolean) {
viewModelScope.launch {
userPreferencesRepository.saveShuttleAnimations(enabled)
}
}

fun updateShuttleRotation(enabled: Boolean) {
viewModelScope.launch {
userPreferencesRepository.saveShuttleRotations(enabled)
}
}

fun clearAllPreferences() =
viewModelScope.launch {
userPreferencesRepository.clearAllPreferences()
Expand All @@ -58,4 +74,6 @@ data class SettingsUiState(
val colorBlindMode: Boolean = false,
val devOptionState: Boolean = false,
val themeMode: ThemeMode = ThemeMode.System,
val animationsEnabled: Boolean = false,
val rotationEnabled: Boolean = true,
)
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,6 @@ fun DevMenuScreen(
})
}

// MinStopDistItem(
// maxStopDist = devMenuUiState.maxStopDist,
// updateMaxStopDist = viewModel::updateMinStopDist,
// )

BaseUrlSettingItem(
currentUrl = devMenuUiState.baseUrl,
updateBaseUrl = viewModel::updateBaseUrl,
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@
<string name="app_theme">App Theme</string>
<string name="redo_setup">Redo Setup</string>
<string name="open_app_settings">Open app settings</string>
<string name="rotation">Shuttle Rotation</string>
<string name="rotation_description">Show vehicle direction</string>
<string name="animation">Shuttle Animation</string>
<string name="animation_description">Smooth movement</string>

<!-- Analytics -->
<string name="analytics">Analytics</string>
Expand Down
Loading