diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3675825e..cd21467b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
, azimElev: Pair) {
+ val context = LocalContext.current
+ val view = LocalView.current
val radarColor = Color(0xFFDCDCDC)
val primaryColor = Color(0xFFFFE082)
val secondaryColor = Color(0xFFDC0000)
@@ -44,11 +59,77 @@ fun RadarViewCompose(item: OrbitalPos, items: List, azimElev: Pair(tween(1000))
val animScale = animTransition.animateFloat(16f, 64f, animSpec, label = "animScale")
+ val aimThreshold = 0.05f
val measurer = rememberTextMeasurer()
val sweepDegrees = remember { mutableFloatStateOf(0f) }
val trackCreated = remember { mutableStateOf(false) }
val trackPath = remember { mutableStateOf(Path()) }
val trackEffect = remember { mutableStateOf(PathEffect.cornerPathEffect(0f)) }
+ val soundPool = remember { mutableStateOf(null) }
+ val beepSoundId = remember { mutableIntStateOf(0) }
+ val aimTargetDifference = remember { mutableFloatStateOf(0f) }
+
+ LaunchedEffect(item.azimuth, item.elevation, azimElev.first, azimElev.second) {
+ val aimAzimuthRadians = azimElev.first.toDouble().toRadians()
+ val aimElevationRadians = abs(min(azimElev.second, 0f)).toDouble().toRadians()
+ // radius of 0.5 makes the aimTargetDifference range 0.0 to 1.0
+ val radius = 0.5
+ val aimX = sph2CartX(aimAzimuthRadians, aimElevationRadians, radius)
+ val aimY = sph2CartY(aimAzimuthRadians, aimElevationRadians, radius)
+ val satX = sph2CartX(item.azimuth, item.elevation, radius)
+ val satY = sph2CartY(item.azimuth, item.elevation, radius)
+ aimTargetDifference.floatValue = sqrt((satX - aimX).pow(2) + (satY - aimY).pow(2))
+
+
+ val minPlaybackRate = 0.5f
+ val maxPlaybackRate = 2.0f
+ val playbackRate =
+ maxPlaybackRate - (aimTargetDifference.floatValue / (maxPlaybackRate - minPlaybackRate))
+
+ soundPool.value?.setRate(beepSoundId.intValue, playbackRate)
+ }
+
+ LaunchedEffect(aimTargetDifference.floatValue < aimThreshold) {
+ if (aimTargetDifference.floatValue < aimThreshold) {
+ view.performHapticFeedback(HapticFeedbackConstantsCompat.VIRTUAL_KEY)
+ soundPool.value?.pause(beepSoundId.intValue)
+ } else {
+ soundPool.value?.resume(beepSoundId.intValue)
+ }
+ }
+
+ LaunchedEffect(item.elevation > 0) {
+ if(item.elevation > 0) {
+ soundPool.value?.resume(beepSoundId.intValue)
+ } else {
+ soundPool.value?.pause(beepSoundId.intValue)
+ }
+ }
+
+ DisposableEffect(Unit) {
+ val audioAttributes = AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build()
+
+ soundPool.value = SoundPool.Builder()
+ .setMaxStreams(1)
+ .setAudioAttributes(audioAttributes)
+ .build()
+
+ beepSoundId.intValue = soundPool.value?.load(context, R.raw.beep, 1) ?: 0
+
+ soundPool.value?.setOnLoadCompleteListener { soundPool, _, status ->
+ if (status == 0) {
+ soundPool.play(beepSoundId.intValue, 0.5f, 0.5f, 0, -1, 1f)
+ }
+ }
+
+ onDispose {
+ soundPool.value?.release()
+ }
+ }
+
Canvas(modifier = Modifier.fillMaxSize()) {
val radius = (size.minDimension / 2f) * 0.95f
if (!trackCreated.value) {
diff --git a/app/src/main/res/raw/beep.mp3 b/app/src/main/res/raw/beep.mp3
new file mode 100644
index 00000000..ed6a42ad
Binary files /dev/null and b/app/src/main/res/raw/beep.mp3 differ