Compare commits

...

9 Commits

Author SHA1 Message Date
Kavish Devar 53679cc902 android: bump version
just doing this because play looks "version code up, let's update!" even if it's not installed from Play, and I can't make another rc1.
2026-09-01 00:13:05 +05:30
Kavish Devar b4cacb89f1 android: adjust pre-first connect text style in m3e 2026-08-27 15:50:48 +05:30
Kavish Devar cf6d226fca android: add demo to demo airpods name 2026-08-27 15:44:10 +05:30
Kavish Devar 4c7a3cb203 android: don't force connectionSuccessful to true in demo state 2026-08-27 15:41:02 +05:30
Kavish Devar 1783bb742e android: remove bypass when going back to 'not supported' page in onboarding 2026-08-27 15:29:43 +05:30
Kavish Devar 3cc4d92d62 android: bump version 2026-08-27 15:26:19 +05:30
Kavish Devar 95ecc0eb3d android: show bypassed message on settings page before first connect 2026-08-27 15:26:10 +05:30
Kavish Devar a7537f2361 android: make bypass compatibility check button scroll to next onboarding page 2026-08-27 15:24:52 +05:30
Kavish Devar 21babd819f android: hide reconnect button in m3e when no successful aacp connection 2026-08-27 15:16:28 +05:30
5 changed files with 109 additions and 79 deletions
@@ -736,96 +736,116 @@ fun AirPodsSettingsScreen(
val animatedShapeColor by animateColorAsState(if (reconnecting) primaryContainerColor else secondaryContainerColor) val animatedShapeColor by animateColorAsState(if (reconnecting) primaryContainerColor else secondaryContainerColor)
Box( if (state.connectionSuccessful) {
modifier = Modifier Box(
.size(240.dp) modifier = Modifier
.background( .size(240.dp)
MaterialTheme.colorScheme.surfaceBright, .background(
CircleShape MaterialTheme.colorScheme.surfaceBright,
) CircleShape
.clickable( )
interactionSource = null, .clickable(
indication = ripple( interactionSource = null,
bounded = false, indication = ripple(
radius = 120.dp bounded = false,
), radius = 120.dp
enabled = !reconnecting, ),
onClick = {} enabled = !reconnecting,
) onClick = {}
.pointerInput(Unit) { )
detectTapGestures( .pointerInput(Unit) {
onTap = { detectTapGestures(
if (!reconnecting) { onTap = {
currentMorphIndex = 1 if (!reconnecting) {
reconnecting = true currentMorphIndex = 1
reconnectFromSavedMac() reconnecting = true
} reconnectFromSavedMac()
}, }
onPress = { },
if (!reconnecting) { onPress = {
morphProgress.animateTo( if (!reconnecting) {
targetValue = 1f, morphProgress.animateTo(
animationSpec = spring( targetValue = 1f,
dampingRatio = Spring.DampingRatioMediumBouncy, animationSpec = spring(
stiffness = Spring.StiffnessLow dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
) )
) tryAwaitRelease()
tryAwaitRelease() morphProgress.animateTo(
morphProgress.animateTo( targetValue = 0f,
targetValue = 0f, animationSpec = spring(
animationSpec = spring( dampingRatio = Spring.DampingRatioMediumBouncy,
dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow
stiffness = Spring.StiffnessLow )
) )
) }
} }
} )
) }
} .drawWithContent {
.drawWithContent { val activeMorph = morphs[currentMorphIndex]
val activeMorph = morphs[currentMorphIndex]
val shapePath = activeMorph.toPath( val shapePath = activeMorph.toPath(
progress = morphProgress.value, progress = morphProgress.value,
path = path path = path
) )
val bounds = shapePath.getBounds() val bounds = shapePath.getBounds()
val scale = min(size.width/bounds.width, size.height/bounds.height) * 0.8f val scale = min(
size.width / bounds.width,
size.height / bounds.height
) * 0.8f
scaleMatrix.reset() scaleMatrix.reset()
scaleMatrix.scale(x = scale, y = scale) scaleMatrix.scale(x = scale, y = scale)
shapePath.transform(scaleMatrix) shapePath.transform(scaleMatrix)
shapePath.translate(size.center - shapePath.getBounds().center) shapePath.translate(size.center - shapePath.getBounds().center)
drawPath( drawPath(
path = shapePath, path = shapePath,
color = animatedShapeColor color = animatedShapeColor
) )
drawContent() drawContent()
}, },
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Icon( Icon(
imageVector = if (reconnecting) MaterialIcons.bluetooth_searching else MaterialIcons.headset_off, imageVector = if (reconnecting) MaterialIcons.bluetooth_searching else MaterialIcons.headset_off,
contentDescription = null, contentDescription = null,
modifier = Modifier.size(84.dp), modifier = Modifier.size(84.dp),
tint = if (reconnecting) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSecondaryContainer tint = if (reconnecting) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSecondaryContainer
)
}
Spacer(Modifier.height(40.dp))
Text(
text = if (reconnecting) stringResource(R.string.reconnecting) else stringResource(R.string.tap_to_reconnect),
style = MaterialTheme.typography.labelSmallEmphasized,
color = MaterialTheme.colorScheme.primary
) )
} else {
Text(
text = stringResource(R.string.airpods_not_connected),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary
)
if (sharedPreferences.getBoolean("bypass_device_check.v2", false)) {
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(R.string.compatibility_check_bypassed),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center
)
}
} }
Spacer(Modifier.height(40.dp))
Text(
text = if (reconnecting) stringResource(R.string.reconnecting) else stringResource(R.string.tap_to_reconnect),
style = MaterialTheme.typography.labelSmallEmphasized,
color = MaterialTheme.colorScheme.primary
)
} }
if (!BuildConfig.PLAY_BUILD) { if (!BuildConfig.PLAY_BUILD) {
@@ -47,6 +47,7 @@ import me.kavishdevar.librepods.presentation.theme.LibrePodsTheme
import me.kavishdevar.librepods.utils.XposedState import me.kavishdevar.librepods.utils.XposedState
import me.kavishdevar.librepods.utils.bypassDeviceCheck import me.kavishdevar.librepods.utils.bypassDeviceCheck
import me.kavishdevar.librepods.utils.isSupported import me.kavishdevar.librepods.utils.isSupported
import me.kavishdevar.librepods.utils.removeDeviceCheckBypass
@OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3Api::class) @OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -191,6 +192,9 @@ fun OnboardingScreen(
NotSupportedPage( NotSupportedPage(
bypassCompatibilityCheck = { bypassCompatibilityCheck = {
bypassDeviceCheck(sharedPreferences) bypassDeviceCheck(sharedPreferences)
animationScope.launch {
state.animateScrollToItem(3)
}
} }
) )
} }
@@ -199,6 +203,9 @@ fun OnboardingScreen(
onBackward = { onBackward = {
animationScope.launch { animationScope.launch {
if (state.canScrollBackward) state.animateScrollToItem(if (isSupported) 1 else 2) if (state.canScrollBackward) state.animateScrollToItem(if (isSupported) 1 else 2)
if (!isSupported) {
removeDeviceCheckBypass(sharedPreferences)
}
} }
}, },
onForward = onOnboardingComplete onForward = onOnboardingComplete
@@ -105,7 +105,7 @@ data class AirPodsUiState(
) )
val demoInstance = AirPodsInstance( val demoInstance = AirPodsInstance(
name = "AirPods Pro", name = "[DEMO] AirPods Pro",
model = AirPodsModels.getModelByModelNumber("A3064")!!, model = AirPodsModels.getModelByModelNumber("A3064")!!,
actualModelNumber = "A3064", actualModelNumber = "A3064",
serialNumber = "JXF9Q94A40", serialNumber = "JXF9Q94A40",
@@ -160,8 +160,6 @@ val demoState = AirPodsUiState(
dynamicEndOfCharge = true, dynamicEndOfCharge = true,
connectionSuccessful = true,
customEq = CustomEq(state = 2, low = 65, mid = 50, high = 70), customEq = CustomEq(state = 2, low = 65, mid = 50, high = 70),
controlStates = mapOf( controlStates = mapOf(
@@ -42,3 +42,7 @@ fun isSupported(sharedPreferences: SharedPreferences): Boolean {
fun bypassDeviceCheck(sharedPreferences: SharedPreferences) { fun bypassDeviceCheck(sharedPreferences: SharedPreferences) {
sharedPreferences.edit{ putBoolean("bypass_device_check.v2", true) } sharedPreferences.edit{ putBoolean("bypass_device_check.v2", true) }
} }
fun removeDeviceCheckBypass(sharedPreferences: SharedPreferences) {
sharedPreferences.edit{ putBoolean("bypass_device_check.v2", false) }
}
@@ -290,4 +290,5 @@
<string name="permissions">Permissions</string> <string name="permissions">Permissions</string>
<string name="privacy_policy">Privacy Policy</string> <string name="privacy_policy">Privacy Policy</string>
<string name="i_agree">I agree</string> <string name="i_agree">I agree</string>
<string name="compatibility_check_bypassed">Compatibility check bypassed. Are you sure your device is compatible?</string>
</resources> </resources>