From 217d9be1776e2273021e01b8210db6f98aee7553 Mon Sep 17 00:00:00 2001 From: darken Date: Mon, 23 Mar 2026 13:46:03 +0100 Subject: [PATCH] fix: Show key icon for single-pod devices when encryption keys are set --- .../compose/preview/MockPodDataProvider.kt | 44 ++++++++++++++++++- .../main/ui/overview/cards/SinglePodsCard.kt | 27 +++++++++--- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/darken/capod/common/compose/preview/MockPodDataProvider.kt b/app/src/main/java/eu/darken/capod/common/compose/preview/MockPodDataProvider.kt index da370ace..6c209675 100644 --- a/app/src/main/java/eu/darken/capod/common/compose/preview/MockPodDataProvider.kt +++ b/app/src/main/java/eu/darken/capod/common/compose/preview/MockPodDataProvider.kt @@ -15,6 +15,8 @@ import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.SinglePodDevice import eu.darken.capod.pods.core.unknown.UnknownDevice import eu.darken.capod.profiles.core.AppleDeviceProfile +import eu.darken.capod.pods.core.apple.ApplePods +import eu.darken.capod.pods.core.apple.protocol.ProximityPayload import eu.darken.capod.profiles.core.DeviceProfile import java.time.Instant @@ -114,11 +116,13 @@ object MockPodDataProvider { _isBeingWorn = true, ) - fun airPodsMaxCharging(): SinglePodDevice = MockSinglePodDevice( + fun airPodsMaxCharging(): SinglePodDevice = MockSingleApplePodDevice( _model = PodDevice.Model.AIRPODS_MAX, _label = "AirPods Max", batteryHeadsetPercent = 0.40f, _isHeadsetBeingCharged = true, + _isIRKMatch = true, + _hasPrivatePayload = true, ) fun beatsSolo3(): SinglePodDevice = MockSinglePodDevice( @@ -273,3 +277,41 @@ private class MockSinglePodDevice( // HasEarDetection override val isBeingWorn: Boolean = _isBeingWorn } + +@Suppress("PropertyName") +private class MockSingleApplePodDevice( + private val _model: PodDevice.Model, + private val _label: String, + override val batteryHeadsetPercent: Float?, + private val _isHeadsetBeingCharged: Boolean = false, + private val _isBeingWorn: Boolean = false, + private val _isIRKMatch: Boolean = false, + private val _hasPrivatePayload: Boolean = false, + rssi: Int = -50, +) : SinglePodDevice, ApplePods, HasChargeDetection, HasEarDetection { + override val identifier: PodDevice.Id = PodDevice.Id() + override val model: PodDevice.Model = _model + override val seenLastAt: Instant = MOCK_NOW + override val seenFirstAt: Instant = MOCK_NOW + override val seenCounter: Int = 5 + override val scanResult: BleScanResult = MockPodDataProvider.dummyScanResult(rssi) + override val reliability: Float = 1.0f + override val signalQuality: Float = 0.80f + override val iconRes: Int = _model.iconRes + override val meta: ApplePods.AppleMeta = ApplePods.AppleMeta( + isIRKMatch = _isIRKMatch, + profile = AppleDeviceProfile(label = _label, model = _model), + ) + override val payload: ProximityPayload = ProximityPayload( + public = ProximityPayload.Public(UByteArray(9)), + private = if (_hasPrivatePayload) ProximityPayload.Private(UByteArray(8)) else null, + ) + + override fun getLabel(context: Context): String = _model.label + + // HasChargeDetection + override val isHeadsetBeingCharged: Boolean = _isHeadsetBeingCharged + + // HasEarDetection + override val isBeingWorn: Boolean = _isBeingWorn +} diff --git a/app/src/main/java/eu/darken/capod/main/ui/overview/cards/SinglePodsCard.kt b/app/src/main/java/eu/darken/capod/main/ui/overview/cards/SinglePodsCard.kt index c98ce461..f9f16ad7 100644 --- a/app/src/main/java/eu/darken/capod/main/ui/overview/cards/SinglePodsCard.kt +++ b/app/src/main/java/eu/darken/capod/main/ui/overview/cards/SinglePodsCard.kt @@ -19,9 +19,12 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Key import androidx.compose.material.icons.twotone.BatteryChargingFull import androidx.compose.material.icons.twotone.Hearing +import androidx.compose.material.icons.twotone.Key import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ElevatedCard import androidx.compose.material3.MaterialTheme @@ -44,6 +47,7 @@ import eu.darken.capod.common.compose.preview.MockPodDataProvider import eu.darken.capod.pods.core.HasChargeDetection import eu.darken.capod.pods.core.HasEarDetection import eu.darken.capod.pods.core.SinglePodDevice +import eu.darken.capod.pods.core.apple.ApplePods import eu.darken.capod.pods.core.firstSeenFormatted import eu.darken.capod.pods.core.formatBatteryPercent import eu.darken.capod.pods.core.getSignalQuality @@ -98,12 +102,23 @@ fun SinglePodsCard( Spacer(modifier = Modifier.width(12.dp)) Column(modifier = Modifier.weight(1f)) { - Text( - text = device.meta.profile?.label ?: "?", - style = MaterialTheme.typography.titleMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = device.meta.profile?.label ?: "?", + style = MaterialTheme.typography.titleMedium, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + if (device is ApplePods && device.meta.isIRKMatch) { + Spacer(modifier = Modifier.width(6.dp)) + Icon( + imageVector = if (device.payload.private != null) Icons.TwoTone.Key else Icons.Outlined.Key, + contentDescription = null, + modifier = Modifier.size(14.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + } Text( text = device.getLabel(context), style = MaterialTheme.typography.bodySmall,