Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
android:name=".services.AirPodsQSService"
android:exported="true"
android:icon="@drawable/airpods"
android:label="ANC Mode"
android:label="@string/anc_mode"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package me.kavishdevar.librepods

import androidx.compose.ui.res.stringResource
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.ComponentName
Expand Down Expand Up @@ -428,7 +429,7 @@ fun NewControlCenterDialogContent(
) {
Icon(
painter = painterResource(id = R.drawable.airpods),
contentDescription = "Device Icon",
contentDescription = stringResource(R.string.device_icon),
tint = textColor.copy(alpha = 0.8f),
modifier = Modifier.size(48.dp)
)
Expand Down Expand Up @@ -588,7 +589,7 @@ fun NewControlCenterDialogContent(
) {
Icon(
painter = painterResource(id = R.drawable.airpods),
contentDescription = "Conversational Awareness",
contentDescription = stringResource(R.string.conversational_awareness),
tint = Color.White,
modifier = Modifier.size(32.dp)
)
Expand All @@ -597,7 +598,7 @@ fun NewControlCenterDialogContent(
Spacer(modifier = Modifier.height(8.dp))

Text(
text = "Conversational\nAwareness",
text = stringResource(R.string.conversational_awareness),
color = Color.White,
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
Expand All @@ -613,7 +614,7 @@ fun NewControlCenterDialogContent(
} else {
Spacer(modifier = Modifier.weight(1f))
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
Text("Loading...", color = textColor)
Text(stringResource(R.string.loading), color = textColor)
}
Spacer(modifier = Modifier.weight(1f))
}
Expand All @@ -629,11 +630,12 @@ private fun getModeIconRes(mode: NoiseControlMode): Int {
}
}

@Composable
private fun getModeLabel(mode: NoiseControlMode): String {
return when (mode) {
NoiseControlMode.OFF -> "Off"
NoiseControlMode.TRANSPARENCY -> "Transparency"
NoiseControlMode.ADAPTIVE -> "Adaptive"
NoiseControlMode.NOISE_CANCELLATION -> "Noise Cancel"
NoiseControlMode.OFF -> stringResource(R.string.off)
NoiseControlMode.TRANSPARENCY -> stringResource(R.string.transparency)
NoiseControlMode.ADAPTIVE -> stringResource(R.string.adaptive)
NoiseControlMode.NOISE_CANCELLATION -> stringResource(R.string.noise_cancellation)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ package me.kavishdevar.librepods.billing
import android.app.Activity
import kotlinx.coroutines.flow.StateFlow

/** Internal price states; UI resolves them in the current locale. */
const val PRICE_LOADING = "__price_loading__"
const val PRICE_UNAVAILABLE = "__price_unavailable__"

interface BillingProvider {
val isPremium: StateFlow<Boolean>
val price: StateFlow<String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class PlayBillingProvider(
private val _isPremium = MutableStateFlow(false)
override val isPremium: StateFlow<Boolean> = _isPremium

private val _price = MutableStateFlow("unknown")
private val _price = MutableStateFlow(PRICE_LOADING)
override val price: StateFlow<String> = _price


Expand All @@ -81,6 +81,7 @@ class PlayBillingProvider(
queryExistingPurchases()
}
} else {
_price.value = PRICE_UNAVAILABLE
Log.w(TAG, "Billing setup failed: ${result.debugMessage}")
}
}
Expand Down Expand Up @@ -112,8 +113,11 @@ class PlayBillingProvider(

if (priceString != null) {
_price.value = priceString
} else {
_price.value = PRICE_UNAVAILABLE
}
} else {
_price.value = PRICE_UNAVAILABLE
Log.w(TAG, "queryProductDetails failed: ${result.billingResult.debugMessage}")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package me.kavishdevar.librepods.presentation.components

import androidx.compose.ui.res.stringResource
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.spring
Expand Down Expand Up @@ -231,12 +232,13 @@ private fun getModeIconRes(mode: NoiseControlMode): Int {
}
}

@Composable
private fun getModeLabel(mode: NoiseControlMode): String {
return when (mode) {
NoiseControlMode.OFF -> "Off"
NoiseControlMode.TRANSPARENCY -> "Transparency"
NoiseControlMode.ADAPTIVE -> "Adaptive"
NoiseControlMode.NOISE_CANCELLATION -> "Noise Cancellation"
NoiseControlMode.OFF -> stringResource(R.string.off)
NoiseControlMode.TRANSPARENCY -> stringResource(R.string.transparency)
NoiseControlMode.ADAPTIVE -> stringResource(R.string.adaptive)
NoiseControlMode.NOISE_CANCELLATION -> stringResource(R.string.noise_cancellation)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ fun PressAndHoldSettings(
) {
val leftActionText = when (leftAction) {
StemAction.CYCLE_NOISE_CONTROL_MODES -> stringResource(R.string.noise_control)
StemAction.DIGITAL_ASSISTANT -> "Digital Assistant"
StemAction.DIGITAL_ASSISTANT -> stringResource(R.string.digital_assistant)
else -> "INVALID!!"
}

val rightActionText = when (rightAction) {
StemAction.CYCLE_NOISE_CONTROL_MODES -> stringResource(R.string.noise_control)
StemAction.DIGITAL_ASSISTANT -> "Digital Assistant"
StemAction.DIGITAL_ASSISTANT -> stringResource(R.string.digital_assistant)
else -> "INVALID!!"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fun NavigationRoot(
) {
Icon(
imageVector = Icons.Outlined.Settings,
contentDescription = "settings",
contentDescription = stringResource(R.string.settings),
modifier = Modifier.size(IconButtonDefaults.mediumIconSize)
)
}
Expand All @@ -115,7 +115,7 @@ fun NavigationRoot(
) {
Icon(
imageVector = if (state.headTrackingActive) MaterialIcons.pause else Icons.Default.PlayArrow,
contentDescription = "Play/Pause",
contentDescription = stringResource(R.string.play_pause),
modifier = Modifier.size(IconButtonDefaults.mediumIconSize)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,10 @@ fun AirPodsSettingsScreen(
val emailIntent = Intent(Intent.ACTION_SENDTO).apply {
data = "mailto:".toUri()
putExtra(Intent.EXTRA_EMAIL, arrayOf("billing@kavish.xyz"))
putExtra(Intent.EXTRA_SUBJECT, "LibrePods Play billing error")
putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.billing_error_email_subject))
putExtra(
Intent.EXTRA_TEXT,
"Please enter your GitHub username to restore your premium access:\n\nGitHub username: "
context.getString(R.string.billing_error_email_body)
)
}
context.startActivity(emailIntent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ fun AppSettingsScreen(
val emailIntent = Intent(Intent.ACTION_SENDTO).apply {
data = "mailto:".toUri()
putExtra(Intent.EXTRA_EMAIL, arrayOf("billing@kavish.xyz"))
putExtra(Intent.EXTRA_SUBJECT, "LibrePods Play billing error")
putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.billing_error_email_subject))
putExtra(
Intent.EXTRA_TEXT,
"Please enter your GitHub username to restore your premium access:\n\nGitHub username: "
context.getString(R.string.billing_error_email_body)
)
}
context.startActivity(emailIntent)
Expand Down Expand Up @@ -570,13 +570,13 @@ fun AppSettingsScreen(
Intent.EXTRA_TEXT,
"${descriptionState.text}" +
"\n\n----------" +
"\nPhone details:" +
"\n" + context.getString(R.string.contact_phone_details) +
"\nMANUFACTURER: ${Build.MANUFACTURER}" +
"\nMODEL: ${Build.MODEL} (${Build.PRODUCT})" +
"\nDISPLAY_VERSION: ${Build.DISPLAY}" +
"\nID: ${Build.ID} (SDK ${Build.VERSION.SDK_INT_FULL})" +
"\nXposed enabled/active: ${XposedState.isAvailable}/${XposedState.bluetoothScopeEnabled}" +
"\n\nApp details:" +
"\n\n" + context.getString(R.string.contact_app_details) +
"\nVERSION: ${BuildConfig.VERSION_NAME}" +
"\nVERSION_CODE: ${BuildConfig.VERSION_CODE}" +
"\nFLAVOR: ${BuildConfig.FLAVOR}" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ fun EqualizerCard(
modifier = Modifier.weight(1f)
) {
Text(
text = "Low".uppercase(),
text = stringResource(R.string.equalizer_low).uppercase(),
style = TextStyle(
fontSize = 14.sp,
fontFamily = FontFamily(Font(R.font.sf_pro)),
Expand All @@ -558,7 +558,7 @@ fun EqualizerCard(
modifier = Modifier.weight(1f)
) {
Text(
text = "Mid".uppercase(),
text = stringResource(R.string.equalizer_mid).uppercase(),
style = TextStyle(
fontSize = 14.sp,
fontFamily = FontFamily(Font(R.font.sf_pro)),
Expand All @@ -575,7 +575,7 @@ fun EqualizerCard(
modifier = Modifier.weight(1f)
) {
Text(
text = "High".uppercase(),
text = stringResource(R.string.equalizer_high).uppercase(),
style = TextStyle(
fontSize = 14.sp,
fontFamily = FontFamily(Font(R.font.sf_pro)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fun HeadTrackingScreen(viewModel: AirPodsViewModel, navigateToPurchase: () -> Un
}

StyledToggle(
label = "Head Gestures",
label = stringResource(R.string.head_gestures),
checked = state.headGesturesEnabled,
onCheckedChange = { viewModel.setHeadGesturesEnabled(it) },
enabled = state.isPremium || state.headGesturesEnabled,
Expand All @@ -171,7 +171,7 @@ fun HeadTrackingScreen(viewModel: AirPodsViewModel, navigateToPurchase: () -> Un

Spacer(modifier = Modifier.height(16.dp))
Text(
"Velocity",
stringResource(R.string.velocity),
style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Bold,
Expand All @@ -195,12 +195,14 @@ fun HeadTrackingScreen(viewModel: AirPodsViewModel, navigateToPurchase: () -> Un
}
}
val gestureTextValue = stringResource(R.string.shake_your_head_or_nod)
val yesGestureDetected = stringResource(R.string.yes_gesture_detected)
val noGestureDetected = stringResource(R.string.no_gesture_detected)
StyledButton(
onClick = {
gestureText = gestureTextValue
coroutineScope.launch {
val accepted = ServiceManager.getService()?.testHeadGestures() ?: false
gestureText = if (accepted) "\"Yes\" gesture detected." else "\"No\" gesture detected."
gestureText = if (accepted) yesGestureDetected else noGestureDetected
}
},
backdrop = backdrop,
Expand All @@ -210,7 +212,7 @@ fun HeadTrackingScreen(viewModel: AirPodsViewModel, navigateToPurchase: () -> Un
maxScale = 0.05f
) {
Text(
"Test Head Gestures",
stringResource(R.string.test_head_gestures),
style = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
Expand Down Expand Up @@ -277,6 +279,8 @@ private fun Plot() {
val maxPoints = 100
val points = remember { mutableStateListOf<Pair<Float, Float>>() }
val darkTheme = isSystemInDarkTheme()
val horizontalLabel = stringResource(R.string.horizontal)
val verticalLabel = stringResource(R.string.vertical)

var maxAbs by remember { mutableFloatStateOf(1000f) }

Expand Down Expand Up @@ -387,7 +391,7 @@ private fun Plot() {
textSize = 12.sp.toPx()
textAlign = Paint.Align.LEFT
}
drawText("Horizontal", width - 140.dp.toPx(), textOffsetY, paint)
drawText(horizontalLabel, width - 140.dp.toPx(), textOffsetY, paint)
}

drawCircle(verticalColor, 5.dp.toPx(), Offset(width - 70.dp.toPx(), legendY))
Expand All @@ -397,7 +401,7 @@ private fun Plot() {
textSize = 12.sp.toPx()
textAlign = Paint.Align.LEFT
}
drawText("Vertical", width - 60.dp.toPx(), textOffsetY, paint)
drawText(verticalLabel, width - 60.dp.toPx(), textOffsetY, paint)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,10 @@ fun HearingAidScreen(viewModel: AirPodsViewModel, onNavigateHearingAidAdjustment

ConfirmationDialog(
showDialog = showDialog,
title = "Enable Hearing Aid",
message = "Enabling Hearing Aid will disable Headphone Accommodation and Customized Transparency Mode.",
confirmText = "Enable",
dismissText = "Cancel",
title = stringResource(R.string.enable_hearing_aid),
message = stringResource(R.string.enable_hearing_aid_confirmation),
confirmText = stringResource(R.string.enable),
dismissText = stringResource(R.string.cancel),
onConfirm = {
showDialog.value = false
val enrolled = state.controlStates[AACPManager.Companion.ControlCommandIdentifiers.HEARING_AID]?.getOrNull(0) == 0x01.toByte()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ fun LongPress(viewModel: AirPodsViewModel, name: String, navigateToPurchase: ()
leadingContent = {
Icon(
painter = painterResource(R.drawable.noise_cancellation),
contentDescription = "Icon",
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.height(42.dp)
Expand All @@ -178,7 +178,7 @@ fun LongPress(viewModel: AirPodsViewModel, name: String, navigateToPurchase: ()
leadingContent = {
Icon(
painter = painterResource(R.drawable.transparency),
contentDescription = "Icon",
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.height(42.dp)
Expand All @@ -198,7 +198,7 @@ fun LongPress(viewModel: AirPodsViewModel, name: String, navigateToPurchase: ()
leadingContent = {
Icon(
painter = painterResource(R.drawable.adaptive),
contentDescription = "Icon",
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.height(42.dp)
Expand All @@ -218,7 +218,7 @@ fun LongPress(viewModel: AirPodsViewModel, name: String, navigateToPurchase: ()
leadingContent = {
Icon(
painter = painterResource(R.drawable.noise_cancellation),
contentDescription = "Icon",
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.height(42.dp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.billing.PRICE_LOADING
import me.kavishdevar.librepods.billing.PRICE_UNAVAILABLE
import me.kavishdevar.librepods.presentation.components.ListItemOrientation
import me.kavishdevar.librepods.presentation.components.MaterialButtonStyle
import me.kavishdevar.librepods.presentation.components.StyledButton
Expand Down Expand Up @@ -188,7 +190,11 @@ fun PurchaseScreen(
materialButtonStyle = MaterialButtonStyle.Filled
) {
Text(
stringResource(R.string.buy_price, state.price),
when (state.price) {
PRICE_LOADING -> stringResource(R.string.price_loading)
PRICE_UNAVAILABLE -> stringResource(R.string.price_unavailable)
else -> stringResource(R.string.buy_price, state.price)
},
style = MaterialTheme.typography.bodyMediumEmphasized,
color = MaterialTheme.colorScheme.onPrimary
)
Expand Down
Loading