feat(reactions): Move reaction settings to per-device profiles

Migrate reaction toggles (auto-play, auto-pause, auto-connect, popups) from global ReactionSettings singleton to per-profile fields on AppleDeviceProfile. Each paired device can now have independent reaction behavior.

Extract ReactionConfig snapshot to decouple PodDevice from AppleDeviceProfile — reaction consumers read device.reactions instead of device.profile. Remove auto-connect from upgrade benefits (now free). Add LegacyReactionSettingsReader for one-shot DataStore migration.
This commit is contained in:
darken
2026-04-14 11:28:41 +02:00
committed by Matthias Urhahn
parent 29df90628f
commit 067eb2e9e0
115 changed files with 834 additions and 1225 deletions
@@ -20,8 +20,6 @@ import eu.darken.capod.common.compose.preview.MockPodDataProvider
import eu.darken.capod.common.theming.CapodTheme
import eu.darken.capod.main.ui.overview.OverviewScreen
import eu.darken.capod.main.ui.overview.OverviewViewModel
import eu.darken.capod.main.ui.settings.SettingsScreen
import eu.darken.capod.main.ui.settings.SettingsViewModel
import eu.darken.capod.main.ui.widget.ComposeWidgetPreview
import eu.darken.capod.main.ui.widget.WidgetConfigurationScreen
import eu.darken.capod.main.ui.widget.WidgetConfigurationViewModel
@@ -32,9 +30,8 @@ import eu.darken.capod.profiles.ui.DeviceManagerScreen
import eu.darken.capod.profiles.ui.DeviceManagerViewModel
import eu.darken.capod.profiles.ui.creation.DeviceProfileCreationScreen
import eu.darken.capod.profiles.ui.creation.DeviceProfileCreationViewModel
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import eu.darken.capod.reaction.ui.ReactionSettingsScreen
import eu.darken.capod.reaction.ui.ReactionSettingsViewModel
import eu.darken.capod.main.ui.devicesettings.DeviceSettingsScreen
import eu.darken.capod.main.ui.devicesettings.DeviceSettingsViewModel
import eu.darken.capod.reaction.ui.popup.PopUpContent as PopUpCard
internal const val DS = "spec:width=1080px,height=2400px,dpi=428"
@@ -113,44 +110,15 @@ internal fun AddProfileContent() = PreviewWrapper {
}
@Composable
internal fun SettingsIndexContent() = PreviewWrapper {
SettingsScreen(
state = SettingsViewModel.State(isPro = true, sponsorUrl = "https://example.com"),
onNavigateUp = {},
onGeneralSettings = {},
onDeviceManager = {},
onReactions = {},
onSupport = {},
onWiki = {},
onChangelog = {},
onHelpTranslate = {},
onAcknowledgements = {},
onPrivacyPolicy = {},
onSponsor = {},
)
}
@Composable
internal fun ReactionSettingsContent() = PreviewWrapper {
ReactionSettingsScreen(
state = ReactionSettingsViewModel.State(
internal fun DeviceSettingsReactionsContent() = PreviewWrapper {
DeviceSettingsScreen(
state = DeviceSettingsViewModel.State(
device = MockPodDataProvider.dualPodMonitoredWithReactions(),
now = MOCK_NOW,
isPro = true,
onePodMode = false,
autoPlay = true,
autoPause = true,
autoConnect = false,
autoConnectCondition = AutoConnectCondition.WHEN_SEEN,
showPopUpOnCaseOpen = true,
showPopUpOnConnection = false,
isNudgeAvailable = true,
),
onNavigateUp = {},
onOnePodModeChanged = {},
onAutoPlayChanged = {},
onAutoPauseChanged = {},
onAutoConnectChanged = {},
onAutoConnectConditionSelected = {},
onShowPopUpOnCaseOpenChanged = {},
onShowPopUpOnConnectionChanged = {},
)
}
@@ -260,14 +228,10 @@ private fun PreviewDeviceProfiles() = DeviceProfilesContent()
@Composable
private fun PreviewAddProfile() = AddProfileContent()
@Preview(name = "7 - Settings", locale = "en", device = DS, showSystemUi = true)
@Preview(name = "7 - Device Settings Reactions", locale = "en", device = DS, showSystemUi = true)
@Composable
private fun PreviewSettingsIndex() = SettingsIndexContent()
private fun PreviewDeviceSettingsReactions() = DeviceSettingsReactionsContent()
@Preview(name = "8 - Reaction Settings", locale = "en", device = DS, showSystemUi = true)
@Composable
private fun PreviewReactionSettings() = ReactionSettingsContent()
@Preview(name = "9 - Homescreen Widget", device = DS, showSystemUi = true)
@Preview(name = "8 - Homescreen Widget", device = DS, showSystemUi = true)
@Composable
private fun PreviewHomescreenWidget() = HomescreenWidgetContent()
@@ -23,6 +23,7 @@ import eu.darken.capod.pods.core.apple.ble.protocol.ProximityPayload
import eu.darken.capod.pods.core.unknown.UnknownSnapshotBle
import eu.darken.capod.profiles.core.AppleDeviceProfile
import eu.darken.capod.profiles.core.DeviceProfile
import eu.darken.capod.profiles.core.ReactionConfig
import java.time.Instant
/** Fixed timestamp for deterministic preview/screenshot rendering. */
@@ -64,6 +65,7 @@ object MockPodDataProvider {
leftPodIcon = R.drawable.device_airpods_pro2_left,
rightPodIcon = R.drawable.device_airpods_pro2_right,
_caseIcon = R.drawable.device_airpods_pro2_case,
_address = "AA:BB:CC:DD:EE:FF",
)
fun airPodsProLowBattery(): DualBlePodSnapshot = MockDualBlePodSnapshot(
@@ -120,6 +122,7 @@ object MockPodDataProvider {
_label = "AirPods Max",
batteryHeadsetPercent = 0.85f,
_isBeingWorn = true,
_address = "AA:BB:CC:DD:EE:FF",
)
fun airPodsMaxCharging(): SingleBlePodSnapshot = MockSingleAppleBlePodSnapshot(
@@ -206,6 +209,22 @@ object MockPodDataProvider {
),
)
/** Dual pods with a profile that has reaction toggles set — used for the Reactions screenshot. */
fun dualPodMonitoredWithReactions(): PodDevice = PodDevice(
profileId = "preview-dual-reactions",
label = "My AirPods Pro",
ble = airPodsProWithKeys(),
aap = null,
reactions = ReactionConfig(
autoPause = true,
autoPlay = true,
onePodMode = false,
autoConnect = true,
showPopUpOnCaseOpen = true,
showPopUpOnConnection = false,
),
)
fun singlePodMonitored(): PodDevice = PodDevice(
profileId = "preview-single",
ble = airPodsMax(),
@@ -379,6 +398,7 @@ private class MockSingleBlePodSnapshot(
override val batteryHeadsetPercent: Float?,
private val _isHeadsetBeingCharged: Boolean = false,
private val _isBeingWorn: Boolean = false,
private val _address: String? = null,
rssi: Int = -50,
) : SingleBlePodSnapshot, HasChargeDetection, HasEarDetection {
override val identifier: BlePodSnapshot.Id = BlePodSnapshot.Id()
@@ -391,7 +411,7 @@ private class MockSingleBlePodSnapshot(
override val signalQuality: Float = 0.80f
override val iconRes: Int = _model.iconRes
override val meta: BlePodSnapshot.Meta = object : BlePodSnapshot.Meta {
override val profile: DeviceProfile = AppleDeviceProfile(label = _label, model = _model)
override val profile: DeviceProfile = AppleDeviceProfile(label = _label, model = _model, address = _address)
}
override fun getLabel(context: Context): String = _model.label
@@ -23,7 +23,7 @@ object Nav {
data object Upgrade : Main
@Serializable
data class DeviceSettings(val address: String) : Main
data class DeviceSettings(val profileId: String) : Main
@Serializable
data object StemActionConfig : Main
@@ -36,9 +36,6 @@ object Nav {
@Serializable
data object General : Settings
@Serializable
data object Reactions : Settings
@Serializable
data object Debug : Settings
@@ -6,10 +6,12 @@ import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.common.permissions.isRequired
import eu.darken.capod.reaction.core.ReactionSettings
import eu.darken.capod.profiles.core.toReactionConfig
import eu.darken.capod.profiles.core.DeviceProfilesRepo
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import java.util.UUID
@@ -20,7 +22,7 @@ import javax.inject.Singleton
class PermissionTool @Inject constructor(
@ApplicationContext private val context: Context,
private val generalSettings: GeneralSettings,
private val reactionSettings: ReactionSettings,
private val profilesRepo: DeviceProfilesRepo,
) {
private val permissionCheckTrigger = MutableStateFlow(UUID.randomUUID())
@@ -29,12 +31,20 @@ class PermissionTool @Inject constructor(
permissionCheckTrigger.value = UUID.randomUUID()
}
private val anyPopupEnabled: Flow<Boolean> = profilesRepo.profiles
.map { profiles ->
profiles.any { profile ->
profile.toReactionConfig().let { it.showPopUpOnCaseOpen || it.showPopUpOnConnection }
}
}
.distinctUntilChanged()
val missingPermissions: Flow<Set<Permission>> = combine(
permissionCheckTrigger,
generalSettings.monitorMode.flow,
reactionSettings.showPopUpOnCaseOpen.flow
anyPopupEnabled,
) { _, monitorMode, showPopUp ->
Permission.values()
Permission.entries
.filter { it != Permission.IGNORE_BATTERY_OPTIMIZATION || monitorMode == MonitorMode.ALWAYS }
.filter { it != Permission.ACCESS_BACKGROUND_LOCATION || monitorMode == MonitorMode.ALWAYS }
.filter { it != Permission.SYSTEM_ALERT_WINDOW || showPopUp }
@@ -14,7 +14,7 @@ import javax.inject.Inject
class DeviceSettingsNavigation @Inject constructor() : NavigationEntry {
override fun EntryProviderScope<NavKey>.setup() {
entry<Nav.Main.DeviceSettings> { key ->
DeviceSettingsScreenHost(address = key.address)
DeviceSettingsScreenHost(profileId = key.profileId)
}
}
@@ -18,21 +18,29 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
import androidx.compose.material.icons.automirrored.twotone.Message
import androidx.compose.material.icons.automirrored.twotone.VolumeUp
import androidx.compose.material.icons.twotone.BluetoothConnected
import androidx.compose.material.icons.twotone.DevicesOther
import androidx.compose.material.icons.twotone.Edit
import androidx.compose.material.icons.twotone.GraphicEq
import androidx.compose.material.icons.twotone.Headphones
import androidx.compose.material.icons.twotone.Hearing
import androidx.compose.material.icons.twotone.LooksOne
import androidx.compose.material.icons.twotone.Loop
import androidx.compose.material.icons.twotone.Mic
import androidx.compose.material.icons.twotone.Nightlight
import androidx.compose.material.icons.twotone.PauseCircle
import androidx.compose.material.icons.twotone.PlayCircle
import androidx.compose.material.icons.twotone.QuestionMark
import androidx.compose.material.icons.twotone.Speed
import androidx.compose.material.icons.twotone.Swipe
import androidx.compose.material.icons.twotone.Timer
import androidx.compose.material.icons.twotone.TouchApp
import androidx.compose.material.icons.twotone.Visibility
import androidx.compose.material.icons.twotone.VisibilityOff
import androidx.compose.material.icons.twotone.Workspaces
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
@@ -48,7 +56,9 @@ import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -86,17 +96,18 @@ import eu.darken.capod.pods.core.apple.aap.AapPodState
import eu.darken.capod.pods.core.apple.aap.protocol.AapDeviceInfo
import eu.darken.capod.pods.core.apple.aap.protocol.AapSetting
import eu.darken.capod.pods.core.apple.ble.devices.HasStateDetection
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import java.time.Duration
@Composable
fun DeviceSettingsScreenHost(
address: String,
profileId: String,
vm: DeviceSettingsViewModel = hiltViewModel(),
) {
ErrorEventHandler(vm)
NavigationEventHandler(vm)
LaunchedEffect(address) { vm.initialize(address) }
LaunchedEffect(profileId) { vm.initialize(profileId) }
val context = LocalContext.current
val snackbarHostState = remember { SnackbarHostState() }
@@ -140,7 +151,6 @@ fun DeviceSettingsScreenHost(
onVolumeSwipeLengthChange = { vm.setVolumeSwipeLength(it) },
onEndCallMuteMicChange = { muteMic, endCall -> vm.setEndCallMuteMic(muteMic, endCall) },
onMicrophoneModeChange = { vm.setMicrophoneMode(it) },
onEarDetectionEnabledChange = { vm.setEarDetectionEnabled(it) },
onListeningModeCycleChange = { vm.setListeningModeCycle(it) },
onAllowOffOptionChange = { vm.setAllowOffOption(it) },
onSleepDetectionChange = { vm.setSleepDetection(it) },
@@ -148,6 +158,13 @@ fun DeviceSettingsScreenHost(
onStemActionsClick = { vm.navToStemConfig() },
onForceConnect = { vm.forceConnect() },
onUpgrade = { vm.launchUpgrade() },
onOnePodModeChange = { vm.setOnePodMode(it) },
onAutoPlayChange = { vm.setAutoPlay(it) },
onAutoPauseChange = { vm.setAutoPause(it) },
onAutoConnectChange = { vm.setAutoConnect(it) },
onAutoConnectConditionChange = { vm.setAutoConnectCondition(it) },
onShowPopUpOnCaseOpenChange = { vm.setShowPopUpOnCaseOpen(it) },
onShowPopUpOnConnectionChange = { vm.setShowPopUpOnConnection(it) },
)
}
@@ -169,7 +186,6 @@ fun DeviceSettingsScreen(
onVolumeSwipeLengthChange: (AapSetting.VolumeSwipeLength.Value) -> Unit = {},
onEndCallMuteMicChange: (AapSetting.EndCallMuteMic.MuteMicMode, AapSetting.EndCallMuteMic.EndCallMode) -> Unit = { _, _ -> },
onMicrophoneModeChange: (AapSetting.MicrophoneMode.Mode) -> Unit = {},
onEarDetectionEnabledChange: (Boolean) -> Unit = {},
onListeningModeCycleChange: (Int) -> Unit = {},
onAllowOffOptionChange: (Boolean) -> Unit = {},
onSleepDetectionChange: (Boolean) -> Unit = {},
@@ -177,11 +193,21 @@ fun DeviceSettingsScreen(
onStemActionsClick: () -> Unit = {},
onForceConnect: () -> Unit = {},
onUpgrade: () -> Unit = {},
onOnePodModeChange: (Boolean) -> Unit = {},
onAutoPlayChange: (Boolean) -> Unit = {},
onAutoPauseChange: (Boolean) -> Unit = {},
onAutoConnectChange: (Boolean) -> Unit = {},
onAutoConnectConditionChange: (AutoConnectCondition) -> Unit = {},
onShowPopUpOnCaseOpenChange: (Boolean) -> Unit = {},
onShowPopUpOnConnectionChange: (Boolean) -> Unit = {},
) {
val device = state.device
val features = device?.model?.features
val enabled = device?.isAapReady == true
val isPro = state.isPro
val reactions = state.reactions
var showAutoConnectConditionDialog by remember { mutableStateOf(false) }
Scaffold(
topBar = {
@@ -254,6 +280,105 @@ fun DeviceSettingsScreen(
}
}
// ── Reactions (per-profile, not gated on AAP) ─────────────────
if (device != null && features != null) {
item("reactions_header") {
SettingsCategoryHeader(text = stringResource(R.string.settings_reaction_label))
}
if (features.hasEarDetection) {
item("reaction_auto_play") {
SettingsSwitchItem(
icon = Icons.TwoTone.PlayCircle,
title = stringResource(R.string.settings_autopplay_label),
subtitle = stringResource(R.string.settings_autoplay_description),
checked = reactions.autoPlay,
onCheckedChange = onAutoPlayChange,
requiresUpgrade = !isPro,
)
}
item("reaction_auto_pause") {
SettingsSwitchItem(
icon = Icons.TwoTone.PauseCircle,
title = stringResource(R.string.settings_autopause_label),
subtitle = stringResource(R.string.settings_autopause_description),
checked = reactions.autoPause,
onCheckedChange = onAutoPauseChange,
requiresUpgrade = !isPro,
)
}
if (features.hasDualPods) {
val earDetectionActive = reactions.autoPlay || reactions.autoPause
item("reaction_one_pod_mode") {
SettingsBaseItem(
title = stringResource(R.string.settings_onepod_mode_label),
subtitle = stringResource(R.string.settings_onepod_mode_description),
icon = Icons.TwoTone.LooksOne,
onClick = { if (earDetectionActive) onOnePodModeChange(!reactions.onePodMode) },
enabled = earDetectionActive,
trailingContent = {
Switch(
checked = reactions.onePodMode,
onCheckedChange = onOnePodModeChange,
enabled = earDetectionActive,
modifier = Modifier.padding(start = 16.dp),
)
},
)
}
}
item("reaction_ear_detection_info") {
SettingsBaseItem(
title = stringResource(R.string.settings_eardetection_info_label),
subtitle = stringResource(R.string.settings_eardetection_info_description),
icon = Icons.TwoTone.QuestionMark,
onClick = {},
enabled = false,
)
}
}
item("reaction_auto_connect") {
SettingsSwitchItem(
icon = Icons.TwoTone.BluetoothConnected,
title = stringResource(R.string.settings_autoconnect_label),
subtitle = stringResource(R.string.settings_autoconnect_description),
checked = reactions.autoConnect,
onCheckedChange = onAutoConnectChange,
)
}
item("reaction_auto_connect_condition") {
SettingsBaseItem(
title = stringResource(R.string.settings_autoconnect_condition_label),
subtitle = stringResource(reactions.autoConnectCondition.labelRes),
icon = Icons.TwoTone.Workspaces,
onClick = { if (reactions.autoConnect) showAutoConnectConditionDialog = true },
enabled = reactions.autoConnect,
)
}
if (features.hasCase) {
item("reaction_popup_caseopen") {
SettingsSwitchItem(
icon = Icons.AutoMirrored.TwoTone.Message,
title = stringResource(R.string.settings_popup_caseopen_label),
subtitle = stringResource(R.string.settings_popup_caseopen_description),
checked = reactions.showPopUpOnCaseOpen,
onCheckedChange = onShowPopUpOnCaseOpenChange,
requiresUpgrade = !isPro,
)
}
}
item("reaction_popup_connection") {
SettingsSwitchItem(
icon = Icons.AutoMirrored.TwoTone.Message,
title = stringResource(R.string.settings_popup_connected_label),
subtitle = stringResource(R.string.settings_popup_connected_description),
checked = reactions.showPopUpOnConnection,
onCheckedChange = onShowPopUpOnConnectionChange,
requiresUpgrade = !isPro,
)
}
}
// Settings — only show when AAP is connected
if (features != null && device.isAapConnected) {
@@ -490,21 +615,6 @@ fun DeviceSettingsScreen(
SettingsCategoryHeader(text = stringResource(R.string.device_settings_category_general_label))
}
if (features.hasEarDetectionToggle) {
val earDetection = device.earDetectionEnabled
?: AapSetting.EarDetectionEnabled(enabled = true)
item("ear_detection_toggle") {
SettingsSwitchItem(
icon = Icons.TwoTone.Hearing,
title = stringResource(R.string.device_settings_ear_detection_label),
subtitle = stringResource(R.string.device_settings_ear_detection_description),
checked = earDetection.enabled,
onCheckedChange = onEarDetectionEnabledChange,
enabled = enabled,
)
}
}
if (features.hasSleepDetection) {
val sleepDet = device.sleepDetection
?: AapSetting.SleepDetection(enabled = true)
@@ -554,9 +664,73 @@ fun DeviceSettingsScreen(
Spacer(modifier = Modifier.height(16.dp))
}
}
if (showAutoConnectConditionDialog && device != null) {
AutoConnectConditionDialog(
current = reactions.autoConnectCondition,
hasEarDetection = features?.hasEarDetection == true,
hasCase = features?.hasCase == true,
onSelect = {
onAutoConnectConditionChange(it)
showAutoConnectConditionDialog = false
},
onDismiss = { showAutoConnectConditionDialog = false },
)
}
}
}
@Composable
private fun AutoConnectConditionDialog(
current: AutoConnectCondition,
hasEarDetection: Boolean,
hasCase: Boolean,
onSelect: (AutoConnectCondition) -> Unit,
onDismiss: () -> Unit,
) {
val options = AutoConnectCondition.entries.filter { condition ->
when (condition) {
AutoConnectCondition.IN_EAR -> hasEarDetection
AutoConnectCondition.CASE_OPEN -> hasCase
AutoConnectCondition.WHEN_SEEN -> true
}
}
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(text = stringResource(R.string.settings_autoconnect_condition_label)) },
text = {
Column(Modifier.selectableGroup()) {
options.forEach { condition ->
val isSelected = condition == current
Row(
modifier = Modifier
.fillMaxWidth()
.selectable(
selected = isSelected,
onClick = { onSelect(condition) },
role = Role.RadioButton,
)
.padding(vertical = 12.dp, horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(selected = isSelected, onClick = null)
Text(
text = stringResource(condition.labelRes),
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp),
)
}
}
}
},
confirmButton = {
TextButton(onClick = onDismiss) {
Text(text = stringResource(android.R.string.cancel))
}
},
)
}
@Composable
private fun DeviceInfoCard(
deviceInfo: AapDeviceInfo?,
@@ -1,14 +1,16 @@
package eu.darken.capod.main.ui.devicesettings
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.bluetooth.BluetoothAddress
import eu.darken.capod.common.bluetooth.BluetoothManager2
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.datastore.value
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.flow.SingleEventFlow
import eu.darken.capod.common.uix.ViewModel4
import eu.darken.capod.main.core.GeneralSettings
import eu.darken.capod.main.core.MonitorMode
import eu.darken.capod.monitor.core.DeviceMonitor
import eu.darken.capod.monitor.core.PodDevice
import eu.darken.capod.common.navigation.Nav
@@ -17,12 +19,18 @@ import eu.darken.capod.common.upgrade.isPro
import eu.darken.capod.pods.core.apple.aap.AapConnectionManager
import eu.darken.capod.pods.core.apple.aap.protocol.AapCommand
import eu.darken.capod.pods.core.apple.aap.protocol.AapSetting
import eu.darken.capod.profiles.core.AppleDeviceProfile
import eu.darken.capod.profiles.core.DeviceProfilesRepo
import eu.darken.capod.profiles.core.ReactionConfig
import eu.darken.capod.profiles.core.ProfileId
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.isActive
import java.time.Instant
@@ -35,15 +43,17 @@ class DeviceSettingsViewModel @Inject constructor(
private val aapManager: AapConnectionManager,
private val upgradeRepo: UpgradeRepo,
private val bluetoothManager: BluetoothManager2,
private val profilesRepo: DeviceProfilesRepo,
private val generalSettings: GeneralSettings,
) : ViewModel4(dispatcherProvider) {
private val targetAddress = MutableStateFlow<BluetoothAddress?>(null)
private val targetProfileId = MutableStateFlow<ProfileId?>(null)
private var initialized = false
fun initialize(address: BluetoothAddress) {
if (initialized && targetAddress.value == address) return
fun initialize(profileId: ProfileId) {
if (initialized && targetProfileId.value == profileId) return
initialized = true
targetAddress.value = address
targetProfileId.value = profileId
}
private val updateTicker = channelFlow<Unit> {
@@ -63,16 +73,16 @@ class DeviceSettingsViewModel @Inject constructor(
val events = SingleEventFlow<Event>()
val state = targetAddress.flatMapLatest { address ->
if (address == null) return@flatMapLatest flowOf(State(device = null))
val state = targetProfileId.flatMapLatest { profileId ->
if (profileId == null) return@flatMapLatest flowOf(State(device = null))
combine(
updateTicker,
deviceMonitor.devices,
deviceForProfile(profileId),
upgradeRepo.upgradeInfo,
isForceConnecting,
) { _, devices, upgrade, forcing ->
) { _, device, upgrade, forcing ->
State(
device = devices.firstOrNull { it.address == address },
device = device,
now = Instant.now(),
isPro = upgrade.isPro,
isNudgeAvailable = bluetoothManager.isNudgeAvailable,
@@ -81,13 +91,31 @@ class DeviceSettingsViewModel @Inject constructor(
}
}.asLiveState()
/**
* Returns the [PodDevice] for [profileId] reactively. Falls back to a synthesized bare
* device when the profile exists but isn't currently visible (no BLE / cache / AAP),
* so the Reactions section can still be edited for pristine profiles.
*/
private fun deviceForProfile(profileId: ProfileId): kotlinx.coroutines.flow.Flow<PodDevice?> =
deviceMonitor.devices.flatMapLatest { devices ->
val live = devices.firstOrNull { it.profileId == profileId }
flow<PodDevice?> { emit(live ?: deviceMonitor.getDeviceForProfile(profileId)) }
}
data class State(
val device: PodDevice?,
val now: Instant = Instant.now(),
val isPro: Boolean = false,
val isNudgeAvailable: Boolean = true,
val isForceConnecting: Boolean = false,
)
) {
val reactions: ReactionConfig get() = device?.reactions ?: ReactionConfig()
}
private suspend fun currentAddress(): String? {
val profileId = targetProfileId.value ?: return null
return deviceMonitor.getDeviceForProfile(profileId)?.address
}
fun forceConnect() = launch {
if (!isForceConnecting.compareAndSet(expect = false, update = true)) {
@@ -95,7 +123,7 @@ class DeviceSettingsViewModel @Inject constructor(
return@launch
}
try {
val address = targetAddress.value ?: run {
val address = currentAddress() ?: run {
events.tryEmit(Event.OpenBluetoothSettings)
return@launch
}
@@ -124,23 +152,18 @@ class DeviceSettingsViewModel @Inject constructor(
if (!accepted) {
events.tryEmit(Event.OpenBluetoothSettings)
}
// On accepted=true, AapAutoConnect.initialConnect() will pick up the new
// connectedDevices entry and trigger the AAP handshake. The card disappears
// when device.isAapConnected becomes true.
} finally {
isForceConnecting.value = false
}
}
private suspend fun sendInternal(command: AapCommand) {
val address = targetAddress.value ?: return
val address = currentAddress() ?: return
try {
aapManager.sendCommand(address, command)
log(TAG) { "Sent $command to $address" }
} catch (e: Exception) {
log(TAG, WARN) { "Failed to send $command: ${e.message}" }
// SingleEventFlow is backed by a BUFFERED Channel — use the suspending emit to avoid
// dropping the event under momentary backpressure.
events.emit(Event.SendFailed(command, e.message))
}
}
@@ -193,12 +216,15 @@ class DeviceSettingsViewModel @Inject constructor(
fun setSleepDetection(enabled: Boolean) = sendProGated(AapCommand.SetSleepDetection(enabled))
fun setDeviceName(name: String) = launch {
val address = targetAddress.value ?: return@launch
sendInternal(AapCommand.SetDeviceName(name))
val address = currentAddress() ?: return@launch
try {
aapManager.sendCommand(address, AapCommand.SetDeviceName(name))
log(TAG) { "Sent SetDeviceName to $address" }
} catch (e: Exception) {
log(TAG, WARN) { "Failed to send SetDeviceName: ${e.message}" }
events.emit(Event.SendFailed(AapCommand.SetDeviceName(name), e.message))
}
// Also try to update the Android-local bond alias so the new name shows in Android's
// Bluetooth settings too. The AAP rename only changes what the AirPods themselves report;
// Android's system display reads from the bond database and needs a separate update.
val bonded = try {
bluetoothManager.bondedDevices().first().firstOrNull { it.address == address }
} catch (e: Exception) {
@@ -212,6 +238,59 @@ class DeviceSettingsViewModel @Inject constructor(
}
}
// ── Reaction toggles (per-profile) ───────────────────────────────────────
private suspend fun updateProfileNow(transform: (AppleDeviceProfile) -> AppleDeviceProfile) {
val profileId = targetProfileId.value ?: return
try {
profilesRepo.updateAppleProfile(profileId, transform)
} catch (e: Exception) {
log(TAG, WARN) { "Failed to update profile $profileId: ${e.message}" }
errorEvents.emit(e)
}
}
private fun proGatedReaction(
enabled: Boolean,
transform: (AppleDeviceProfile) -> AppleDeviceProfile,
) = launch {
// Disabling never requires pro; enabling does.
if (enabled && !upgradeRepo.isPro()) {
navTo(Nav.Main.Upgrade)
return@launch
}
updateProfileNow(transform)
}
fun setOnePodMode(enabled: Boolean) = launch { updateProfileNow { it.copy(onePodMode = enabled) } }
fun setAutoPlay(enabled: Boolean) = proGatedReaction(enabled) { it.copy(autoPlay = enabled) }
fun setAutoPause(enabled: Boolean) = proGatedReaction(enabled) { it.copy(autoPause = enabled) }
fun setAutoConnect(enabled: Boolean) = launch {
updateProfileNow { it.copy(autoConnect = enabled) }
if (enabled) {
// Auto-connect requires ALWAYS mode to react to BLE/case/ear events when
// nothing is connected. We intentionally do NOT revert on disable — the user
// may have set ALWAYS manually, or another profile may still need it.
if (generalSettings.monitorMode.value() != MonitorMode.ALWAYS) {
log(TAG) { "Forcing monitorMode to ALWAYS because autoConnect was enabled" }
generalSettings.monitorMode.value(MonitorMode.ALWAYS)
}
}
}
fun setAutoConnectCondition(condition: AutoConnectCondition) = launch {
updateProfileNow { it.copy(autoConnectCondition = condition) }
}
fun setShowPopUpOnCaseOpen(enabled: Boolean) =
proGatedReaction(enabled) { it.copy(showPopUpOnCaseOpen = enabled) }
fun setShowPopUpOnConnection(enabled: Boolean) =
proGatedReaction(enabled) { it.copy(showPopUpOnConnection = enabled) }
fun navToStemConfig() = launch {
if (upgradeRepo.isPro()) {
navTo(Nav.Main.StemActionConfig)
@@ -154,8 +154,8 @@ class OverviewViewModel @Inject constructor(
}
fun goToDeviceSettings(device: PodDevice) {
val address = device.address ?: return
navTo(Nav.Main.DeviceSettings(address))
val profileId = device.profileId ?: return
navTo(Nav.Main.DeviceSettings(profileId))
}
fun goToEditProfile(device: PodDevice) {
@@ -141,7 +141,7 @@ fun DualPodsCard(
}
}
if (device.address != null && onDeviceSettings != null) {
if (device.profileId != null && onDeviceSettings != null) {
IconButton(onClick = onDeviceSettings) {
Icon(
imageVector = Icons.TwoTone.Tune,
@@ -149,7 +149,8 @@ fun DualPodsCard(
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
} else if (device.profileId != null && device.address == null && onEditProfile != null) {
}
if (device.profileId != null && device.address == null && onEditProfile != null) {
IconButton(onClick = onEditProfile) {
Icon(
imageVector = Icons.TwoTone.Warning,
@@ -140,7 +140,7 @@ fun SinglePodsCard(
}
}
if (device.address != null && onDeviceSettings != null) {
if (device.profileId != null && onDeviceSettings != null) {
IconButton(onClick = onDeviceSettings) {
Icon(
imageVector = Icons.TwoTone.Tune,
@@ -148,7 +148,8 @@ fun SinglePodsCard(
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
} else if (device.profileId != null && device.address == null && onEditProfile != null) {
}
if (device.profileId != null && device.address == null && onEditProfile != null) {
IconButton(onClick = onEditProfile) {
Icon(
imageVector = Icons.TwoTone.Warning,
@@ -11,7 +11,6 @@ import androidx.compose.material.icons.twotone.Favorite
import androidx.compose.material.icons.twotone.Settings
import androidx.compose.material.icons.twotone.SupportAgent
import androidx.compose.material.icons.twotone.Translate
import androidx.compose.material.icons.twotone.Widgets
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
@@ -47,7 +46,6 @@ fun SettingsScreenHost(vm: SettingsViewModel = hiltViewModel()) {
onNavigateUp = { vm.navUp() },
onGeneralSettings = { vm.navTo(Nav.Settings.General) },
onDeviceManager = { vm.navTo(Nav.Main.DeviceManager) },
onReactions = { vm.navTo(Nav.Settings.Reactions) },
onSupport = { vm.navTo(Nav.Settings.Support) },
onWiki = { vm.openUrl("https://github.com/d4rken-org/capod/wiki") },
onChangelog = { vm.openUrl("https://capod.darken.eu/changelog") },
@@ -65,7 +63,6 @@ fun SettingsScreen(
onNavigateUp: () -> Unit,
onGeneralSettings: () -> Unit,
onDeviceManager: () -> Unit,
onReactions: () -> Unit,
onSupport: () -> Unit,
onWiki: () -> Unit,
onChangelog: () -> Unit,
@@ -121,14 +118,6 @@ fun SettingsScreen(
onClick = onDeviceManager,
)
}
item {
SettingsBaseItem(
title = stringResource(R.string.settings_reaction_label),
subtitle = stringResource(R.string.settings_reaction_description),
icon = Icons.TwoTone.Widgets,
onClick = onReactions,
)
}
item {
SettingsCategoryHeader(text = stringResource(R.string.settings_category_other_label))
}
@@ -192,7 +181,6 @@ private fun SettingsScreenPreview() = PreviewWrapper {
onNavigateUp = {},
onGeneralSettings = {},
onDeviceManager = {},
onReactions = {},
onSupport = {},
onWiki = {},
onChangelog = {},
@@ -15,6 +15,7 @@ import eu.darken.capod.pods.core.apple.aap.AapConnectionManager
import eu.darken.capod.pods.core.apple.ble.devices.ApplePods
import eu.darken.capod.pods.core.apple.aap.AapPodState
import eu.darken.capod.profiles.core.AppleDeviceProfile
import eu.darken.capod.profiles.core.toReactionConfig
import eu.darken.capod.profiles.core.DeviceProfile
import eu.darken.capod.profiles.core.DeviceProfilesRepo
import kotlinx.coroutines.CoroutineScope
@@ -64,6 +65,7 @@ class DeviceMonitor @Inject constructor(
profileAddress = profile?.address,
profileModel = profile?.model,
profileKeyState = profile.toBleKeyState(),
reactions = profile.toReactionConfig(),
)
}
@@ -114,6 +116,7 @@ class DeviceMonitor @Inject constructor(
profileAddress = profile.address,
profileModel = profile.model,
profileKeyState = profile.toBleKeyState(),
reactions = profile.toReactionConfig(),
)
}
@@ -167,24 +170,26 @@ class DeviceMonitor @Inject constructor(
}
val profile = profilesRepo.profiles.firstOrNull()?.firstOrNull { it.id == profileId }
val cached = deviceStateCache.load(profileId)
val aap = profile?.let { aapManager.allStates.value.forProfile(it) }
if (cached == null && aap == null) {
log(TAG) { "No device found for profile $profileId" }
if (profile == null) {
log(TAG) { "No profile with id $profileId" }
return null
}
val cached = deviceStateCache.load(profileId)
val aap = aapManager.allStates.value.forProfile(profile)
log(TAG) { "Found fallback device for profile $profileId (cached=${cached != null}, aap=${aap != null})" }
log(TAG) {
"Synthesizing device for profile $profileId (cached=${cached != null}, aap=${aap != null})"
}
return PodDevice(
profileId = profileId,
label = profile?.label,
label = profile.label,
ble = null,
aap = aap,
cached = cached,
profileAddress = profile?.address,
profileModel = profile?.model,
profileAddress = profile.address,
profileModel = profile.model,
profileKeyState = profile.toBleKeyState(),
reactions = profile.toReactionConfig(),
)
}
@@ -20,6 +20,7 @@ import eu.darken.capod.pods.core.apple.ble.devices.HasChargeDetectionDual
import eu.darken.capod.pods.core.apple.ble.devices.HasDualMicrophone
import eu.darken.capod.pods.core.apple.ble.devices.HasEarDetection
import eu.darken.capod.pods.core.apple.ble.devices.HasEarDetectionDual
import eu.darken.capod.profiles.core.ReactionConfig
import java.time.Duration
import java.time.Instant
@@ -45,6 +46,8 @@ data class PodDevice(
* every time the BLE scanner misses the next advertisement batch.
*/
internal val profileKeyState: BleKeyState = BleKeyState.NONE,
/** Reaction toggle snapshot from the profile. Defaults to all-off when no profile is matched. */
val reactions: ReactionConfig = ReactionConfig(),
) {
val model: PodModel get() = ble?.model ?: profileModel ?: cached?.model ?: PodModel.UNKNOWN
/** Bonded BR/EDR address (from profile). Used for AAP commands. */
@@ -4,6 +4,7 @@ import eu.darken.capod.common.serialization.ByteArrayBase64Serializer
import eu.darken.capod.pods.core.apple.PodModel
import eu.darken.capod.pods.core.apple.ble.protocol.IdentityResolvingKey
import eu.darken.capod.pods.core.apple.ble.protocol.ProximityEncryptionKey
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -21,4 +22,23 @@ data class AppleDeviceProfile(
@SerialName("identityKey") @Serializable(with = ByteArrayBase64Serializer::class) val identityKey: IdentityResolvingKey? = null,
@SerialName("encryptionKey") @Serializable(with = ByteArrayBase64Serializer::class) val encryptionKey: ProximityEncryptionKey? = null,
@SerialName("address") override val address: String? = null,
) : DeviceProfile
@SerialName("reactionAutoPause") val autoPause: Boolean = false,
@SerialName("reactionAutoPlay") val autoPlay: Boolean = false,
@SerialName("reactionOnePodMode") val onePodMode: Boolean = false,
@SerialName("reactionAutoConnect") val autoConnect: Boolean = false,
@SerialName("reactionAutoConnectCondition") val autoConnectCondition: AutoConnectCondition = AutoConnectCondition.WHEN_SEEN,
@SerialName("reactionShowPopUpOnCaseOpen") val showPopUpOnCaseOpen: Boolean = false,
@SerialName("reactionShowPopUpOnConnection") val showPopUpOnConnection: Boolean = false,
) : DeviceProfile, HasReactionConfig {
override val reactionConfig: ReactionConfig
get() = ReactionConfig(
autoPause = autoPause,
autoPlay = autoPlay,
onePodMode = onePodMode,
autoConnect = autoConnect,
autoConnectCondition = autoConnectCondition,
showPopUpOnCaseOpen = showPopUpOnCaseOpen,
showPopUpOnConnection = showPopUpOnConnection,
)
}
@@ -6,10 +6,14 @@ import eu.darken.capod.R
import eu.darken.capod.common.coroutine.AppScope
import eu.darken.capod.common.datastore.valueBlocking
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.serialization.SerializationCapod
import eu.darken.capod.main.core.GeneralSettings
import eu.darken.capod.monitor.core.cache.DeviceStateCache
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import kotlinx.serialization.json.Json
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@@ -26,37 +30,80 @@ class DeviceProfilesRepo @Inject constructor(
private val generalSettings: GeneralSettings,
private val settings: DeviceProfilesSettings,
private val deviceStateCache: DeviceStateCache,
@SerializationCapod private val json: Json,
) {
private val mutex = Mutex()
init {
scope.launch {
if (settings.defaultProfileCreated.valueBlocking) return@launch
log(TAG) { "Creating default profile" }
var defaultProfile = AppleDeviceProfile(
label = context.getString(R.string.profiles_name_default),
)
if (!settings.singleToMultiMigrationDone.valueBlocking) {
log(TAG) { "Migrating settings default profile" }
defaultProfile = defaultProfile.copy(
minimumSignalQuality = generalSettings.oldMinimumSignalQuality.valueBlocking,
model = generalSettings.oldMainDeviceModel.valueBlocking,
address = generalSettings.oldMainDeviceAddress.valueBlocking,
identityKey = generalSettings.oldMainDeviceIdentityKey.valueBlocking,
encryptionKey = generalSettings.oldMainDeviceEncryptionKey.valueBlocking,
if (!settings.defaultProfileCreated.valueBlocking) {
log(TAG) { "Creating default profile" }
var defaultProfile = AppleDeviceProfile(
label = context.getString(R.string.profiles_name_default),
)
settings.singleToMultiMigrationDone.valueBlocking = true
if (!settings.singleToMultiMigrationDone.valueBlocking) {
log(TAG) { "Migrating settings default profile" }
defaultProfile = defaultProfile.copy(
minimumSignalQuality = generalSettings.oldMinimumSignalQuality.valueBlocking,
model = generalSettings.oldMainDeviceModel.valueBlocking,
address = generalSettings.oldMainDeviceAddress.valueBlocking,
identityKey = generalSettings.oldMainDeviceIdentityKey.valueBlocking,
encryptionKey = generalSettings.oldMainDeviceEncryptionKey.valueBlocking,
)
settings.singleToMultiMigrationDone.valueBlocking = true
}
log(TAG) { "Default profile: $defaultProfile" }
addProfile(defaultProfile)
settings.defaultProfileCreated.valueBlocking = true
}
log(TAG) { "Default profile: $defaultProfile" }
addProfile(defaultProfile)
settings.defaultProfileCreated.valueBlocking = true
// Reaction migration runs INDEPENDENTLY of defaultProfileCreated. Existing
// installs already have defaultProfileCreated=true, so nesting this inside the
// block above would silently swallow the migration on upgrade.
if (!settings.reactionMigrationDone.valueBlocking) {
migrateLegacyReactions()
}
}
}
private suspend fun migrateLegacyReactions() {
log(TAG) { "Migrating legacy global reaction settings onto profiles" }
mutex.withLock {
val legacy = try {
LegacyReactionSettingsReader(context, json).read()
} catch (e: Exception) {
log(TAG, WARN) { "Failed to read legacy reactions, defaulting all profiles: ${e.message}" }
null
}
val current = settings.profiles.valueBlocking.profiles
val migrated = current.map { p ->
if (p !is AppleDeviceProfile || legacy == null) return@map p
val features = p.model.features
val coercedCondition = when {
legacy.autoConnectCondition == AutoConnectCondition.IN_EAR && !features.hasEarDetection ->
AutoConnectCondition.WHEN_SEEN
legacy.autoConnectCondition == AutoConnectCondition.CASE_OPEN && !features.hasCase ->
AutoConnectCondition.WHEN_SEEN
else -> legacy.autoConnectCondition
}
p.copy(
autoPause = legacy.autoPause,
autoPlay = legacy.autoPlay,
onePodMode = legacy.onePodMode && features.hasDualPods && features.hasEarDetection,
autoConnect = legacy.autoConnect,
autoConnectCondition = coercedCondition,
showPopUpOnCaseOpen = legacy.showPopUpOnCaseOpen,
showPopUpOnConnection = legacy.showPopUpOnConnection,
)
}
settings.profiles.valueBlocking = DeviceProfilesContainer(migrated)
settings.reactionMigrationDone.valueBlocking = true
}
log(TAG) { "Legacy reaction migration complete" }
}
val profiles: Flow<List<DeviceProfile>> = settings.profiles.flow.map { it.profiles }
suspend fun addProfile(profile: DeviceProfile, addFirst: Boolean = false) = mutex.withLock {
@@ -80,6 +127,30 @@ class DeviceProfilesRepo @Inject constructor(
log(VERBOSE) { "Updated device profile: ${profile.label}" }
}
/**
* Read-modify-write helper that preserves every field the caller doesn't touch.
* Prevents callers that only know a subset of fields (e.g. the profile editor holding
* name/model/keys/address/signalQuality) from silently wiping fields the user set
* elsewhere — notably the reaction toggles edited from Device Settings.
*/
suspend fun updateAppleProfile(
id: ProfileId,
transform: (AppleDeviceProfile) -> AppleDeviceProfile,
) = mutex.withLock {
val currentContainer = settings.profiles.valueBlocking
val existing = currentContainer.profiles.firstOrNull { it.id == id } as? AppleDeviceProfile
if (existing == null) {
log(TAG, WARN) { "updateAppleProfile($id): profile not found or not AppleDeviceProfile" }
return@withLock
}
val updated = transform(existing)
val otherProfiles = currentContainer.profiles.filter { it.id != id }
checkAddressUniqueness(updated, otherProfiles)
val updatedProfiles = currentContainer.profiles.map { if (it.id == id) updated else it }
settings.profiles.valueBlocking = DeviceProfilesContainer(updatedProfiles)
log(VERBOSE) { "Updated apple device profile: ${updated.label}" }
}
suspend fun removeProfile(profileId: ProfileId) = mutex.withLock {
val currentContainer = settings.profiles.valueBlocking
val updatedProfiles = currentContainer.profiles.filter { it.id != profileId }
@@ -33,5 +33,6 @@ class DeviceProfilesSettings @Inject constructor(
)
val singleToMultiMigrationDone = dataStore.createValue("profiles.migration.v2.done", false)
val defaultProfileCreated = dataStore.createValue("profiles.default.v2.created", false)
val reactionMigrationDone = dataStore.createValue("profiles.reactions.migration.done", false)
}
@@ -0,0 +1,75 @@
package eu.darken.capod.profiles.core
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import kotlinx.coroutines.flow.first
import kotlinx.serialization.json.Json
/**
* One-shot reader for the legacy global `settings_reaction` DataStore. Used by the reaction
* migration in [DeviceProfilesRepo] to copy the old global values onto every profile. Does
* not depend on the old `ReactionSettings` class (deleted in the same change), so the
* migration can still run after that class is gone.
*/
class LegacyReactionSettingsReader(context: Context, private val json: Json) {
private val Context.legacyStore: DataStore<Preferences> by preferencesDataStore(
name = LEGACY_STORE_NAME,
)
private val dataStore: DataStore<Preferences> = context.applicationContext.legacyStore
suspend fun read(): LegacyReactionValues {
val prefs = dataStore.data.first()
val conditionRaw = prefs[CONDITION_KEY]
val condition = conditionRaw?.let {
try {
json.decodeFromString<AutoConnectCondition>(it)
} catch (e: Exception) {
log(TAG, WARN) { "Failed to decode legacy auto-connect condition: ${e.message}" }
null
}
} ?: AutoConnectCondition.WHEN_SEEN
return LegacyReactionValues(
autoPause = prefs[AUTO_PAUSE_KEY] ?: false,
autoPlay = prefs[AUTO_PLAY_KEY] ?: false,
autoConnect = prefs[AUTO_CONNECT_KEY] ?: false,
autoConnectCondition = condition,
showPopUpOnCaseOpen = prefs[POPUP_CASE_OPEN_KEY] ?: false,
showPopUpOnConnection = prefs[POPUP_CONNECTED_KEY] ?: false,
onePodMode = prefs[ONE_POD_KEY] ?: false,
)
}
companion object {
private val TAG = logTag("LegacyReactionReader")
private const val LEGACY_STORE_NAME = "settings_reaction"
internal val AUTO_PAUSE_KEY = booleanPreferencesKey("reaction.autopause.enabled")
internal val AUTO_PLAY_KEY = booleanPreferencesKey("reaction.autoplay.enabled")
internal val AUTO_CONNECT_KEY = booleanPreferencesKey("reaction.autoconnect.enabled")
internal val CONDITION_KEY = stringPreferencesKey("reaction.autoconnect.condition")
internal val POPUP_CASE_OPEN_KEY = booleanPreferencesKey("reaction.popup.caseopen")
internal val POPUP_CONNECTED_KEY = booleanPreferencesKey("reaction.popup.connected")
internal val ONE_POD_KEY = booleanPreferencesKey("reaction.onepod.enabled")
}
}
data class LegacyReactionValues(
val autoPause: Boolean,
val autoPlay: Boolean,
val autoConnect: Boolean,
val autoConnectCondition: AutoConnectCondition,
val showPopUpOnCaseOpen: Boolean,
val showPopUpOnConnection: Boolean,
val onePodMode: Boolean,
)
@@ -0,0 +1,20 @@
package eu.darken.capod.profiles.core
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
data class ReactionConfig(
val autoPause: Boolean = false,
val autoPlay: Boolean = false,
val onePodMode: Boolean = false,
val autoConnect: Boolean = false,
val autoConnectCondition: AutoConnectCondition = AutoConnectCondition.WHEN_SEEN,
val showPopUpOnCaseOpen: Boolean = false,
val showPopUpOnConnection: Boolean = false,
)
interface HasReactionConfig {
val reactionConfig: ReactionConfig
}
fun DeviceProfile?.toReactionConfig(): ReactionConfig =
(this as? HasReactionConfig)?.reactionConfig ?: ReactionConfig()
@@ -19,6 +19,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
import androidx.compose.material.icons.twotone.Add
import androidx.compose.material.icons.twotone.DragHandle
import androidx.compose.material.icons.twotone.Tune
import androidx.compose.material3.Card
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
@@ -63,6 +64,7 @@ fun DeviceManagerScreenHost(vm: DeviceManagerViewModel = hiltViewModel()) {
onBack = { vm.navUp() },
onAddDevice = { vm.onAddDevice() },
onEditProfile = { profile -> vm.onEditProfile(profile) },
onDeviceSettings = { profile -> vm.onDeviceSettings(profile) },
onReorder = { ids -> vm.onReorder(ids) },
)
}
@@ -74,6 +76,7 @@ fun DeviceManagerScreen(
onBack: () -> Unit,
onAddDevice: () -> Unit,
onEditProfile: (DeviceProfile) -> Unit,
onDeviceSettings: (DeviceProfile) -> Unit = {},
onReorder: (List<ProfileId>) -> Unit = {},
) {
val lazyListState = rememberLazyListState()
@@ -142,6 +145,7 @@ fun DeviceManagerScreen(
),
profile = profile,
onClick = { if (!reorderableState.isDragging) onEditProfile(profile) },
onDeviceSettings = { onDeviceSettings(profile) },
showDragHandle = showDragHandles,
)
}
@@ -230,13 +234,14 @@ private fun ProfileRow(
modifier: Modifier = Modifier,
profile: DeviceProfile,
onClick: () -> Unit,
onDeviceSettings: () -> Unit = {},
showDragHandle: Boolean = false,
) {
Row(
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.padding(horizontal = 16.dp, vertical = 12.dp),
.padding(start = 16.dp, end = 4.dp, top = 12.dp, bottom = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Image(
@@ -256,6 +261,13 @@ private fun ProfileRow(
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
IconButton(onClick = onDeviceSettings) {
Icon(
imageVector = Icons.TwoTone.Tune,
contentDescription = stringResource(R.string.device_settings_open_cd),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
if (showDragHandle) {
Icon(
imageVector = Icons.TwoTone.DragHandle,
@@ -37,6 +37,11 @@ class DeviceManagerViewModel @Inject constructor(
navTo(Nav.Main.DeviceProfileCreation(profileId = profile.id))
}
fun onDeviceSettings(profile: DeviceProfile) {
log(TAG) { "onDeviceSettings(): $profile" }
navTo(Nav.Main.DeviceSettings(profileId = profile.id))
}
fun onReorder(profileIds: List<ProfileId>) = launch {
log(TAG) { "onReorder(): ${profileIds.size} profiles" }
deviceProfilesRepo.reorderProfilesById(profileIds)
@@ -219,20 +219,30 @@ class DeviceProfileCreationViewModel @Inject constructor(
launch {
try {
val profile = AppleDeviceProfile(
id = if (isEditMode) profileId!! else UUID.randomUUID().toString(),
label = name,
model = editorState.selectedModel,
minimumSignalQuality = editorState.minimumSignalQuality,
identityKey = editorState.identityKeyHex?.fromHex(),
encryptionKey = editorState.encryptionKeyHex?.fromHex(),
address = editorState.selectedDeviceAddress,
)
if (isEditMode) {
deviceProfilesRepo.updateProfile(profile)
log(TAG) { "Profile updated: $profile" }
// Read-modify-write so reaction toggles (and any other fields this editor
// doesn't know about) survive a rename or key-refresh.
deviceProfilesRepo.updateAppleProfile(profileId!!) { existing ->
existing.copy(
label = name,
model = editorState.selectedModel,
minimumSignalQuality = editorState.minimumSignalQuality,
identityKey = editorState.identityKeyHex?.fromHex(),
encryptionKey = editorState.encryptionKeyHex?.fromHex(),
address = editorState.selectedDeviceAddress,
)
}
log(TAG) { "Profile updated: $profileId" }
} else {
val profile = AppleDeviceProfile(
id = UUID.randomUUID().toString(),
label = name,
model = editorState.selectedModel,
minimumSignalQuality = editorState.minimumSignalQuality,
identityKey = editorState.identityKeyHex?.fromHex(),
encryptionKey = editorState.encryptionKeyHex?.fromHex(),
address = editorState.selectedDeviceAddress,
)
deviceProfilesRepo.addProfile(profile)
log(TAG) { "Profile created: $profile" }
}
@@ -1,48 +0,0 @@
package eu.darken.capod.reaction.core
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.SharedPreferencesMigration
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import eu.darken.capod.common.datastore.createValue
import eu.darken.capod.common.serialization.SerializationCapod
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import kotlinx.serialization.json.Json
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ReactionSettings @Inject constructor(
@ApplicationContext private val context: Context,
@SerializationCapod json: Json,
) {
private val Context.dataStore by preferencesDataStore(
name = "settings_reaction",
produceMigrations = { ctx -> listOf(SharedPreferencesMigration(ctx, "settings_reaction")) }
)
private val dataStore: DataStore<Preferences> get() = context.dataStore
val autoPause = dataStore.createValue("reaction.autopause.enabled", false)
val autoPlay = dataStore.createValue("reaction.autoplay.enabled", false)
val autoConnect = dataStore.createValue("reaction.autoconnect.enabled", false)
val autoConnectCondition = dataStore.createValue(
"reaction.autoconnect.condition",
AutoConnectCondition.WHEN_SEEN,
json,
onErrorFallbackToDefault = true,
)
val showPopUpOnCaseOpen = dataStore.createValue("reaction.popup.caseopen", false)
val showPopUpOnConnection = dataStore.createValue("reaction.popup.connected", false)
val onePodMode = dataStore.createValue("reaction.onepod.enabled", false)
}
@@ -10,10 +10,9 @@ import eu.darken.capod.main.core.GeneralSettings
import eu.darken.capod.monitor.core.DeviceMonitor
import eu.darken.capod.monitor.core.primaryDevice
import eu.darken.capod.pods.core.apple.ble.devices.DualApplePods
import eu.darken.capod.profiles.core.DeviceProfilesRepo
import eu.darken.capod.reaction.core.ReactionSettings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filterNotNull
@@ -22,23 +21,23 @@ import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
import eu.darken.capod.common.datastore.valueBlocking
@Singleton
class AutoConnect @Inject constructor(
private val bluetoothManager: BluetoothManager2,
private val deviceMonitor: DeviceMonitor,
private val generalSettings: GeneralSettings,
private val reactionSettings: ReactionSettings,
private val deviceProfilesRepo: DeviceProfilesRepo,
) {
fun monitor(): Flow<Unit> = reactionSettings.autoConnect.flow
fun monitor(): Flow<Unit> = deviceMonitor.primaryDevice()
.map { it?.reactions?.autoConnect == true }
.distinctUntilChanged()
.flatMapLatest { isAutoConnectEnabled ->
if (isAutoConnectEnabled) {
combine(
bluetoothManager.connectedDevices,
deviceMonitor.primaryDevice().filterNotNull().distinctUntilChangedBy { it.rawDataHex },
deviceMonitor.primaryDevice().filterNotNull().distinctUntilChangedBy {
Triple(it.rawDataHex, it.reactions.autoConnectCondition, it.reactions.onePodMode)
},
) { connectedDevices, mainDevice ->
connectedDevices to mainDevice
}
@@ -73,13 +72,14 @@ class AutoConnect @Inject constructor(
return@map
}
val condition = reactionSettings.autoConnectCondition.valueBlocking
val reactions = mainDevice.reactions
val condition = reactions.autoConnectCondition
log(TAG) { "Checking condition $condition" }
val lidState = mainDevice.caseLidState
val isBeingWorn = mainDevice.isBeingWorn ?: false
val isEitherPodInEar = mainDevice.isEitherPodInEar ?: false
val onePodMode = reactionSettings.onePodMode.valueBlocking
val onePodMode = reactions.onePodMode
val decision = evaluateAutoConnect(
mainDeviceAddr = mainDeviceAddr,
@@ -2,7 +2,6 @@ package eu.darken.capod.reaction.core.playpause
import eu.darken.capod.common.MediaControl
import eu.darken.capod.common.bluetooth.BluetoothManager2
import eu.darken.capod.common.datastore.valueBlocking
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
@@ -11,12 +10,11 @@ import eu.darken.capod.common.flow.setupCommonEventHandlers
import eu.darken.capod.common.flow.withPrevious
import eu.darken.capod.monitor.core.DeviceMonitor
import eu.darken.capod.monitor.core.primaryDevice
import eu.darken.capod.reaction.core.ReactionSettings
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
import javax.inject.Singleton
@@ -25,22 +23,21 @@ import javax.inject.Singleton
class PlayPause @Inject constructor(
private val deviceMonitor: DeviceMonitor,
private val bluetoothManager: BluetoothManager2,
private val reactionSettings: ReactionSettings,
private val mediaControl: MediaControl,
) {
fun monitor() = combine(
reactionSettings.autoPlay.flow,
reactionSettings.autoPause.flow,
reactionSettings.onePodMode.flow, // Included to restart pipeline when toggled; value read at decision time
) { play, pause, _ -> play || pause }
.flatMapLatest { if (it) bluetoothManager.connectedDevices else emptyFlow() }
.flatMapLatest {
if (it.isEmpty()) {
fun monitor() = deviceMonitor.primaryDevice()
.map { device -> device?.reactions?.let { it.autoPlay || it.autoPause } == true }
.distinctUntilChanged()
.flatMapLatest { shouldMonitor ->
if (shouldMonitor) bluetoothManager.connectedDevices else emptyFlow()
}
.flatMapLatest { connected ->
if (connected.isEmpty()) {
log(TAG) { "No known devices connected." }
emptyFlow()
} else {
log(TAG) { "Known devices connected: $it" }
log(TAG) { "Known devices connected: $connected" }
deviceMonitor.primaryDevice()
}
}
@@ -48,21 +45,28 @@ class PlayPause @Inject constructor(
.withPrevious()
.filter { (previous, current) ->
if (previous == null || current == null) return@filter false
log(TAG, VERBOSE) { "previous-id=${previous.identifier}, current-id=${current.identifier}" }
val match = previous.identifier == current.identifier
// Use profileId (stable across BLE address rotations) rather than BLE identifier.
// Only profiled devices reach this point (outer gate requires profile.autoPlay/autoPause).
val match = previous.profileId != null && previous.profileId == current.profileId
if (!match) log(TAG, WARN) { "Main device switched, skipping reaction." }
match
}
.onEach { (previous, current) ->
log(TAG, VERBOSE) { "Checking\nprevious=$previous\ncurrent=$current" }
val reactions = current?.reactions
if (reactions == null) {
log(TAG, VERBOSE) { "No reactions on current device, skipping reaction" }
return@onEach
}
// Convert to EarDetectionState based on device capabilities
val prevState: EarDetectionState
val currState: EarDetectionState
when {
previous!!.hasEarDetection && previous.hasDualPods &&
current!!.hasEarDetection && current.hasDualPods -> {
current.hasEarDetection && current.hasDualPods -> {
// Dual pod devices (AirPods, AirPods Pro, etc.)
log(TAG, VERBOSE) {
"Dual-pod device: left=${current.isLeftInEar}, right=${current.isRightInEar}"
@@ -77,7 +81,7 @@ class PlayPause @Inject constructor(
)
}
previous!!.hasEarDetection && current!!.hasEarDetection -> {
previous.hasEarDetection && current.hasEarDetection -> {
// Single pod devices (AirPods Max, etc.)
log(TAG, VERBOSE) { "Single-pod device: worn=${current.isBeingWorn}" }
prevState = EarDetectionState.fromSinglePod(worn = previous.isBeingWorn ?: false)
@@ -94,7 +98,7 @@ class PlayPause @Inject constructor(
val decision = evaluatePlayPauseAction(
previous = prevState,
current = currState,
onePodMode = reactionSettings.onePodMode.valueBlocking,
onePodMode = reactions.onePodMode,
isCurrentlyPlaying = mediaControl.isPlaying
)
@@ -102,21 +106,21 @@ class PlayPause @Inject constructor(
// Execute the decision
when {
decision.shouldPlay && reactionSettings.autoPlay.valueBlocking -> {
decision.shouldPlay && reactions.autoPlay -> {
log(TAG) { "autoPlay is triggered, sendPlay() - ${decision.reason}" }
mediaControl.sendPlay()
}
decision.shouldPlay && !reactionSettings.autoPlay.valueBlocking -> {
decision.shouldPlay && !reactions.autoPlay -> {
log(TAG, VERBOSE) { "autoPlay is disabled" }
}
decision.shouldPause && reactionSettings.autoPause.valueBlocking -> {
decision.shouldPause && reactions.autoPause -> {
log(TAG) { "autoPause is triggered, sendPause() - ${decision.reason}" }
mediaControl.sendPause()
}
decision.shouldPause && !reactionSettings.autoPause.valueBlocking -> {
decision.shouldPause && !reactions.autoPause -> {
log(TAG, VERBOSE) { "autoPause is disabled" }
}
}
@@ -1,6 +1,7 @@
package eu.darken.capod.reaction.core.popup
import eu.darken.capod.common.bluetooth.BluetoothAddress
import eu.darken.capod.common.bluetooth.BluetoothDevice2
import eu.darken.capod.common.bluetooth.BluetoothManager2
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.log
@@ -11,12 +12,9 @@ import eu.darken.capod.monitor.core.DeviceMonitor
import eu.darken.capod.monitor.core.PodDevice
import eu.darken.capod.monitor.core.primaryDevice
import eu.darken.capod.pods.core.apple.ble.devices.DualApplePods
import eu.darken.capod.reaction.core.ReactionSettings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import java.time.Duration
@@ -27,35 +25,41 @@ import javax.inject.Singleton
@Singleton
class PopUpReaction @Inject constructor(
private val deviceMonitor: DeviceMonitor,
private val reactionSettings: ReactionSettings,
private val bluetoothManager: BluetoothManager2,
) {
private val caseCoolDowns = mutableMapOf<String, Instant>()
private val caseCoolDowns = java.util.concurrent.ConcurrentHashMap<String, Instant>()
private fun monitorCase(): Flow<Event> = reactionSettings.showPopUpOnCaseOpen.flow
.flatMapLatest { isEnabled ->
if (isEnabled) {
deviceMonitor.primaryDevice().distinctUntilChangedBy { it?.rawDataHex }
} else {
emptyFlow()
}
private fun monitorCase(): Flow<Event> = deviceMonitor.primaryDevice()
.distinctUntilChangedBy {
// Re-emit on profile changes (eligibility) AND on raw BLE state changes (lid).
Triple(it?.profileId, it?.reactions?.showPopUpOnCaseOpen, it?.rawDataHex)
}
.withPrevious()
.setupCommonEventHandlers(TAG) { "popUpCase" }
.mapNotNull { (previous, current) ->
if (current?.caseLidState == null) {
return@mapNotNull null
val wasEligible = previous?.reactions?.showPopUpOnCaseOpen == true
val isEligible = current?.reactions?.showPopUpOnCaseOpen == true
// Eligibility transition: just lost it (toggled off, or switched to a profile
// with the toggle off). Dismiss any visible overlay immediately.
if (wasEligible && !isEligible) {
log(TAG) { "Case popup eligibility lost, emitting Hide" }
return@mapNotNull Event.PopupHide()
}
if (!isEligible) return@mapNotNull null
if (current.caseLidState == null) return@mapNotNull null
log(TAG, VERBOSE) {
"previous=${previous?.caseLidState}, current=${current.caseLidState}"
}
log(TAG, VERBOSE) { "previous-id=${previous?.identifier}, current-id=${current.identifier}" }
val isSameDeviceOrProfile = previous?.identifier == current.identifier ||
(previous?.profileId != null && previous.profileId == current.profileId)
val isSameDeviceOrProfile = previous?.profileId != null && previous.profileId == current.profileId
val isSameDeviceWithCaseNowOpen = isSameDeviceOrProfile && previous?.caseLidState != current.caseLidState
val isNewDeviceWithJustOpenedCase = !isSameDeviceOrProfile && previous?.caseLidState != current.caseLidState
val isNewDeviceWithJustOpenedCase = !isSameDeviceOrProfile
&& previous != null
&& previous.caseLidState != null
&& previous.caseLidState != current.caseLidState
if (!isSameDeviceWithCaseNowOpen && !isNewDeviceWithJustOpenedCase) {
return@mapNotNull null
@@ -66,7 +70,7 @@ class PopUpReaction @Inject constructor(
}
private fun throttleCasePopUps(current: PodDevice): Event? {
val cooldownKey = current.profileId ?: current.identifier.toString()
val cooldownKey = current.profileId ?: current.identifier?.toString() ?: return null
val now = Instant.now()
val lastShown = caseCoolDowns[cooldownKey]
@@ -99,38 +103,57 @@ class PopUpReaction @Inject constructor(
}
}
private val connectionCoolDowns = mutableMapOf<BluetoothAddress, Instant>()
private val connectionCoolDowns = java.util.concurrent.ConcurrentHashMap<BluetoothAddress, Instant>()
private fun monitorConnection(): Flow<Event> = reactionSettings.showPopUpOnConnection.flow
.flatMapLatest { isEnabled ->
if (!isEnabled) return@flatMapLatest emptyFlow()
private data class ConnectionWindow(
val direct: BluetoothDevice2?,
val broadcast: PodDevice?,
val eligible: Boolean,
)
combine(
bluetoothManager.connectedDevices,
deviceMonitor.primaryDevice().distinctUntilChangedBy { it?.rawDataHex },
) { devices, broadcast ->
log(TAG) { "$broadcast $devices " }
val primaryAddr = broadcast?.address
val direct = devices.singleOrNull { it.address == primaryAddr }.also {
log(TAG, VERBOSE) { "Connected main device is $it" }
}
if (direct == null) {
connectionCoolDowns.remove(primaryAddr).also {
if (it != null) log(TAG) { "Cleared connection cooldown for $primaryAddr due to disconect" }
}
}
if (direct != null && broadcast != null) direct to broadcast else null
private fun monitorConnection(): Flow<Event> = combine(
bluetoothManager.connectedDevices,
deviceMonitor.primaryDevice().distinctUntilChangedBy {
Triple(it?.profileId, it?.reactions?.showPopUpOnConnection, it?.rawDataHex)
},
) { devices, broadcast ->
val eligible = broadcast?.reactions?.showPopUpOnConnection == true
if (!eligible) {
ConnectionWindow(direct = null, broadcast = null, eligible = false)
} else {
val primaryAddr = broadcast.address
?: return@combine ConnectionWindow(direct = null, broadcast = null, eligible = false)
val direct = devices.singleOrNull { it.address == primaryAddr }.also {
log(TAG, VERBOSE) { "Connected main device is $it" }
}
if (direct == null) {
connectionCoolDowns.remove(primaryAddr).also {
if (it != null) log(TAG) { "Cleared connection cooldown for $primaryAddr due to disconnect" }
}
}
ConnectionWindow(direct = direct, broadcast = broadcast, eligible = true)
}
}
.withPrevious()
.mapNotNull { (previouss, currents) ->
val previousConnected = previouss?.first
.mapNotNull { (previous, current) ->
val wasEligible = previous?.eligible == true
val isEligible = current.eligible
// Eligibility transition: dismiss any visible overlay immediately.
if (wasEligible && !isEligible) {
log(TAG) { "Connection popup eligibility lost, emitting Hide" }
return@mapNotNull Event.PopupHide()
}
if (!isEligible) return@mapNotNull null
val previousConnected = previous?.direct
log(TAG, VERBOSE) { "previousConnected: $previousConnected" }
val previousBroadcasted = previouss?.second
val previousBroadcasted = previous?.broadcast
log(TAG, VERBOSE) { "previousBroadcasted: $previousBroadcasted" }
val currentConnected = currents?.first
val currentConnected = current.direct
log(TAG, VERBOSE) { "currentConnected: $currentConnected" }
val currentBroadcasted = currents?.second
val currentBroadcasted = current.broadcast
log(TAG, VERBOSE) { "currentBroadcasted: $currentBroadcasted" }
if (previousConnected != null && previousBroadcasted != null && currentConnected == null) {
@@ -1,26 +0,0 @@
package eu.darken.capod.reaction.ui
import androidx.navigation3.runtime.EntryProviderScope
import androidx.navigation3.runtime.NavKey
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import eu.darken.capod.common.navigation.Nav
import eu.darken.capod.common.navigation.NavigationEntry
import javax.inject.Inject
class ReactionSettingsNavigation @Inject constructor() : NavigationEntry {
override fun EntryProviderScope<NavKey>.setup() {
entry<Nav.Settings.Reactions> { ReactionSettingsScreenHost() }
}
@Module
@InstallIn(SingletonComponent::class)
abstract class Mod {
@Binds
@IntoSet
abstract fun bind(entry: ReactionSettingsNavigation): NavigationEntry
}
}
@@ -1,292 +0,0 @@
package eu.darken.capod.reaction.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
import androidx.compose.material.icons.twotone.BluetoothConnected
import androidx.compose.material.icons.twotone.LooksOne
import androidx.compose.material.icons.automirrored.twotone.Message
import androidx.compose.material.icons.twotone.PauseCircle
import androidx.compose.material.icons.twotone.PlayCircle
import androidx.compose.material.icons.twotone.QuestionMark
import androidx.compose.material.icons.twotone.Workspaces
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import eu.darken.capod.R
import eu.darken.capod.common.compose.Preview2
import eu.darken.capod.common.compose.PreviewWrapper
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import eu.darken.capod.common.error.ErrorEventHandler
import eu.darken.capod.common.navigation.NavigationEventHandler
import eu.darken.capod.common.settings.SettingsBaseItem
import eu.darken.capod.common.settings.SettingsCategoryHeader
import eu.darken.capod.common.settings.SettingsSwitchItem
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
@Composable
fun ReactionSettingsScreenHost(vm: ReactionSettingsViewModel = hiltViewModel()) {
ErrorEventHandler(vm)
NavigationEventHandler(vm)
val state by vm.state.collectAsStateWithLifecycle(initialValue = null)
state?.let {
ReactionSettingsScreen(
state = it,
onNavigateUp = { vm.navUp() },
onOnePodModeChanged = { enabled -> vm.setOnePodMode(enabled) },
onAutoPlayChanged = { enabled -> vm.setAutoPlay(enabled) },
onAutoPauseChanged = { enabled -> vm.setAutoPause(enabled) },
onAutoConnectChanged = { enabled -> vm.setAutoConnect(enabled) },
onAutoConnectConditionSelected = { condition -> vm.setAutoConnectCondition(condition) },
onShowPopUpOnCaseOpenChanged = { enabled -> vm.setShowPopUpOnCaseOpen(enabled) },
onShowPopUpOnConnectionChanged = { enabled -> vm.setShowPopUpOnConnection(enabled) },
)
}
}
@Composable
fun ReactionSettingsScreen(
state: ReactionSettingsViewModel.State,
onNavigateUp: () -> Unit,
onOnePodModeChanged: (Boolean) -> Unit,
onAutoPlayChanged: (Boolean) -> Unit,
onAutoPauseChanged: (Boolean) -> Unit,
onAutoConnectChanged: (Boolean) -> Unit,
onAutoConnectConditionSelected: (AutoConnectCondition) -> Unit,
onShowPopUpOnCaseOpenChanged: (Boolean) -> Unit,
onShowPopUpOnConnectionChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
var showAutoConnectConditionDialog by remember { mutableStateOf(false) }
Scaffold(
modifier = modifier,
topBar = {
TopAppBar(
title = { Text(text = stringResource(R.string.settings_reaction_label)) },
navigationIcon = {
IconButton(onClick = onNavigateUp) {
Icon(
imageVector = Icons.AutoMirrored.TwoTone.ArrowBack,
contentDescription = null,
)
}
},
)
},
) { innerPadding ->
LazyColumn(modifier = Modifier.padding(innerPadding)) {
item {
SettingsCategoryHeader(text = stringResource(R.string.settings_autopplay_label))
}
item {
SettingsBaseItem(
title = stringResource(R.string.settings_onepod_mode_label),
subtitle = stringResource(R.string.settings_onepod_mode_description),
icon = Icons.TwoTone.LooksOne,
onClick = { onOnePodModeChanged(!state.onePodMode) },
trailingContent = {
Switch(
checked = state.onePodMode,
onCheckedChange = onOnePodModeChanged,
modifier = Modifier.padding(start = 16.dp),
)
},
)
}
item {
SettingsSwitchItem(
icon = Icons.TwoTone.PlayCircle,
title = stringResource(R.string.settings_autopplay_label),
subtitle = stringResource(R.string.settings_autoplay_description),
checked = state.autoPlay,
onCheckedChange = onAutoPlayChanged,
requiresUpgrade = !state.isPro,
)
}
item {
SettingsSwitchItem(
icon = Icons.TwoTone.PauseCircle,
title = stringResource(R.string.settings_autopause_label),
subtitle = stringResource(R.string.settings_autopause_description),
checked = state.autoPause,
onCheckedChange = onAutoPauseChanged,
requiresUpgrade = !state.isPro,
)
}
item {
SettingsBaseItem(
title = stringResource(R.string.settings_eardetection_info_label),
subtitle = stringResource(R.string.settings_eardetection_info_description),
icon = Icons.TwoTone.QuestionMark,
onClick = {},
enabled = false,
)
}
item {
SettingsCategoryHeader(text = stringResource(R.string.settings_autoconnect_label))
}
item {
SettingsSwitchItem(
icon = Icons.TwoTone.BluetoothConnected,
title = stringResource(R.string.settings_autoconnect_label),
subtitle = stringResource(R.string.settings_autoconnect_description),
checked = state.autoConnect,
onCheckedChange = onAutoConnectChanged,
requiresUpgrade = !state.isPro,
)
}
item {
SettingsBaseItem(
title = stringResource(R.string.settings_autoconnect_condition_label),
subtitle = stringResource(state.autoConnectCondition.labelRes),
icon = Icons.TwoTone.Workspaces,
onClick = { if (state.autoConnect) showAutoConnectConditionDialog = true },
enabled = state.autoConnect,
)
}
item {
SettingsCategoryHeader(text = stringResource(R.string.settings_category_other_label))
}
item {
SettingsSwitchItem(
icon = Icons.AutoMirrored.TwoTone.Message,
title = stringResource(R.string.settings_popup_caseopen_label),
subtitle = stringResource(R.string.settings_popup_caseopen_description),
checked = state.showPopUpOnCaseOpen,
onCheckedChange = onShowPopUpOnCaseOpenChanged,
requiresUpgrade = !state.isPro,
)
}
item {
SettingsSwitchItem(
icon = Icons.AutoMirrored.TwoTone.Message,
title = stringResource(R.string.settings_popup_connected_label),
subtitle = stringResource(R.string.settings_popup_connected_description),
checked = state.showPopUpOnConnection,
onCheckedChange = onShowPopUpOnConnectionChanged,
requiresUpgrade = !state.isPro,
)
}
}
}
if (showAutoConnectConditionDialog) {
AlertDialog(
onDismissRequest = { showAutoConnectConditionDialog = false },
title = { Text(text = stringResource(R.string.settings_autoconnect_condition_label)) },
text = {
Column(Modifier.selectableGroup()) {
AutoConnectCondition.entries.forEach { condition ->
val isSelected = condition == state.autoConnectCondition
Row(
modifier = Modifier
.fillMaxWidth()
.selectable(
selected = isSelected,
onClick = {
onAutoConnectConditionSelected(condition)
showAutoConnectConditionDialog = false
},
role = Role.RadioButton,
)
.padding(vertical = 12.dp, horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = isSelected,
onClick = null,
)
Text(
text = stringResource(condition.labelRes),
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp),
)
}
}
}
},
confirmButton = {
TextButton(onClick = { showAutoConnectConditionDialog = false }) {
Text(text = stringResource(android.R.string.cancel))
}
},
)
}
}
@Preview2
@Composable
private fun ReactionSettingsScreenPreview() = PreviewWrapper {
ReactionSettingsScreen(
state = ReactionSettingsViewModel.State(
isPro = true,
onePodMode = false,
autoPlay = true,
autoPause = true,
autoConnect = false,
autoConnectCondition = AutoConnectCondition.WHEN_SEEN,
showPopUpOnCaseOpen = true,
showPopUpOnConnection = false,
),
onNavigateUp = {},
onOnePodModeChanged = {},
onAutoPlayChanged = {},
onAutoPauseChanged = {},
onAutoConnectChanged = {},
onAutoConnectConditionSelected = {},
onShowPopUpOnCaseOpenChanged = {},
onShowPopUpOnConnectionChanged = {},
)
}
@Preview2
@Composable
private fun ReactionSettingsScreenNonProPreview() = PreviewWrapper {
ReactionSettingsScreen(
state = ReactionSettingsViewModel.State(
isPro = false,
onePodMode = false,
autoPlay = false,
autoPause = false,
autoConnect = false,
autoConnectCondition = AutoConnectCondition.WHEN_SEEN,
showPopUpOnCaseOpen = false,
showPopUpOnConnection = false,
),
onNavigateUp = {},
onOnePodModeChanged = {},
onAutoPlayChanged = {},
onAutoPauseChanged = {},
onAutoConnectChanged = {},
onAutoConnectConditionSelected = {},
onShowPopUpOnCaseOpenChanged = {},
onShowPopUpOnConnectionChanged = {},
)
}
@@ -1,134 +0,0 @@
package eu.darken.capod.reaction.ui
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.navigation.Nav
import eu.darken.capod.common.uix.ViewModel4
import eu.darken.capod.common.upgrade.UpgradeRepo
import eu.darken.capod.main.core.GeneralSettings
import eu.darken.capod.main.core.MonitorMode
import eu.darken.capod.reaction.core.ReactionSettings
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import eu.darken.capod.common.datastore.valueBlocking
@HiltViewModel
class ReactionSettingsViewModel @Inject constructor(
dispatcherProvider: DispatcherProvider,
private val reactionSettings: ReactionSettings,
private val generalSettings: GeneralSettings,
private val upgradeRepo: UpgradeRepo,
) : ViewModel4(dispatcherProvider) {
data class State(
val isPro: Boolean,
val onePodMode: Boolean,
val autoPlay: Boolean,
val autoPause: Boolean,
val autoConnect: Boolean,
val autoConnectCondition: AutoConnectCondition,
val showPopUpOnCaseOpen: Boolean,
val showPopUpOnConnection: Boolean,
)
private val isPro = upgradeRepo.upgradeInfo.map { it.isPro }.asLiveState()
val state = combine(
isPro,
reactionSettings.onePodMode.flow,
reactionSettings.autoPlay.flow,
reactionSettings.autoPause.flow,
reactionSettings.autoConnect.flow,
reactionSettings.autoConnectCondition.flow,
reactionSettings.showPopUpOnCaseOpen.flow,
reactionSettings.showPopUpOnConnection.flow,
) { values ->
State(
isPro = values[0] as Boolean,
onePodMode = values[1] as Boolean,
autoPlay = values[2] as Boolean,
autoPause = values[3] as Boolean,
autoConnect = values[4] as Boolean,
autoConnectCondition = values[5] as AutoConnectCondition,
showPopUpOnCaseOpen = values[6] as Boolean,
showPopUpOnConnection = values[7] as Boolean,
)
}.asLiveState()
fun setOnePodMode(enabled: Boolean) {
reactionSettings.onePodMode.valueBlocking = enabled
}
fun setAutoPlay(enabled: Boolean) = launch {
if (!enabled) {
reactionSettings.autoPlay.valueBlocking = false
return@launch
}
if (isPro.first()) {
reactionSettings.autoPlay.valueBlocking = true
} else {
navTo(Nav.Main.Upgrade)
}
}
fun setAutoPause(enabled: Boolean) = launch {
if (!enabled) {
reactionSettings.autoPause.valueBlocking = false
return@launch
}
if (isPro.first()) {
reactionSettings.autoPause.valueBlocking = true
} else {
navTo(Nav.Main.Upgrade)
}
}
fun setAutoConnect(enabled: Boolean) = launch {
if (!enabled) {
reactionSettings.autoConnect.valueBlocking = false
return@launch
}
if (isPro.first()) {
reactionSettings.autoConnect.valueBlocking = true
generalSettings.monitorMode.valueBlocking = MonitorMode.ALWAYS
} else {
navTo(Nav.Main.Upgrade)
}
}
fun setAutoConnectCondition(condition: AutoConnectCondition) {
reactionSettings.autoConnectCondition.valueBlocking = condition
}
fun setShowPopUpOnCaseOpen(enabled: Boolean) = launch {
if (!enabled) {
reactionSettings.showPopUpOnCaseOpen.valueBlocking = false
return@launch
}
if (isPro.first()) {
reactionSettings.showPopUpOnCaseOpen.valueBlocking = true
} else {
navTo(Nav.Main.Upgrade)
}
}
fun setShowPopUpOnConnection(enabled: Boolean) = launch {
if (!enabled) {
reactionSettings.showPopUpOnConnection.valueBlocking = false
return@launch
}
if (isPro.first()) {
reactionSettings.showPopUpOnConnection.valueBlocking = true
} else {
navTo(Nav.Main.Upgrade)
}
}
companion object {
private val TAG = logTag("Settings", "Reaction", "VM")
}
}
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod word deur een persoon ontwikkel. Opgradering ontsluit ekstra funksies en help om die app aan die lewe te hou.</string>
<string name="upgrade_benefit_themes">Tema-aanpassing</string>
<string name="upgrade_benefit_autoplay">Outo-speel &amp; outo-pouseer</string>
<string name="upgrade_benefit_autoconnect">Outo-koppel</string>
<string name="upgrade_benefit_popups">Opspringvenster by kas oop &amp; verbinding</string>
<string name="upgrade_benefit_widgets">Tuisskerm-widgets</string>
<string name="upgrade_benefit_device_settings">Gevorderde toestel-instellings</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Toestelle</string>
<string name="settings_devices_description">Bestuur jou toestelle.</string>
<string name="settings_reaction_label">Reaksies</string>
<string name="settings_reaction_description">Reageer op gebeure en gedrag.</string>
<string name="settings_category_yourdevice_label">Jou toestel</string>
<string name="settings_category_compatibility_options_title">Verenigbaarheidsopsies</string>
<string name="settings_category_compatibility_options_description">Moenie aanraak as alles werk nie ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod በአንድ ሰው ብቻ ተዘጋጅቷል። ማሻሻያ ተጨማሪ ባህሪያትን ያስከፍትና መተግበሪያውን ህያው ለማቆየት ይረዳል።</string>
<string name="upgrade_benefit_themes">ጭብጥ ብጁ አሰናዳ</string>
<string name="upgrade_benefit_autoplay">ራስ-ሰር አጫውት &amp; ራስ-ሰር አቁም</string>
<string name="upgrade_benefit_autoconnect">ራስ-ሰር ግንኙነት</string>
<string name="upgrade_benefit_popups">ቴሌ ሲከፈት &amp; ሲገናኝ ፖፕ-አፕ</string>
<string name="upgrade_benefit_widgets">የመነሻ ስክሪን ዊጀቶች</string>
<string name="upgrade_benefit_device_settings">የተሻሻሉ የመሣሪያ ቅንብሮች</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">መሳሪያዎች</string>
<string name="settings_devices_description">መሳሪያዎችዎን ያስተዳድሩ።</string>
<string name="settings_reaction_label">ግብረመልሶች</string>
<string name="settings_reaction_description">ለክስተቶች እና ባህሪዎች ምላሽ ይስጡ።</string>
<string name="settings_category_yourdevice_label">የእርስዎ መሣሪያ</string>
<string name="settings_category_compatibility_options_title">የተኳኋኝነት አማራጮች</string>
<string name="settings_category_compatibility_options_description">ሁሉም ነገር የሚሰራ ከሆነ አይንኩ ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">تم تطوير CAPod من قِبل شخص واحد. الترقية تفتح ميزات إضافية وتساعد في إبقاء التطبيق حياً.</string>
<string name="upgrade_benefit_themes">تخصيص السمة</string>
<string name="upgrade_benefit_autoplay">تشغيل تلقائي وإيقاف مؤقت تلقائي</string>
<string name="upgrade_benefit_autoconnect">اتصال تلقائي</string>
<string name="upgrade_benefit_popups">نافذة منبثقة عند فتح الغطاء والاتصال</string>
<string name="upgrade_benefit_widgets">عناصر واجهة الشاشة الرئيسية</string>
<string name="upgrade_benefit_device_settings">إعدادات الجهاز المتقدمة</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">الأجهزة</string>
<string name="settings_devices_description">إدارة أجهزتك.</string>
<string name="settings_reaction_label">ردود الفعل</string>
<string name="settings_reaction_description">التفاعل مع الأحداث والسلوكيات.</string>
<string name="settings_category_yourdevice_label">جهازك</string>
<string name="settings_category_compatibility_options_title">خيارات التوافق</string>
<string name="settings_category_compatibility_options_description">لا تلمس إذا كان كل شيء يعمل ؛)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod tək bir şəxs tərəfindən hazırlanıb. Yüksəltmə əlavə funksiyaları açır və tətbiqin yaşamasına kömək edir.</string>
<string name="upgrade_benefit_themes">Tema fərdiləşdirməsi</string>
<string name="upgrade_benefit_autoplay">Avtomatik oynat və avtomatik dayandır</string>
<string name="upgrade_benefit_autoconnect">Avtomatik qoşulma</string>
<string name="upgrade_benefit_popups">Qutunu açarkən və qoşulduqda açılan pəncərə</string>
<string name="upgrade_benefit_widgets">Ana ekran vidcetləri</string>
<string name="upgrade_benefit_device_settings">Qabaqcıl cihaz parametrləri</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Cihazlar</string>
<string name="settings_devices_description">Cihazlarınızı idarə edin.</string>
<string name="settings_reaction_label">Reaksiyalar</string>
<string name="settings_reaction_description">Hadisələrə və davranışlara reaksiya verin.</string>
<string name="settings_category_yourdevice_label">Sizin cihazınız</string>
<string name="settings_category_compatibility_options_title">Uyğunluq seçimləri</string>
<string name="settings_category_compatibility_options_description">Hər şey işləyirsə toxunmayın ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod распрацаваны адным чалавекам. Абнаўленне разблакоўвае дадатковыя функцыі і дапамагае трымаць праграму ў жывых.</string>
<string name="upgrade_benefit_themes">Наладка тэм</string>
<string name="upgrade_benefit_autoplay">Аўтаматычнае прайграванне і паўза</string>
<string name="upgrade_benefit_autoconnect">Аўтаматычнае падключэнне</string>
<string name="upgrade_benefit_popups">Усплывальнае акно пры адкрыцці скрынкі і падключэнні</string>
<string name="upgrade_benefit_widgets">Віджэты галоўнага экрана</string>
<string name="upgrade_benefit_device_settings">Пашыраныя налады прылады</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Прылады</string>
<string name="settings_devices_description">Кіруйце вашымі прыладамі.</string>
<string name="settings_reaction_label">Рэакцыі</string>
<string name="settings_reaction_description">Рэагаваць на падзеі і паводзіны.</string>
<string name="settings_category_yourdevice_label">Ваша прылада</string>
<string name="settings_category_compatibility_options_title">Параметры сумяшчальнасці</string>
<string name="settings_category_compatibility_options_description">Не чапайце, калі ўсё працуе ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod е разработен от един човек. Надграждането отключва допълнителни функции и помага да поддържате приложението живо.</string>
<string name="upgrade_benefit_themes">Персонализиране на тема</string>
<string name="upgrade_benefit_autoplay">Автоматично възпроизвеждане и пауза</string>
<string name="upgrade_benefit_autoconnect">Автоматично свързване</string>
<string name="upgrade_benefit_popups">Изскачащ прозорец при отваряне на калъфа и свързване</string>
<string name="upgrade_benefit_widgets">Джаджи на началния екран</string>
<string name="upgrade_benefit_device_settings">Разширени настройки на устройството</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Устройства</string>
<string name="settings_devices_description">Управлявайте устройствата си.</string>
<string name="settings_reaction_label">Реакции</string>
<string name="settings_reaction_description">Реагирайте на събития и поведения.</string>
<string name="settings_category_yourdevice_label">Вашето устройство</string>
<string name="settings_category_compatibility_options_title">Опции за съвместимост</string>
<string name="settings_category_compatibility_options_description">Не пипайте, ако всичко работи ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod একজন একক ব্যক্তি দ্বারা তৈরি। আপগ্রেড করলে অতিরিক্ত বৈশিষ্ট্য আনলক হয় এবং অ্যাপটি বাঁচিয়ে রাখতে সহায়তা করে।</string>
<string name="upgrade_benefit_themes">থিম কাস্টমাইজেশন</string>
<string name="upgrade_benefit_autoplay">স্বয়ংক্রিয় প্লে এবং স্বয়ংক্রিয় পজ</string>
<string name="upgrade_benefit_autoconnect">স্বয়ংক্রিয় সংযোগ</string>
<string name="upgrade_benefit_popups">কেস খোলা ও সংযোগের সময় পপআপ</string>
<string name="upgrade_benefit_widgets">হোম স্ক্রিন উইজেট</string>
<string name="upgrade_benefit_device_settings">উন্নত ডিভাইস সেটিংস</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">ডিভাইস</string>
<string name="settings_devices_description">আপনার ডিভাইসগুলি পরিচালনা করুন।</string>
<string name="settings_reaction_label">প্রতিক্রিয়া</string>
<string name="settings_reaction_description">ঘটনা এবং আচরণের প্রতি প্রতিক্রিয়া জানান।</string>
<string name="settings_category_yourdevice_label">আপনার ডিভাইস</string>
<string name="settings_category_compatibility_options_title">সামঞ্জস্যতার বিকল্প</string>
<string name="settings_category_compatibility_options_description">সবকিছু কাজ করলে স্পর্শ করবেন না ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">El CAPod està desenvolupat per una sola persona. La millora desbloqueja funcions addicionals i ajuda a mantenir l\'aplicació activa.</string>
<string name="upgrade_benefit_themes">Personalització de temes</string>
<string name="upgrade_benefit_autoplay">Reproducció i pausa automàtica</string>
<string name="upgrade_benefit_autoconnect">Connexió automàtica</string>
<string name="upgrade_benefit_popups">Finestra emergent en obrir la funda i en connectar</string>
<string name="upgrade_benefit_widgets">Ginys de la pantalla d\'inici</string>
<string name="upgrade_benefit_device_settings">Configuració avançada del dispositiu</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositius</string>
<string name="settings_devices_description">Gestioneu els dispositius.</string>
<string name="settings_reaction_label">Reaccions</string>
<string name="settings_reaction_description">Reacció davant esdeveniments i comportaments.</string>
<string name="settings_category_yourdevice_label">El vostre dispositiu</string>
<string name="settings_category_compatibility_options_title">Opcions de compatibilitat</string>
<string name="settings_category_compatibility_options_description">No ho toqueu si tot funciona ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod vyvíjí jediná osoba. Upgrade odemkne další funkce a pomůže udržet aplikaci naživu.</string>
<string name="upgrade_benefit_themes">Přizpůsobení motivu</string>
<string name="upgrade_benefit_autoplay">Automatické přehrávání a pozastavení</string>
<string name="upgrade_benefit_autoconnect">Automatické připojení</string>
<string name="upgrade_benefit_popups">Vyskakovací okno při otevření a připojení</string>
<string name="upgrade_benefit_widgets">Widgety domovské obrazovky</string>
<string name="upgrade_benefit_device_settings">Pokročilá nastavení zařízení</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Zařízení</string>
<string name="settings_devices_description">Správa zařízení.</string>
<string name="settings_reaction_label">Reakce</string>
<string name="settings_reaction_description">Reakce na události a chování.</string>
<string name="settings_category_yourdevice_label">Vaše zařízení</string>
<string name="settings_category_compatibility_options_title">Možnosti kompatibility</string>
<string name="settings_category_compatibility_options_description">Nedotýkejte se, pokud vše funguje ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod er udviklet af én person. Opgradering låser ekstra funktioner op og hjælper med at holde appen i live.</string>
<string name="upgrade_benefit_themes">Tema-tilpasning</string>
<string name="upgrade_benefit_autoplay">Auto-afspilning &amp; auto-pause</string>
<string name="upgrade_benefit_autoconnect">Auto-tilslut</string>
<string name="upgrade_benefit_popups">Popup ved åbning af etui &amp; tilslutning</string>
<string name="upgrade_benefit_widgets">Startskærm-widgets</string>
<string name="upgrade_benefit_device_settings">Avancerede enhedsindstillinger</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Enheder</string>
<string name="settings_devices_description">Administrer dine enheder.</string>
<string name="settings_reaction_label">Reaktioner</string>
<string name="settings_reaction_description">Reager på begivenheder og adfærd.</string>
<string name="settings_category_yourdevice_label">Din enhed</string>
<string name="settings_category_compatibility_options_title">Kompatibilitetsindstillinger</string>
<string name="settings_category_compatibility_options_description">Rør ikke, hvis alt virker ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod wird von einer einzelnen Person entwickelt. Ein Upgrade schaltet zusätzliche Funktionen frei und hilft, die App am Leben zu erhalten.</string>
<string name="upgrade_benefit_themes">Design-Anpassung</string>
<string name="upgrade_benefit_autoplay">Automatische Wiedergabe &amp; automatisches Pausieren</string>
<string name="upgrade_benefit_autoconnect">Automatisch verbinden</string>
<string name="upgrade_benefit_popups">Popup beim Öffnen des Cases &amp; bei Verbindung</string>
<string name="upgrade_benefit_widgets">Startbildschirm-Widgets</string>
<string name="upgrade_benefit_device_settings">Erweiterte Geräteeinstellungen</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Geräte</string>
<string name="settings_devices_description">Verwalte Deine Geräte.</string>
<string name="settings_reaction_label">Reaktionen</string>
<string name="settings_reaction_description">Reagier auf Ereignisse und Verhaltensweisen.</string>
<string name="settings_category_yourdevice_label">Dein Gerät</string>
<string name="settings_category_compatibility_options_title">Kompatibilitätsoptionen</string>
<string name="settings_category_compatibility_options_description">Nicht anfassen, wenn alles funktioniert ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">Το CAPod αναπτύσσεται από ένα μόνο άτομο. Η αναβάθμιση ξεκλειδώνει επιπλέον λειτουργίες και βοηθά στη συνέχεια της εφαρμογής.</string>
<string name="upgrade_benefit_themes">Προσαρμογή θέματος</string>
<string name="upgrade_benefit_autoplay">Αυτόματη αναπαραγωγή &amp; αυτόματη παύση</string>
<string name="upgrade_benefit_autoconnect">Αυτόματη σύνδεση</string>
<string name="upgrade_benefit_popups">Αναδυόμενο παράθυρο κατά το άνοιγμα θήκης &amp; σύνδεση</string>
<string name="upgrade_benefit_widgets">Γραφικά στοιχεία αρχικής οθόνης</string>
<string name="upgrade_benefit_device_settings">Προηγμένες ρυθμίσεις συσκευής</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Συσκευές</string>
<string name="settings_devices_description">Διαχειριστείτε τις συσκευές σας.</string>
<string name="settings_reaction_label">Αντιδράσεις</string>
<string name="settings_reaction_description">Αντίδραση σε συμβάντα και συμπεριφορές.</string>
<string name="settings_category_yourdevice_label">Η συσκευή σας</string>
<string name="settings_category_compatibility_options_title">Επιλογές συμβατότητας</string>
<string name="settings_category_compatibility_options_description">Μην αγγίζετε αν όλα λειτουργούν ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod es desarrollado por una sola persona. Actualizar desbloquea funciones extra y ayuda a mantener la app viva.</string>
<string name="upgrade_benefit_themes">Personalización de tema</string>
<string name="upgrade_benefit_autoplay">Reproducción automática y pausa automática</string>
<string name="upgrade_benefit_autoconnect">Conexión automática</string>
<string name="upgrade_benefit_popups">Ventana emergente al abrir el estuche y al conectar</string>
<string name="upgrade_benefit_widgets">Widgets de pantalla de inicio</string>
<string name="upgrade_benefit_device_settings">Configuración avanzada del dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Gestionar tus dispositivos.</string>
<string name="settings_reaction_label">Reacciones</string>
<string name="settings_reaction_description">Reaccionar a eventos y comportamientos.</string>
<string name="settings_category_yourdevice_label">Tu dispositivo</string>
<string name="settings_category_compatibility_options_title">Opciones de compatibilidad</string>
<string name="settings_category_compatibility_options_description">No tocar si todo funciona ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod es desarrollado por una sola persona. Actualizar desbloquea funciones adicionales y ayuda a mantener la aplicación activa.</string>
<string name="upgrade_benefit_themes">Personalización de temas</string>
<string name="upgrade_benefit_autoplay">Reproducción automática y pausa automática</string>
<string name="upgrade_benefit_autoconnect">Conexión automática</string>
<string name="upgrade_benefit_popups">Popup al abrir la funda y conexión</string>
<string name="upgrade_benefit_widgets">Widgets de pantalla de inicio</string>
<string name="upgrade_benefit_device_settings">Ajustes avanzados del dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Gestionar tus dispositivos.</string>
<string name="settings_reaction_label">Reacciones</string>
<string name="settings_reaction_description">Reaccionar a eventos y comportamientos.</string>
<string name="settings_category_yourdevice_label">Tu dispositivo</string>
<string name="settings_category_compatibility_options_title">Opciones de compatibilidad</string>
<string name="settings_category_compatibility_options_description">No tocar si todo funciona ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod es desarrollado por una sola persona. Actualizar desbloquea funciones adicionales y ayuda a mantener la app viva.</string>
<string name="upgrade_benefit_themes">Personalización de tema</string>
<string name="upgrade_benefit_autoplay">Reproducción automática y pausa automática</string>
<string name="upgrade_benefit_autoconnect">Conexión automática</string>
<string name="upgrade_benefit_popups">Ventana emergente al abrir el estuche y al conectar</string>
<string name="upgrade_benefit_widgets">Widgets de pantalla de inicio</string>
<string name="upgrade_benefit_device_settings">Configuración avanzada del dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Gestionar tus dispositivos.</string>
<string name="settings_reaction_label">Reacciones</string>
<string name="settings_reaction_description">Reaccionar a eventos y comportamientos.</string>
<string name="settings_category_yourdevice_label">Tu dispositivo</string>
<string name="settings_category_compatibility_options_title">Opciones de compatibilidad</string>
<string name="settings_category_compatibility_options_description">No toques si todo funciona ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPodi arendab üks inimene. Uuendamine avab lisavõimalused ja aitab rakendust arendada.</string>
<string name="upgrade_benefit_themes">Teema kohandamine</string>
<string name="upgrade_benefit_autoplay">Automaatesitus ja automaatne paus</string>
<string name="upgrade_benefit_autoconnect">Automaatne ühendamine</string>
<string name="upgrade_benefit_popups">Hüpikaken korpuse avamisel ja ühendamisel</string>
<string name="upgrade_benefit_widgets">Avakuva vidinad</string>
<string name="upgrade_benefit_device_settings">Täpsemad seadme sätted</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Seadmed</string>
<string name="settings_devices_description">Seadmete haldamine.</string>
<string name="settings_reaction_label">Reaktsioonid</string>
<string name="settings_reaction_description">Reageerige sündmustele ja tegevustele.</string>
<string name="settings_category_yourdevice_label">Teie seade</string>
<string name="settings_category_compatibility_options_title">Ühilduvuse valikud</string>
<string name="settings_category_compatibility_options_description">Las jääda, kui kõik toimib ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod pertsona bakar batek garatzen du. Berrituz gero, funtzio gehigarriak desblokeatzen dira eta aplikazioa bizirik mantentzen laguntzen duzu.</string>
<string name="upgrade_benefit_themes">Gai pertsonalizazioa</string>
<string name="upgrade_benefit_autoplay">Erreprodukzio automatikoa eta eten automatikoa</string>
<string name="upgrade_benefit_autoconnect">Automatikoki konektatu</string>
<string name="upgrade_benefit_popups">Leiho gainerakorra kutxako irekieran eta konexioan</string>
<string name="upgrade_benefit_widgets">Hasierako pantailako widgetak</string>
<string name="upgrade_benefit_device_settings">Gailuaren ezarpen aurreratuak</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Gailuak</string>
<string name="settings_devices_description">Kudeatu zure gailuak.</string>
<string name="settings_reaction_label">Erreakzioak</string>
<string name="settings_reaction_description">Erreakzionatu gertaera eta portaerei.</string>
<string name="settings_category_yourdevice_label">Zure gailua</string>
<string name="settings_category_compatibility_options_title">Bateragarritasun aukerak</string>
<string name="settings_category_compatibility_options_description">Ez ukitu dena ondo badabil ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod توسط یک نفر توسعه داده می‌شود. ارتقا دادن ویژگی‌های اضافی را باز می‌کند و به زنده نگه داشتن برنامه کمک می‌کند.</string>
<string name="upgrade_benefit_themes">سفارشی‌سازی پوسته</string>
<string name="upgrade_benefit_autoplay">پخش خودکار و توقف خودکار</string>
<string name="upgrade_benefit_autoconnect">اتصال خودکار</string>
<string name="upgrade_benefit_popups">پنجره‌ی بازشو هنگام باز کردن جعبه و اتصال</string>
<string name="upgrade_benefit_widgets">ابزارک‌های صفحه‌ی اصلی</string>
<string name="upgrade_benefit_device_settings">تنظیمات پیشرفته دستگاه</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">دستگاه‌ها</string>
<string name="settings_devices_description">مدیریت دستگاه‌های شما.</string>
<string name="settings_reaction_label">واکنش‌ها</string>
<string name="settings_reaction_description">به رویدادها و رفتارها واکنش نشان دهید.</string>
<string name="settings_category_yourdevice_label">دستگاه شما</string>
<string name="settings_category_compatibility_options_title">گزینه‌های سازگاری</string>
<string name="settings_category_compatibility_options_description">اگر همه چیز کار می‌کند، دست نزنید ؛)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod on yhden henkilön kehittämä. Päivittäminen avaa lisäominaisuuksia ja auttaa pitämään sovelluksen hengissä.</string>
<string name="upgrade_benefit_themes">Teeman mukauttaminen</string>
<string name="upgrade_benefit_autoplay">Automaattinen toisto &amp; tauko</string>
<string name="upgrade_benefit_autoconnect">Automaattinen yhdistäminen</string>
<string name="upgrade_benefit_popups">Ponnahdusikkuna koteloa avattaessa &amp; yhdistettäessä</string>
<string name="upgrade_benefit_widgets">Aloitusnäytön widgetit</string>
<string name="upgrade_benefit_device_settings">Laitteiden lisäasetukset</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Laitteet</string>
<string name="settings_devices_description">Hallitse laitteitasi.</string>
<string name="settings_reaction_label">Reaktiot</string>
<string name="settings_reaction_description">Reagoi tapahtumiin ja käyttäytymiseen.</string>
<string name="settings_category_yourdevice_label">Laitteesi</string>
<string name="settings_category_compatibility_options_title">Yhteensopivuusasetukset</string>
<string name="settings_category_compatibility_options_description">Älä koske, jos kaikki toimii ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">Ang CAPod ay ginawa ng isang tao. Ang pag-upgrade ay nagbubukas ng mga karagdagang feature at tumutulong na mapanatiling buhay ang app.</string>
<string name="upgrade_benefit_themes">Pag-customize ng tema</string>
<string name="upgrade_benefit_autoplay">Auto-play &amp; auto-pause</string>
<string name="upgrade_benefit_autoconnect">Auto-connect</string>
<string name="upgrade_benefit_popups">Popup sa pagbubukas ng case &amp; koneksyon</string>
<string name="upgrade_benefit_widgets">Mga widget ng home screen</string>
<string name="upgrade_benefit_device_settings">Mga advanced na setting ng device</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Mga Device</string>
<string name="settings_devices_description">Pamahalaan ang iyong mga device.</string>
<string name="settings_reaction_label">Mga Reaksyon</string>
<string name="settings_reaction_description">Mag-react sa mga kaganapan at pag-uugali.</string>
<string name="settings_category_yourdevice_label">Iyong device</string>
<string name="settings_category_compatibility_options_title">Mga opsyon sa compatibility</string>
<string name="settings_category_compatibility_options_description">Huwag galawin kung gumagana ang lahat ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod est développée par une seule personne. Passer à la version Pro déverrouille des fonctions supplémentaires et contribue à la pérennité de lappli.</string>
<string name="upgrade_benefit_themes">Personnalisation du thème</string>
<string name="upgrade_benefit_autoplay">Lecture et pause automatiques</string>
<string name="upgrade_benefit_autoconnect">Connexion automatique</string>
<string name="upgrade_benefit_popups">Fenêtre de notification à l\'ouverture de l\'étui et à la connexion</string>
<string name="upgrade_benefit_widgets">Widgets sur l’écran daccueil</string>
<string name="upgrade_benefit_device_settings">Paramètres avancés de lappareil</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Appareils</string>
<string name="settings_devices_description">Gérez vos appareils.</string>
<string name="settings_reaction_label">Réactions</string>
<string name="settings_reaction_description">Réagir à des événements et à des comportements.</string>
<string name="settings_category_yourdevice_label">Votre appareil</string>
<string name="settings_category_compatibility_options_title">Options de compatibilité</string>
<string name="settings_category_compatibility_options_description">Ne rien changer rien si tout fonctionne ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod está desenvolvido por unha soa persoa. Actualizar desbloquea funcionalidades adicionais e axuda a manter a aplicación viva.</string>
<string name="upgrade_benefit_themes">Personalización de temas</string>
<string name="upgrade_benefit_autoplay">Reprodución automática e pausa automática</string>
<string name="upgrade_benefit_autoconnect">Conexión automática</string>
<string name="upgrade_benefit_popups">Ventá emerxente ao abrir a funda e ao conectar</string>
<string name="upgrade_benefit_widgets">Widgets da pantalla de inicio</string>
<string name="upgrade_benefit_device_settings">Configuración avanzada do dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Xestiona os teus dispositivos.</string>
<string name="settings_reaction_label">Reaccións</string>
<string name="settings_reaction_description">Reaccionar a eventos e comportamentos.</string>
<string name="settings_category_yourdevice_label">O teu dispositivo</string>
<string name="settings_category_compatibility_options_title">Opcións de compatibilidade</string>
<string name="settings_category_compatibility_options_description">Non tocar se todo funciona ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod एक अकेले व्यक्ति द्वारा विकसित किया गया है। अपग्रेड करने से अतिरिक्त सुविधाएं अनलॉक होती हैं और ऐप को जीवित रखने में मदद मिलती है।</string>
<string name="upgrade_benefit_themes">थीम अनुकूलन</string>
<string name="upgrade_benefit_autoplay">ऑटो-प्ले और ऑटो-पॉज़</string>
<string name="upgrade_benefit_autoconnect">ऑटो-कनेक्ट</string>
<string name="upgrade_benefit_popups">केस खोलने और कनेक्शन पर पॉपअप</string>
<string name="upgrade_benefit_widgets">होम स्क्रीन विजेट</string>
<string name="upgrade_benefit_device_settings">उन्नत डिवाइस सेटिंग्स</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">डिवाइस</string>
<string name="settings_devices_description">अपने डिवाइस प्रबंधित करें।</string>
<string name="settings_reaction_label">प्रतिक्रियाएँ</string>
<string name="settings_reaction_description">घटनाओं और व्यवहारों पर प्रतिक्रिया दें।</string>
<string name="settings_category_yourdevice_label">आपका डिवाइस</string>
<string name="settings_category_compatibility_options_title">संगतता विकल्प</string>
<string name="settings_category_compatibility_options_description">अगर सब कुछ काम कर रहा है तो स्पर्श न करें ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod razvija jedna osoba. Nadogradnja otključava dodatne značajke i pomaže da aplikacija ostane aktivna.</string>
<string name="upgrade_benefit_themes">Prilagodba tema</string>
<string name="upgrade_benefit_autoplay">Automatska reprodukcija i pauza</string>
<string name="upgrade_benefit_autoconnect">Automatsko povezivanje</string>
<string name="upgrade_benefit_popups">Skočni prozor pri otvaranju kutije i spajanju</string>
<string name="upgrade_benefit_widgets">Widgeti početnog zaslona</string>
<string name="upgrade_benefit_device_settings">Napredne postavke uređaja</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Uređaji</string>
<string name="settings_devices_description">Upravljajte svojim uređajima.</string>
<string name="settings_reaction_label">Reakcije</string>
<string name="settings_reaction_description">Reagirajte na događaje i ponašanja.</string>
<string name="settings_category_yourdevice_label">Vaš uređaj</string>
<string name="settings_category_compatibility_options_title">Opcije kompatibilnosti</string>
<string name="settings_category_compatibility_options_description">Ne dirajte ako sve radi ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">A CAPod-ot egyetlen fejlesztő készíti. A frissítéssel extra funkciókat érhetsz el, és segíted az alkalmazás életben tartását.</string>
<string name="upgrade_benefit_themes">Téma testreszabás</string>
<string name="upgrade_benefit_autoplay">Automatikus lejátszás és szüneteltetés</string>
<string name="upgrade_benefit_autoconnect">Automatikus csatlakozás</string>
<string name="upgrade_benefit_popups">Felugró ablak tok megnyitásakor és csatlakozáskor</string>
<string name="upgrade_benefit_widgets">Kezdőképernyő-widgetek</string>
<string name="upgrade_benefit_device_settings">Speciális eszközbeállítások</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Eszközök</string>
<string name="settings_devices_description">Eszközök kezelése.</string>
<string name="settings_reaction_label">Reakciók</string>
<string name="settings_reaction_description">Reagáljon az eseményekre és viselkedésekre.</string>
<string name="settings_category_yourdevice_label">Eszközei</string>
<string name="settings_category_compatibility_options_title">Kompatibilitási opciók</string>
<string name="settings_category_compatibility_options_description">Ezekhez ne nyúljon, ha minden jól műkődik ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod-ը մշակվում է մեկ անձի կողմից: Բարելավելը բացում է լրացուցիչ հնարավորություններ եւ օգնում է հավելվածը կենդանի պահել:</string>
<string name="upgrade_benefit_themes">Թեմայի հարմարեցում</string>
<string name="upgrade_benefit_autoplay">Ավտոնվագում &amp; ավտոդադար</string>
<string name="upgrade_benefit_autoconnect">Ինքնամիացում</string>
<string name="upgrade_benefit_popups">Թռուցիկ՝ պատյան բացելիս &amp; կապվելիս</string>
<string name="upgrade_benefit_widgets">Գլխավոր էկրանի վիջեթներ</string>
<string name="upgrade_benefit_device_settings">Սառքի լրացկին կառավարումներ</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Սարքեր</string>
<string name="settings_devices_description">Կառավարեք ձեր սարքերը։</string>
<string name="settings_reaction_label">Արձագանքներ</string>
<string name="settings_reaction_description">Արձագանքեք իրադարձություններին և վարքագծերին։</string>
<string name="settings_category_yourdevice_label">Ձեր սարքը</string>
<string name="settings_category_compatibility_options_title">Համատեղելիության ընտրանքներ</string>
<string name="settings_category_compatibility_options_description">Մի դիպչեք, եթե ամեն ինչ աշխատում է ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod dikembangkan oleh satu orang. Meningkatkan versi membuka fitur tambahan dan membantu menjaga aplikasi tetap berjalan.</string>
<string name="upgrade_benefit_themes">Kustomisasi tema</string>
<string name="upgrade_benefit_autoplay">Putar otomatis &amp; jeda otomatis</string>
<string name="upgrade_benefit_autoconnect">Sambungkan otomatis</string>
<string name="upgrade_benefit_popups">Popup saat kotak dibuka &amp; dihubungkan</string>
<string name="upgrade_benefit_widgets">Widget layar beranda</string>
<string name="upgrade_benefit_device_settings">Pengaturan perangkat lanjutan</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Perangkat</string>
<string name="settings_devices_description">Kelola perangkat Anda.</string>
<string name="settings_reaction_label">Reaksi</string>
<string name="settings_reaction_description">Bereaksi terhadap peristiwa dan perilaku.</string>
<string name="settings_category_yourdevice_label">Perangkat Anda</string>
<string name="settings_category_compatibility_options_title">Opsi kompatibilitas</string>
<string name="settings_category_compatibility_options_description">Jangan sentuh jika semuanya berfungsi ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod er þróað af einum einstaklingi. Uppfærsla opnar aukaeiginleika og hjálpar til við að halda forritinu lifandi.</string>
<string name="upgrade_benefit_themes">Sérsniðið þema</string>
<string name="upgrade_benefit_autoplay">Sjálfvirk spilun og hlé</string>
<string name="upgrade_benefit_autoconnect">Sjálfvirk tenging</string>
<string name="upgrade_benefit_popups">Sprettigluggi við opnun hulsins og tengingu</string>
<string name="upgrade_benefit_widgets">Heimaskjáviðbætur</string>
<string name="upgrade_benefit_device_settings">Tæki stillingar (avanó)</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Tæki</string>
<string name="settings_devices_description">Hafa umsjón með tækjunum þínum.</string>
<string name="settings_reaction_label">Viðbrögð</string>
<string name="settings_reaction_description">Bregðast við atburðum og hegðun.</string>
<string name="settings_category_yourdevice_label">Tækið þitt</string>
<string name="settings_category_compatibility_options_title">Samhæfisvalkostir</string>
<string name="settings_category_compatibility_options_description">Ekki snerta ef allt virkar ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod è sviluppato da una singola persona. Aggiornare sblocca funzionalità extra e aiuta a mantenere l\'app in vita.</string>
<string name="upgrade_benefit_themes">Personalizzazione tema</string>
<string name="upgrade_benefit_autoplay">Riproduzione automatica e pausa automatica</string>
<string name="upgrade_benefit_autoconnect">Connessione automatica</string>
<string name="upgrade_benefit_popups">Popup all\'apertura della custodia e alla connessione</string>
<string name="upgrade_benefit_widgets">Widget della schermata home</string>
<string name="upgrade_benefit_device_settings">Impostazioni avanzate dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivi</string>
<string name="settings_devices_description">Gestisci i tuoi dispositivi.</string>
<string name="settings_reaction_label">Reazioni</string>
<string name="settings_reaction_description">Reagisci a eventi e comportamenti.</string>
<string name="settings_category_yourdevice_label">Il tuo dispositivo</string>
<string name="settings_category_compatibility_options_title">Opzioni di compatibilità</string>
<string name="settings_category_compatibility_options_description">Non toccare se tutto funziona ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod פותחה על ידי אדם אחד. שדרוג פותח תכונות נוספות ועוזר לשמור על האפליקציה בחיים.</string>
<string name="upgrade_benefit_themes">התאמה אישית של ערכת נושא</string>
<string name="upgrade_benefit_autoplay">השמעה אוטומטית והשהיה אוטומטית</string>
<string name="upgrade_benefit_autoconnect">חיבור אוטומטי</string>
<string name="upgrade_benefit_popups">חלון קופץ בפתיחת הנרתיק וחיבור</string>
<string name="upgrade_benefit_widgets">ווידג\'טים למסך הבית</string>
<string name="upgrade_benefit_device_settings">הגדרות מכשיר מתקדמות</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">מכשירים</string>
<string name="settings_devices_description">ניהול המכשירים שלך.</string>
<string name="settings_reaction_label">תגובות</string>
<string name="settings_reaction_description">להגיב לאירועים והתנהגויות.</string>
<string name="settings_category_yourdevice_label">המכשיר שלך</string>
<string name="settings_category_compatibility_options_title">מצב תאימות</string>
<string name="settings_category_compatibility_options_description">אל תיגע אם הכל עובד ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPodは一人の開発者によって作られています。アップグレードすると追加機能がアンロックされ、アプリの存続を支援できます。</string>
<string name="upgrade_benefit_themes">テーマのカスタマイズ</string>
<string name="upgrade_benefit_autoplay">自動再生 &amp; 自動一時停止</string>
<string name="upgrade_benefit_autoconnect">自動接続</string>
<string name="upgrade_benefit_popups">ケースオープン &amp; 接続時のポップアップ</string>
<string name="upgrade_benefit_widgets">ホーム画面ウィジェット</string>
<string name="upgrade_benefit_device_settings">詳細なデバイス設定</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">デバイス</string>
<string name="settings_devices_description">デバイスを管理します。</string>
<string name="settings_reaction_label">リアクション</string>
<string name="settings_reaction_description">イベントや行動に反応します。</string>
<string name="settings_category_yourdevice_label">あなたのデバイス</string>
<string name="settings_category_compatibility_options_title">互換性オプション</string>
<string name="settings_category_compatibility_options_description">すべてが機能する場合は触れないでください ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod შემუშავებულია ერთი ადამიანის მიერ. განახლება ხსნის დამატებით ფუნქციებს და ეხმარება აპს გადარჩენაში.</string>
<string name="upgrade_benefit_themes">თემის მორგება</string>
<string name="upgrade_benefit_autoplay">ავტო-დაკვრა და ავტო-პაუზა</string>
<string name="upgrade_benefit_autoconnect">ავტომატური დაკავშირება</string>
<string name="upgrade_benefit_popups">Popup ქეისის გახსნისა და დაკავშირებისას</string>
<string name="upgrade_benefit_widgets">მთავარი ეკრანის ვიჯეტები</string>
<string name="upgrade_benefit_device_settings">მოწყობილობის გაფართოებული პარამეტრები</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">მოწყობილობები</string>
<string name="settings_devices_description">მართეთ თქვენი მოწყობილობები.</string>
<string name="settings_reaction_label">რეაქციები</string>
<string name="settings_reaction_description">რეაგირება მოვლენებსა და ქცევებზე.</string>
<string name="settings_category_yourdevice_label">თქვენი მოწყობილობა</string>
<string name="settings_category_compatibility_options_title">თავსებადობის პარამეტრები</string>
<string name="settings_category_compatibility_options_description">არ შეეხოთ, თუ ყველაფერი მუშაობს ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ត្រូវបានអភិវឌ្ឍដោយបុគ្គលម្នាក់។ ការតម្លើងកំណែថ្មីដោះសោមុខងារបន្ថែម ហើយជួយឱ្យកម្មវិធីនៅតែដំណើរការ។</string>
<string name="upgrade_benefit_themes">ការប្ដូរទ្រង់ទ្រាយតាមបំណង</string>
<string name="upgrade_benefit_autoplay">ចាក់ដោយស្វ័យប្រវត្តិ &amp; ផ្អាកដោយស្វ័យប្រវត្តិ</string>
<string name="upgrade_benefit_autoconnect">ភ្ជាប់ដោយស្វ័យប្រវត្តិ</string>
<string name="upgrade_benefit_popups">Popup នៅពេលបើកប្រអប់ &amp; ការភ្ជាប់</string>
<string name="upgrade_benefit_widgets">វិជេតអេក្រង់ដើម</string>
<string name="upgrade_benefit_device_settings">ការកំណត់ឧបករណ៍កម្រិតខ្ពស់</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">ឧបករណ៍</string>
<string name="settings_devices_description">គ្រប់គ្រងឧបករណ៍របស់អ្នក។</string>
<string name="settings_reaction_label">ប្រតិកម្ម</string>
<string name="settings_reaction_description">ប្រតិកម្មចំពោះព្រឹត្តិការណ៍ និងអាកប្បកិរិយា។</string>
<string name="settings_category_yourdevice_label">ឧបករណ៍របស់អ្នក</string>
<string name="settings_category_compatibility_options_title">ជម្រើសភាពឆបគ្នា</string>
<string name="settings_category_compatibility_options_description">កុំប៉ះប្រសិនបើអ្វីៗដំណើរការបានល្អ ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ji aliyê kesekî yekane ve tê pêşxistin. Nûvekirina sepanê taybetmendiyên zêde vedike û dibe alîkar ku sepan sax bimîne.</string>
<string name="upgrade_benefit_themes">Xweşandina temayê</string>
<string name="upgrade_benefit_autoplay">Otomatîk lêdan &amp; otomatîk rawestin</string>
<string name="upgrade_benefit_autoconnect">Girêdana otomatîk</string>
<string name="upgrade_benefit_popups">Popup dema vekirina qutiyê &amp; girêdanê</string>
<string name="upgrade_benefit_widgets">Widgetên ekrana malê</string>
<string name="upgrade_benefit_device_settings">Mîhengen pêşkertî yên cîhazê</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Amûr</string>
<string name="settings_devices_description">Amûrên xwe birêve bibin.</string>
<string name="settings_reaction_label">Bertek</string>
<string name="settings_reaction_description">Bertek nîşanî bûyer û tevgeran bide.</string>
<string name="settings_category_yourdevice_label">Amûra we</string>
<string name="settings_category_compatibility_options_title">Vebijarkên lihevhatinê</string>
<string name="settings_category_compatibility_options_description">Heke her tişt baş dixebite dest nedin ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ಅನ್ನು ಒಬ್ಬ ವ್ಯಕ್ತಿ ಅಭಿವೃದ್ಧಿಪಡಿಸಿದ್ದಾರೆ. ಅಪ್‌ಗ್ರೇಡ್ ಮಾಡುವುದರಿಂದ ಹೆಚ್ಚುವರಿ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲಾಗುತ್ತದೆ ಮತ್ತು ಅ್ಯಾಪ್ ಅನ್ನು ಜೀವಂತವಾಗಿಡಲು ಸಹಾಯ ಮಾಡುತ್ತದೆ.</string>
<string name="upgrade_benefit_themes">ಥೀಮ್ ಕಸ್ಟಮೈಸೇಶನ್</string>
<string name="upgrade_benefit_autoplay">ಆಟೋ-ಪ್ಲೇ ಮತ್ತು ಆಟೋ-ಪಾಸ್</string>
<string name="upgrade_benefit_autoconnect">ಸ್ವಯಂ-ಸಂಪರ್ಕ</string>
<string name="upgrade_benefit_popups">ಕೇಸ್ ತೆರೆದಾಗ ಮತ್ತು ಸಂಪರ್ಕದ ಸಮಯದಲ್ಲಿ ಪಾಪಪ್</string>
<string name="upgrade_benefit_widgets">ಹೋಮ್ ಸ್ಕ್ರೀನ್ ವಿಜೆಟ್‌ಗಳು</string>
<string name="upgrade_benefit_device_settings">ಸುಧಾರಿತ ಸಾಧನ ಸೆಟ್ಟಿಂಗ್ಸ್</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">ಸಾಧನಗಳು</string>
<string name="settings_devices_description">ನಿಮ್ಮ ಸಾಧನಗಳನ್ನು ನಿರ್ವಹಿಸಿ.</string>
<string name="settings_reaction_label">ಪ್ರತಿಕ್ರಿಯೆಗಳು</string>
<string name="settings_reaction_description">ಘಟನೆಗಳು ಮತ್ತು ನಡವಳಿಕೆಗಳಿಗೆ ಪ್ರತಿಕ್ರಿಯಿಸಿ.</string>
<string name="settings_category_yourdevice_label">ನಿಮ್ಮ ಸಾಧನ</string>
<string name="settings_category_compatibility_options_title">ಹೊಂದಾಣಿಕೆ ಆಯ್ಕೆಗಳು</string>
<string name="settings_category_compatibility_options_description">ಎಲ್ಲವೂ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿದ್ದರೆ ಮುಟ್ಟಬೇಡಿ ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod는 한 명이 개발합니다. 업그레이드하면 추가 기능이 잠금 해제되고 앱 유지에 도움이 됩니다.</string>
<string name="upgrade_benefit_themes">테마 사용자 지정</string>
<string name="upgrade_benefit_autoplay">자동 재생 &amp; 자동 일시정지</string>
<string name="upgrade_benefit_autoconnect">자동 연결</string>
<string name="upgrade_benefit_popups">케이스 열기 &amp; 연결 시 팝업</string>
<string name="upgrade_benefit_widgets">홈 화면 위젯</string>
<string name="upgrade_benefit_device_settings">고급 기기 설정</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">장치</string>
<string name="settings_devices_description">당신의 장치를 관리하세요.</string>
<string name="settings_reaction_label">반응</string>
<string name="settings_reaction_description">이벤트 및 행동에 반응합니다.</string>
<string name="settings_category_yourdevice_label">내 기기</string>
<string name="settings_category_compatibility_options_title">호환성 옵션</string>
<string name="settings_category_compatibility_options_description">모든 것이 작동하면 건드리지 마세요 ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod бир адам тарабынан иштелип чыгат. Жаңыртуу кошумча функцияларды ачып, колдонмонун тирүү калуусуна жардам берет.</string>
<string name="upgrade_benefit_themes">Темаларды ыңгайлаштыруу</string>
<string name="upgrade_benefit_autoplay">Авто-ойнотуу &amp; авто-токтотуу</string>
<string name="upgrade_benefit_autoconnect">Авто туташуу</string>
<string name="upgrade_benefit_popups">Кутуча ачылганда &amp; туташканда калкыма терезе</string>
<string name="upgrade_benefit_widgets">Башкы экран виджеттери</string>
<string name="upgrade_benefit_device_settings">Өнүккөн түзмөк жөндөөлөрү</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Түзмөктөр</string>
<string name="settings_devices_description">Түзмөктөрүңүздү башкаруу.</string>
<string name="settings_reaction_label">Реакциялар</string>
<string name="settings_reaction_description">Окуяларга жана жүрүм-турумдарга реакция кылыңыз.</string>
<string name="settings_category_yourdevice_label">Сиздин түзмөгүңүз</string>
<string name="settings_category_compatibility_options_title">Шайкештик опциялары</string>
<string name="settings_category_compatibility_options_description">Эгер баары иштесе тийбеңиз ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ຖືກພັດທະນາໂດຍຄົນດຽວ. ການອັບເກຣດຈະປົດລັອກຟີເຈີເພີ່ມເຕີມ ແລະ ຊ່ວຍຮັກສາແອັບໃຫ້ດຳເນີນຕໍ່ໄປ.</string>
<string name="upgrade_benefit_themes">ປັບແຕ່ງຮູບແບບ</string>
<string name="upgrade_benefit_autoplay">ຫຼິ້ນອັດຕະໂນມັດ &amp; ຢຸດຊົ່ວຄາວອັດຕະໂນມັດ</string>
<string name="upgrade_benefit_autoconnect">ເຊື່ອມຕໍ່ອັດຕະໂນມັດ</string>
<string name="upgrade_benefit_popups">ປັອບອັບເມື່ອເປີດກ່ອງ &amp; ເຊື່ອມຕໍ່</string>
<string name="upgrade_benefit_widgets">ວິດເຈັດໜ້າຈໍຫຼັກ</string>
<string name="upgrade_benefit_device_settings">ການຕັ້ງຄ່າອຸປະກອນຂັ້ນສູງ</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">ອຸປະກອນ</string>
<string name="settings_devices_description">ຈັດການອຸປະກອນຂອງທ່ານ.</string>
<string name="settings_reaction_label">ປະຕິກິລິຍາ</string>
<string name="settings_reaction_description">ປະຕິກິລິຍາຕໍ່ເຫດການ ແລະ ພຶດຕິກຳ.</string>
<string name="settings_category_yourdevice_label">ອຸປະກອນຂອງທ່ານ</string>
<string name="settings_category_compatibility_options_title">ຕົວເລືອກຄວາມເຂົ້າກັນໄດ້</string>
<string name="settings_category_compatibility_options_description">ຢ່າແຕະຕ້ອງຖ້າທຸກຢ່າງເຮັດວຽກ ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod sukūrė vienas žmogus. Atnaujinimas atrakins papildomas funkcijas ir padės išlaikyti programėlę gyvą.</string>
<string name="upgrade_benefit_themes">Temos pritaikymas</string>
<string name="upgrade_benefit_autoplay">Automatinis grojimas ir pauzė</string>
<string name="upgrade_benefit_autoconnect">Automatinis prisijungimas</string>
<string name="upgrade_benefit_popups">Iššokantis langas atidarius dėklą ir prisijungus</string>
<string name="upgrade_benefit_widgets">Pradinio ekrano valdikliai</string>
<string name="upgrade_benefit_device_settings">Išplėstiniai įrenginio nustatymai</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Įrenginiai</string>
<string name="settings_devices_description">Tvarkykite savo įrenginius.</string>
<string name="settings_reaction_label">Reakcijos</string>
<string name="settings_reaction_description">Reaguoti į įvykius ir elgseną.</string>
<string name="settings_category_yourdevice_label">Jūsų įrenginys</string>
<string name="settings_category_compatibility_options_title">Suderinamumo parinktys</string>
<string name="settings_category_compatibility_options_description">Nelieskite, jei viskas veikia ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ir izstrādājusi viena persona. Jaunināšana atbloķē papildu funkcijas un palīdz uzturēt lietotni pie dzīvības.</string>
<string name="upgrade_benefit_themes">Tēmu pielāgošana</string>
<string name="upgrade_benefit_autoplay">Automātiska atskaņošana un pauze</string>
<string name="upgrade_benefit_autoconnect">Automātiska savienošana</string>
<string name="upgrade_benefit_popups">Uznirstošs logs, atverot futrāli un savienojoties</string>
<string name="upgrade_benefit_widgets">Sākuma ekrāna logrīki</string>
<string name="upgrade_benefit_device_settings">Papildu ierīces iestatījumi</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Ierīces</string>
<string name="settings_devices_description">Pārvaldiet savas ierīces.</string>
<string name="settings_reaction_label">Reakcijas</string>
<string name="settings_reaction_description">Reaģēt uz notikumiem un uzvedību.</string>
<string name="settings_category_yourdevice_label">Jūsu ierīce</string>
<string name="settings_category_compatibility_options_title">Saderības opcijas</string>
<string name="settings_category_compatibility_options_description">Neaiztieciet, ja viss darbojas ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod е развиен од една личност. Надградувањето отклучува дополнителни функции и помага да се одржи апликацијата жива.</string>
<string name="upgrade_benefit_themes">Прилагодување на теми</string>
<string name="upgrade_benefit_autoplay">Автоматско пуштање &amp; автоматска пауза</string>
<string name="upgrade_benefit_autoconnect">Автоматско поврзување</string>
<string name="upgrade_benefit_popups">Исскочувачки прозорец при отворање на куќиштето &amp; поврзување</string>
<string name="upgrade_benefit_widgets">Виџети на почетниот екран</string>
<string name="upgrade_benefit_device_settings">Напредни поставки на уредот</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Уреди</string>
<string name="settings_devices_description">Управувајте со вашите уреди.</string>
<string name="settings_reaction_label">Реакции</string>
<string name="settings_reaction_description">Реагирајте на настани и однесувања.</string>
<string name="settings_category_yourdevice_label">Вашиот уред</string>
<string name="settings_category_compatibility_options_title">Опции за компатибилност</string>
<string name="settings_category_compatibility_options_description">Не допирајте ако сè работи ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ഒരൊറ്റ വ്യക്തി വികസിപ്പിച്ചതാണ്. അപ്‌ഗ്രേഡ് ചെയ്യുന്നത് അധിക സവിശേഷതകൾ അൺലോക്ക് ചെയ്യുകയും ആപ്പ് നിലനിർത്താൻ സഹായിക്കുകയും ചെയ്യുന്നു.</string>
<string name="upgrade_benefit_themes">തീം ഇഷ്ടാനുസൃതമാക്കൽ</string>
<string name="upgrade_benefit_autoplay">ഓട്ടോ-പ്ലേ &amp; ഓട്ടോ-പോസ്</string>
<string name="upgrade_benefit_autoconnect">ഓട്ടോ-കണക്റ്റ്</string>
<string name="upgrade_benefit_popups">കേസ് തുറക്കുമ്പോഴും കണക്ഷൻ സമയത്തും പോപ്പ്അപ്പ്</string>
<string name="upgrade_benefit_widgets">ഹോം സ്ക്രീൻ വിജറ്റുകൾ</string>
<string name="upgrade_benefit_device_settings">വിപുലമായ ഉപകരണ ക്രമീകരണങ്ങൾ</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">ഉപകരണങ്ങൾ</string>
<string name="settings_devices_description">നിങ്ങളുടെ ഉപകരണങ്ങൾ നിയന്ത്രിക്കുക.</string>
<string name="settings_reaction_label">പ്രতিকകരണങ്ങൾ</string>
<string name="settings_reaction_description">സംഭവങ്ങളോടും പെരുമാറ്റങ്ങളോടും പ്രതികരിക്കുക.</string>
<string name="settings_category_yourdevice_label">നിങ്ങളുടെ ഉപകരണം</string>
<string name="settings_category_compatibility_options_title">അനുയോജ്യത ഓപ്ഷനുകൾ</string>
<string name="settings_category_compatibility_options_description">എല്ലാം ശരിയായി പ്രവർത്തിക്കുന്നുണ്ടെങ്കിൽ തൊടരുത് ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod-ийг нэг хүн боловсруулсан. Шинэчлэх нь нэмэлт функцуудыг нээж, аппликейшнийг амьд байлгахад тусалдаг.</string>
<string name="upgrade_benefit_themes">Загварын тохиргоо</string>
<string name="upgrade_benefit_autoplay">Автомат тоглуулах &amp; автомат зогсоох</string>
<string name="upgrade_benefit_autoconnect">Автомат холболт</string>
<string name="upgrade_benefit_popups">Тохиолдол нээх &amp; холбогдох үед popup</string>
<string name="upgrade_benefit_widgets">Нүүр дэлгэцийн виджетүүд</string>
<string name="upgrade_benefit_device_settings">Төхөөрөмжийн нарийнчилсан тохиргоо</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Төхөөрөмжүүд</string>
<string name="settings_devices_description">Төхөөрөмжүүдээ удирдах.</string>
<string name="settings_reaction_label">Урвалууд</string>
<string name="settings_reaction_description">Үйл явдал, зан үйлд хариу үйлдэл үзүүлнэ.</string>
<string name="settings_category_yourdevice_label">Таны төхөөрөмж</string>
<string name="settings_category_compatibility_options_title">Тохиромжтой байдлын сонголтууд</string>
<string name="settings_category_compatibility_options_description">Хэрэв бүх зүйл ажиллаж байвал бүү хүр ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod एका व्यक्तीने विकसित केला आहे. अपग्रेड केल्यास अतिरिक्त वैशिष्ट्ये मिळतात आणि अॅप सुरू ठेवण्यास मदत होते.</string>
<string name="upgrade_benefit_themes">थीम सानुकूलन</string>
<string name="upgrade_benefit_autoplay">ऑटो-प्ले आणि ऑटो-पॉज</string>
<string name="upgrade_benefit_autoconnect">ऑटो-कनेक्ट</string>
<string name="upgrade_benefit_popups">केस उघडताना आणि कनेक्शनवर पॉपअप</string>
<string name="upgrade_benefit_widgets">होम स्क्रीन विजेट</string>
<string name="upgrade_benefit_device_settings">प्रगत डिव्हाइस सेटिंग्ज</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">डिव्हाइस</string>
<string name="settings_devices_description">आपल्या डिव्हाइसचे व्यवस्थापन करा.</string>
<string name="settings_reaction_label">प्रतिक्रिया</string>
<string name="settings_reaction_description">घटना आणि वर्तनांवर प्रतिक्रिया द्या.</string>
<string name="settings_category_yourdevice_label">तुमचे डिव्हाइस</string>
<string name="settings_category_compatibility_options_title">सुसंगतता पर्याय</string>
<string name="settings_category_compatibility_options_description">सर्व काही ठीक चालत असल्यास स्पर्श करू नका ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod dibangunkan oleh seorang individu. Menaik taraf membuka kunci ciri-ciri tambahan dan membantu mengekalkan aplikasi ini.</string>
<string name="upgrade_benefit_themes">Penyesuaian tema</string>
<string name="upgrade_benefit_autoplay">Main automatik &amp; jeda automatik</string>
<string name="upgrade_benefit_autoconnect">Sambung automatik</string>
<string name="upgrade_benefit_popups">Popup semasa buka kotak &amp; sambungan</string>
<string name="upgrade_benefit_widgets">Widget skrin utama</string>
<string name="upgrade_benefit_device_settings">Tetapan peranti lanjutan</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Peranti</string>
<string name="settings_devices_description">Urus peranti anda.</string>
<string name="settings_reaction_label">Reaksi</string>
<string name="settings_reaction_description">Bertindak balas terhadap peristiwa dan tingkah laku.</string>
<string name="settings_category_yourdevice_label">Peranti anda</string>
<string name="settings_category_compatibility_options_title">Pilihan keserasian</string>
<string name="settings_category_compatibility_options_description">Jangan sentuh jika semuanya berfungsi ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ကို တစ်ဦးတည်းသောသူက တည်ဆောက်ထားသည်။ အဆင့်မြှင့်ခြင်းဖြင့် အပိုဝန်ဆောင်မှုများကို ရယူနိုင်ပြီး အက်ပ်ကို ဆက်လက်ရှင်သန်စေရန် ကူညီပေးသည်။</string>
<string name="upgrade_benefit_themes">အပြင်အဆင် စိတ်ကြိုက်ပြင်ဆင်မှု</string>
<string name="upgrade_benefit_autoplay">အလိုအလျောက် ဖွင့်ခြင်း &amp; ခေတ္တရပ်ခြင်း</string>
<string name="upgrade_benefit_autoconnect">အလိုအလျောက် ချိတ်ဆက်ခြင်း</string>
<string name="upgrade_benefit_popups">ဖွင့်သောအခါ &amp; ချိတ်ဆက်သောအခါ Popup ပေါ်လာခြင်း</string>
<string name="upgrade_benefit_widgets">ပင်မစခရင် Widget များ</string>
<string name="upgrade_benefit_device_settings">အဆင့်မြင့့်် ကိရိယာ ဆက်တင်များ</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">စက်ပစ္စည်းများ</string>
<string name="settings_devices_description">သင့်စက်ပစ္စည်းများကို စီမံခန့်ခွဲပါ။</string>
<string name="settings_reaction_label">တုံ့ပြန်မှုများ</string>
<string name="settings_reaction_description">ဖြစ်ရပ်များနှင့် အပြုအမူများအပေါ် တုံ့ပြန်ပါ။</string>
<string name="settings_category_yourdevice_label">သင့်စက်ပစ္စည်း</string>
<string name="settings_category_compatibility_options_title">လိုက်ဖက်ညီမှုရွေးချယ်စရာများ</string>
<string name="settings_category_compatibility_options_description">အရာအားလုံးအဆင်ပြေနေပါက မထိပါနှင့် ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod er utviklet av én person. Oppgradering låser opp ekstra funksjoner og bidrar til å holde appen i live.</string>
<string name="upgrade_benefit_themes">Tematilpasning</string>
<string name="upgrade_benefit_autoplay">Autoavspilling &amp; autopause</string>
<string name="upgrade_benefit_autoconnect">Autotilkobling</string>
<string name="upgrade_benefit_popups">Popup ved åpning av etui &amp; tilkobling</string>
<string name="upgrade_benefit_widgets">Hjemmeskjerm-widgeter</string>
<string name="upgrade_benefit_device_settings">Avanserte enhetsinnstillinger</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Enheter</string>
<string name="settings_devices_description">Administrer enhetene dine.</string>
<string name="settings_reaction_label">Reaksjoner</string>
<string name="settings_reaction_description">Reager på hendelser og oppførsel.</string>
<string name="settings_category_yourdevice_label">Enheten din</string>
<string name="settings_category_compatibility_options_title">Kompatibilitets-alternativer</string>
<string name="settings_category_compatibility_options_description">Ikke rør hvis alt virker ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod एकल व्यक्तिद्वारा विकास गरिएको छ। अपग्रेड गर्दा थप सुविधाहरू अनलक हुन्छन् र एपलाई जीवित राख्न मद्दत गर्छ।</string>
<string name="upgrade_benefit_themes">थिम अनुकूलन</string>
<string name="upgrade_benefit_autoplay">स्वत: प्ले र स्वत: पज</string>
<string name="upgrade_benefit_autoconnect">स्वत: जडान</string>
<string name="upgrade_benefit_popups">केस खोल्दा र जडान हुँदा पपअप</string>
<string name="upgrade_benefit_widgets">होम स्क्रिन विजेटहरू</string>
<string name="upgrade_benefit_device_settings">उन्नत उपकरण सेटिङहरू</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">उपकरणहरू</string>
<string name="settings_devices_description">आफ्ना उपकरणहरू व्यवस्थापन गर्नुहोस्।</string>
<string name="settings_reaction_label">प्रतिक्रियाहरू</string>
<string name="settings_reaction_description">घटनाहरू र व्यवहारहरूमा प्रतिक्रिया दिनुहोस्।</string>
<string name="settings_category_yourdevice_label">तपाईंको उपकरण</string>
<string name="settings_category_compatibility_options_title">अनुकूलता विकल्पहरू</string>
<string name="settings_category_compatibility_options_description">सबै कुरा ठीकठाक चलिरहेको छ भने नचलाउनुहोस् ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod wordt ontwikkeld door één persoon. Upgraden ontgrendelt extra functies en helpt de app in leven te houden.</string>
<string name="upgrade_benefit_themes">Thema-aanpassing</string>
<string name="upgrade_benefit_autoplay">Automatisch afspelen &amp; pauzeren</string>
<string name="upgrade_benefit_autoconnect">Automatisch verbinden</string>
<string name="upgrade_benefit_popups">Popup bij openen van hoesje &amp; verbinding</string>
<string name="upgrade_benefit_widgets">Startscherm-widgets</string>
<string name="upgrade_benefit_device_settings">Geavanceerde apparaatinstellingen</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Apparaten</string>
<string name="settings_devices_description">Beheer je apparaten.</string>
<string name="settings_reaction_label">Reacties</string>
<string name="settings_reaction_description">Reageren op gebeurtenissen en gedragingen.</string>
<string name="settings_category_yourdevice_label">Uw apparaat</string>
<string name="settings_category_compatibility_options_title">Compatibiliteitsopties</string>
<string name="settings_category_compatibility_options_description">Niet aankomen als alles werkt ;-)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod jest rozwijany przez jedną osobę. Uaktualnienie odblokowuje dodatkowe funkcje i pomaga utrzymać aplikację przy życiu.</string>
<string name="upgrade_benefit_themes">Personalizacja motywu</string>
<string name="upgrade_benefit_autoplay">Automatyczne odtwarzanie i automatyczna pauza</string>
<string name="upgrade_benefit_autoconnect">Automatyczne połączenie</string>
<string name="upgrade_benefit_popups">Wyskakujące okienko po otwarciu etui i połączeniu</string>
<string name="upgrade_benefit_widgets">Widżety ekranu głównego</string>
<string name="upgrade_benefit_device_settings">Zaawansowane ustawienia urządzenia</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Urządzenia</string>
<string name="settings_devices_description">Zarządzaj swoimi urządzeniami.</string>
<string name="settings_reaction_label">Reakcje</string>
<string name="settings_reaction_description">Reakcje na wydarzenia lub zachowania.</string>
<string name="settings_category_yourdevice_label">Twoje urządzenie</string>
<string name="settings_category_compatibility_options_title">Opcje kompatybilności</string>
<string name="settings_category_compatibility_options_description">Nie dotykaj, jeżeli wszystko działa ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">O CAPod é desenvolvido por uma única pessoa. Fazer upgrade desbloqueia recursos extras e ajuda a manter o aplicativo ativo.</string>
<string name="upgrade_benefit_themes">Personalização de tema</string>
<string name="upgrade_benefit_autoplay">Reprodução automática &amp; pausa automática</string>
<string name="upgrade_benefit_autoconnect">Conexão automática</string>
<string name="upgrade_benefit_popups">Popup ao abrir o estojo &amp; conexão</string>
<string name="upgrade_benefit_widgets">Widgets da tela inicial</string>
<string name="upgrade_benefit_device_settings">Configurações avançadas do dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Gerenciar seus dispositivos</string>
<string name="settings_reaction_label">Reações</string>
<string name="settings_reaction_description">Reaja a eventos e comportamentos.</string>
<string name="settings_category_yourdevice_label">Seu dispositivo</string>
<string name="settings_category_compatibility_options_title">Opções de compatibilidade</string>
<string name="settings_category_compatibility_options_description">Não toque se tudo funcionar ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">O CAPod é desenvolvido por uma única pessoa. Atualizar desbloqueia funcionalidades extra e ajuda a manter a aplicação ativa.</string>
<string name="upgrade_benefit_themes">Personalização de tema</string>
<string name="upgrade_benefit_autoplay">Reprodução automática &amp; pausa automática</string>
<string name="upgrade_benefit_autoconnect">Ligar automaticamente</string>
<string name="upgrade_benefit_popups">Pop-up ao abrir a caixa &amp; ao ligar</string>
<string name="upgrade_benefit_widgets">Widgets do ecrã principal</string>
<string name="upgrade_benefit_device_settings">Definições avançadas do dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Gerir os seus dispositivos.</string>
<string name="settings_reaction_label">Reações</string>
<string name="settings_reaction_description">Reagir a eventos e comportamentos.</string>
<string name="settings_category_yourdevice_label">O seu dispositivo</string>
<string name="settings_category_compatibility_options_title">Opções de compatibilidade</string>
<string name="settings_category_compatibility_options_description">Não mexa se tudo estiver a funcionar ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod è sviluppà da ina singula persuna. Actualisar sblucca funcziuns supplementaras ed agida a mantegnair l\'app viva.</string>
<string name="upgrade_benefit_themes">Persunalisaziun dal tema</string>
<string name="upgrade_benefit_autoplay">Start automatic &amp; pausa automatica</string>
<string name="upgrade_benefit_autoconnect">Connectar automaticamain</string>
<string name="upgrade_benefit_popups">Popup sin avrir il cais &amp; connexiun</string>
<string name="upgrade_benefit_widgets">Widgets sin l\'ècran principal</string>
<string name="upgrade_benefit_device_settings">Parameters avanzads da l\'apparat</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Apparats</string>
<string name="settings_devices_description">Administrar Voss apparats.</string>
<string name="settings_reaction_label">Reacziuns</string>
<string name="settings_reaction_description">Reagir sin eveniments e cumportaments.</string>
<string name="settings_category_yourdevice_label">Voss apparat</string>
<string name="settings_category_compatibility_options_title">Opziuns da cumpatibilitad</string>
<string name="settings_category_compatibility_options_description">Betg tuccar sche tut funcziuna ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod este dezvoltat de o singură persoană. Actualizarea deblochează funcții extra și ajută la menținerea aplicației în viață.</string>
<string name="upgrade_benefit_themes">Personalizare temă</string>
<string name="upgrade_benefit_autoplay">Redare automată și pauză automată</string>
<string name="upgrade_benefit_autoconnect">Conectare automată</string>
<string name="upgrade_benefit_popups">Fereastră pop-up la deschiderea husă și conectare</string>
<string name="upgrade_benefit_widgets">Widgeturi ecran principal</string>
<string name="upgrade_benefit_device_settings">Setări avansate dispozitiv</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispozitive</string>
<string name="settings_devices_description">Gestionați dispozitivele dvs.</string>
<string name="settings_reaction_label">Reacții</string>
<string name="settings_reaction_description">Reacționați la evenimente și comportamente.</string>
<string name="settings_category_yourdevice_label">Dispozitivul tău</string>
<string name="settings_category_compatibility_options_title">Opțiuni de compatibilitate</string>
<string name="settings_category_compatibility_options_description">Nu atingeți dacă totul funcționează ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod разработан одним человеком. Обновление открывает дополнительные функции и помогает поддерживать приложение.</string>
<string name="upgrade_benefit_themes">Настройка темы</string>
<string name="upgrade_benefit_autoplay">Авто-воспроизведение и авто-пауза</string>
<string name="upgrade_benefit_autoconnect">Автоподключение</string>
<string name="upgrade_benefit_popups">Всплывающее окно при открытии чехла и подключении</string>
<string name="upgrade_benefit_widgets">Виджеты главного экрана</string>
<string name="upgrade_benefit_device_settings">Расширенные настройки устройства</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Устройства</string>
<string name="settings_devices_description">Управление устройствами.</string>
<string name="settings_reaction_label">Реакции</string>
<string name="settings_reaction_description">Реакции на события и действия.</string>
<string name="settings_category_yourdevice_label">Ваше устройство</string>
<string name="settings_category_compatibility_options_title">Настройки совместимости</string>
<string name="settings_category_compatibility_options_description">Не трогать, если всё работает :)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod est isvilupadu dae una sola persona. Aggiornar isbloca funtzionalidades in prus e agiudat a mantènnere s\'app in vita.</string>
<string name="upgrade_benefit_themes">Personalizzatzione de su tema</string>
<string name="upgrade_benefit_autoplay">Reprodutzione autom. e pausa autom.</string>
<string name="upgrade_benefit_autoconnect">Cullegamentu automàticu</string>
<string name="upgrade_benefit_popups">Popup a s\'apertùra de sa custodia e cullegamentu</string>
<string name="upgrade_benefit_widgets">Widget de sa pantalla printzipale</string>
<string name="upgrade_benefit_device_settings">Impostatziones avanzadas de su dispositivo</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Dispositivos</string>
<string name="settings_devices_description">Gestisci is dispositivos tuos.</string>
<string name="settings_reaction_label">Reatziones</string>
<string name="settings_reaction_description">Reaghit a eventos e cumportamentos.</string>
<string name="settings_category_yourdevice_label">Su dispositivu tuo</string>
<string name="settings_category_compatibility_options_title">Opsiones de cumpatibilidade</string>
<string name="settings_category_compatibility_options_description">Non toches si totu funtzionat ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod සකසා ඇත්තේ එක් කෙනෙකු විසිනි. යාවත්කාලීන කිරීම අමතර විශේෂාංග විවෘත කරන අතර යෙදුම ක්‍රියාත්මකව තබා ගැනීමට උපකාරී වේ.</string>
<string name="upgrade_benefit_themes">තේමා අභිරුචිකරණය</string>
<string name="upgrade_benefit_autoplay">ස්වයංක්‍රීය ධාවනය සහ ස්වයංක්‍රීය විරාමය</string>
<string name="upgrade_benefit_autoconnect">ස්වයංක්‍රීයව සම්බන්ධ වන්න</string>
<string name="upgrade_benefit_popups">කේස් විවෘත කිරීමේ සහ සම්බන්ධතාවයේ පොප්අප්</string>
<string name="upgrade_benefit_widgets">මුල් පිටු තිර විජට්</string>
<string name="upgrade_benefit_device_settings">උසස් උපාංග සැකසුම්</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">උපාංග</string>
<string name="settings_devices_description">ඔබගේ උපාංග කළමනාකරණය කරන්න.</string>
<string name="settings_reaction_label">ප්‍රතික්‍රියා</string>
<string name="settings_reaction_description">සිදුවීම් සහ හැසිරීම් වලට ප්‍රතිචාර දක්වන්න.</string>
<string name="settings_category_yourdevice_label">ඔබගේ උපාංගය</string>
<string name="settings_category_compatibility_options_title">ගැළපුම් විකල්ප</string>
<string name="settings_category_compatibility_options_description">සියල්ල ක්‍රියාත්මක නම් අත නොගසන්න ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod vyvíja jedna osoba. Aktualizácia odomkne extra funkcie a pomáha udržiavať aplikáciu v prevádzke.</string>
<string name="upgrade_benefit_themes">Prispôsobenie tém</string>
<string name="upgrade_benefit_autoplay">Automatické prehrávanie &amp; pauza</string>
<string name="upgrade_benefit_autoconnect">Automatické pripojenie</string>
<string name="upgrade_benefit_popups">Vyskakovacie okno pri otvorení puzdra &amp; pripojení</string>
<string name="upgrade_benefit_widgets">Widgety domovskej obrazovky</string>
<string name="upgrade_benefit_device_settings">Pokročilé nastavenia zariadenia</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Zariadenia</string>
<string name="settings_devices_description">Spravujte svoje zariadenia.</string>
<string name="settings_reaction_label">Reakcie</string>
<string name="settings_reaction_description">Reakcia na udalosti a správanie.</string>
<string name="settings_category_yourdevice_label">Vaše zariadenie</string>
<string name="settings_category_compatibility_options_title">Možnosti kompatibility</string>
<string name="settings_category_compatibility_options_description">Nedotýkajte sa, ak všetko funguje ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod je razvila ena sama oseba. Z nadgradnjo odklenete dodatne funkcije in pomagate ohranjati aplikacijo.</string>
<string name="upgrade_benefit_themes">Prilagajanje teme</string>
<string name="upgrade_benefit_autoplay">Samodejno predvajanje in zaustavitev</string>
<string name="upgrade_benefit_autoconnect">Samodejna povezava</string>
<string name="upgrade_benefit_popups">Pojavno okno ob odprtju ohišja in povezavi</string>
<string name="upgrade_benefit_widgets">Gradniki na začetnem zaslonu</string>
<string name="upgrade_benefit_device_settings">Napredne nastavitve naprave</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Naprave</string>
<string name="settings_devices_description">Upravljajte svoje naprave.</string>
<string name="settings_reaction_label">Reakcije</string>
<string name="settings_reaction_description">Odzovite se na dogodke in vedenja.</string>
<string name="settings_category_yourdevice_label">Vaša naprava</string>
<string name="settings_category_compatibility_options_title">Možnosti združljivosti</string>
<string name="settings_category_compatibility_options_description">Ne dotikajte se, če vse deluje ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod është zhvilluar nga një person i vetëm. Përmirësimi zhbllokon veçori shtesë dhe ndihmon të mbajë aplikacionin gjallë.</string>
<string name="upgrade_benefit_themes">Personalizimi i temës</string>
<string name="upgrade_benefit_autoplay">Auto-luaj &amp; auto-pauzë</string>
<string name="upgrade_benefit_autoconnect">Lidhje automatike</string>
<string name="upgrade_benefit_popups">Dritare kërcyese kur hapet kuti &amp; lidhja</string>
<string name="upgrade_benefit_widgets">Miniaplikacionet e ekranit kryesor</string>
<string name="upgrade_benefit_device_settings">Cilësimet e avancuara të pajisjes</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Pajisjet</string>
<string name="settings_devices_description">Menaxhoni pajisjet tuaja.</string>
<string name="settings_reaction_label">Reagimet</string>
<string name="settings_reaction_description">Reago ndaj ngjarjeve dhe sjelljeve.</string>
<string name="settings_category_yourdevice_label">Pajisja juaj</string>
<string name="settings_category_compatibility_options_title">Opsionet e përputhshmërisë</string>
<string name="settings_category_compatibility_options_description">Mos i prekni nëse gjithçka funksionon ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod је развила једна особа. Надоградњом откључавате додатне функције и помажете да апликација опстане.</string>
<string name="upgrade_benefit_themes">Прилагођавање теме</string>
<string name="upgrade_benefit_autoplay">Аутоматско репродуковање и паузирање</string>
<string name="upgrade_benefit_autoconnect">Аутоматско повезивање</string>
<string name="upgrade_benefit_popups">Искачући прозор при отварању кућишта и повезивању</string>
<string name="upgrade_benefit_widgets">Виџети почетног екрана</string>
<string name="upgrade_benefit_device_settings">Напредна подешавања уређаја</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Уређаји</string>
<string name="settings_devices_description">Управљајте својим уређајима.</string>
<string name="settings_reaction_label">Реакције</string>
<string name="settings_reaction_description">Реагујте на догађаје и понашања.</string>
<string name="settings_category_yourdevice_label">Ваш уређај</string>
<string name="settings_category_compatibility_options_title">Опције компатибилности</string>
<string name="settings_category_compatibility_options_description">Не дирајте ако све ради ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod är utvecklad av en enda person. Uppgraderingen låser upp extra funktioner och hjälper till att hålla appen vid liv.</string>
<string name="upgrade_benefit_themes">Temoanpassning</string>
<string name="upgrade_benefit_autoplay">Uppspelning automatiskt &amp; automatisk paus</string>
<string name="upgrade_benefit_autoconnect">Anslut automatiskt</string>
<string name="upgrade_benefit_popups">Popup vid öppning av fodral &amp; anslutning</string>
<string name="upgrade_benefit_widgets">Hemskärmswidgetar</string>
<string name="upgrade_benefit_device_settings">Avancerade enhetsinställningar</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Enheter</string>
<string name="settings_devices_description">Hantera dina enheter.</string>
<string name="settings_reaction_label">Reaktioner</string>
<string name="settings_reaction_description">Reagera på händelser och beteenden.</string>
<string name="settings_category_yourdevice_label">Din enhet</string>
<string name="settings_category_compatibility_options_title">Kompatibilitetsalternativ</string>
<string name="settings_category_compatibility_options_description">Rör inte om allt fungerar ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod inaendelezwa na mtu mmoja. Kuboresha kunafungua vipengele vya ziada na husaidia kuweka programu iwe hai.</string>
<string name="upgrade_benefit_themes">Ubinafsishaji wa mandhari</string>
<string name="upgrade_benefit_autoplay">Cheza kiotomatiki &amp; simama kiotomatiki</string>
<string name="upgrade_benefit_autoconnect">Unganisha kiotomatiki</string>
<string name="upgrade_benefit_popups">Dirisha la kuibuka wakati wa kufungua kifuniko &amp; muunganiko</string>
<string name="upgrade_benefit_widgets">Wijeti za skrini ya nyumbani</string>
<string name="upgrade_benefit_device_settings">Mipangilio ya kifaa ya hali ya juu</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Vifaa</string>
<string name="settings_devices_description">Simamia vifaa vyako.</string>
<string name="settings_reaction_label">Matendo</string>
<string name="settings_reaction_description">Jibu kwa matukio na tabia.</string>
<string name="settings_category_yourdevice_label">Kifaa chako</string>
<string name="settings_category_compatibility_options_title">Chaguo za uoanifu</string>
<string name="settings_category_compatibility_options_description">Usiguse ikiwa kila kitu kinafanya kazi ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ஒரு நபரால் உருவாக்கப்பட்டது. மேம்படுத்துவது கூடுதல் அம்சங்களை திறக்கிறது மற்றும் பயன்பாட்டை உயிருடன் வைத்திருக்க உதவுகிறது.</string>
<string name="upgrade_benefit_themes">தீம் தனிப்பயனாக்கம்</string>
<string name="upgrade_benefit_autoplay">தானியங்கு இயக்கம் மற்றும் தானியங்கு இடைநிறுத்தம்</string>
<string name="upgrade_benefit_autoconnect">தானியங்கு இணைப்பு</string>
<string name="upgrade_benefit_popups">கேஸ் திறக்கும்போது மற்றும் இணைப்பின்போது பாப்அப்</string>
<string name="upgrade_benefit_widgets">முகப்புத் திரை விட்ஜெட்கள்</string>
<string name="upgrade_benefit_device_settings">மேம்பட்ட சாதன அமைப்புகள்</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">சாதனங்கள்</string>
<string name="settings_devices_description">உங்கள் சாதனங்களை நிர்வகிக்கவும்.</string>
<string name="settings_reaction_label">எதிர்வினைகள்</string>
<string name="settings_reaction_description">நிகழ்வுகள் மற்றும் நடத்தைகளுக்கு எதிர்வினையாற்று.</string>
<string name="settings_category_yourdevice_label">உங்கள் சாதனம்</string>
<string name="settings_category_compatibility_options_title">இணக்கத்தன்மை விருப்பங்கள்</string>
<string name="settings_category_compatibility_options_description">எல்லாம் வேலை செய்தால் தொடாதே ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ఒక వ్యక్తిచే అభివృద్ధి చేయబడింది. అప్‌గ్రేడ్ చేయడం అదనపు ఫీచర్లను అన్‌లాక్ చేస్తుంది మరియు యాప్‌ను సజీవంగా ఉంచడానికి సహాయపడుతుంది.</string>
<string name="upgrade_benefit_themes">థీమ్ కస్టమైజేషన్</string>
<string name="upgrade_benefit_autoplay">ఆటో-ప్లే &amp; ఆటో-పాజ్</string>
<string name="upgrade_benefit_autoconnect">ఆటో-కనెక్ట్</string>
<string name="upgrade_benefit_popups">కేస్ తెరిచినప్పుడు &amp; కనెక్షన్‌పై పాప్‌అప్</string>
<string name="upgrade_benefit_widgets">హోమ్ స్క్రీన్ విడ్జెట్‌లు</string>
<string name="upgrade_benefit_device_settings">అధునాతన పరికర సెట్టింగ్‌లు</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">పరికరాలు</string>
<string name="settings_devices_description">మీ పరికరాలను నిర్వహించండి.</string>
<string name="settings_reaction_label">ప్రతిచర్యలు</string>
<string name="settings_reaction_description">ఈవెంట్‌లు మరియు ప్రవర్తనలకు ప్రతిస్పందించండి.</string>
<string name="settings_category_yourdevice_label">మీ పరికరం</string>
<string name="settings_category_compatibility_options_title">అనుకూలత ఎంపికలు</string>
<string name="settings_category_compatibility_options_description">అన్నీ పని చేస్తే తాకవద్దు ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod พัฒนาโดยบุคคลเพียงคนเดียว การอัปเกรดจะปลดล็อกฟีเจอร์เพิ่มเติมและช่วยให้แอปนี้ดำเนินต่อไปได้</string>
<string name="upgrade_benefit_themes">การปรับแต่งธีม</string>
<string name="upgrade_benefit_autoplay">เล่นอัตโนมัติและหยุดชั่วคราวอัตโนมัติ</string>
<string name="upgrade_benefit_autoconnect">เชื่อมต่ออัตโนมัติ</string>
<string name="upgrade_benefit_popups">ป๊อปอัปเมื่อเปิดเคสและเชื่อมต่อ</string>
<string name="upgrade_benefit_widgets">วิดเจ็ตหน้าจอหลัก</string>
<string name="upgrade_benefit_device_settings">การตั้งค่าอุปกรณ์ขั้นสูง</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">อุปกรณ์</string>
<string name="settings_devices_description">จัดการอุปกรณ์ของคุณ</string>
<string name="settings_reaction_label">ปฏิกิริยา</string>
<string name="settings_reaction_description">ตอบสนองต่อเหตุการณ์และพฤติกรรม</string>
<string name="settings_category_yourdevice_label">อุปกรณ์ของคุณ</string>
<string name="settings_category_compatibility_options_title">ตัวเลือกความเข้ากันได้</string>
<string name="settings_category_compatibility_options_description">อย่าแตะต้องหากทุกอย่างทำงานได้ดี ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod bir kişi tarafından geliştirilmiştir. Yükseltme ekstra özelliklerin kilidini açar ve uygulamanın canlı kalabilmesine yardımcı olur.</string>
<string name="upgrade_benefit_themes">Tema özelleştirmesi</string>
<string name="upgrade_benefit_autoplay">Oto-oynatma &amp; oto-duraklatma</string>
<string name="upgrade_benefit_autoconnect">Oto-bağlanma</string>
<string name="upgrade_benefit_popups">Kutu açıldığında &amp; bağlandığında popup</string>
<string name="upgrade_benefit_widgets">Ana ekran widgetleri</string>
<string name="upgrade_benefit_device_settings">Gelişmiş cihaz ayarları</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Cihazlar</string>
<string name="settings_devices_description">Cihazlarınızı yönetin.</string>
<string name="settings_reaction_label">Tepkiler</string>
<string name="settings_reaction_description">Olaylar ve etkileşimlere verilen tepkiler.</string>
<string name="settings_category_yourdevice_label">Aygıtınız</string>
<string name="settings_category_compatibility_options_title">Uyumluluk seçenekleri</string>
<string name="settings_category_compatibility_options_description">Eğer her şey düzgün çalışıyorsa lütfen dokunma ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod розробляється однією людиною. Оновлення розблоковує додаткові функції та допомагає підтримувати застосунок.</string>
<string name="upgrade_benefit_themes">Налаштування теми</string>
<string name="upgrade_benefit_autoplay">Автовідтворення та автопауза</string>
<string name="upgrade_benefit_autoconnect">Автопід\'єднання</string>
<string name="upgrade_benefit_popups">Спливаюче вікно при відкритті футляра та підключенні</string>
<string name="upgrade_benefit_widgets">Віджети головного екрана</string>
<string name="upgrade_benefit_device_settings">Розширені налаштування пристрою</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Пристрої</string>
<string name="settings_devices_description">Керування вашими пристроями.</string>
<string name="settings_reaction_label">Реакції</string>
<string name="settings_reaction_description">Реагування на події та дії.</string>
<string name="settings_category_yourdevice_label">Ваш пристрій</string>
<string name="settings_category_compatibility_options_title">Опції сумісності</string>
<string name="settings_category_compatibility_options_description">Не чіпай, якщо все працює ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod ایک اکیلے شخص نے بنائی ہے۔ اپگریڈ کرنے سے اضافی خصوصیات ملتی ہیں اور ایپ کو زندہ رکھنے میں مدد ملتی ہے۔</string>
<string name="upgrade_benefit_themes">تھیم کی تخصیص</string>
<string name="upgrade_benefit_autoplay">خودکار چلائیں اور خودکار رکیں</string>
<string name="upgrade_benefit_autoconnect">خودکار کنیکٹ</string>
<string name="upgrade_benefit_popups">کیس کھلنے اور کنیکشن پر پاپ اپ</string>
<string name="upgrade_benefit_widgets">ہوم اسکرین ویجٹس</string>
<string name="upgrade_benefit_device_settings">ڈیوائس کی اعلی ترتیبات</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">آلات</string>
<string name="settings_devices_description">اپنے آلات کا نظم کریں۔</string>
<string name="settings_reaction_label">رد عمل</string>
<string name="settings_reaction_description">واقعات اور رویوں پر رد عمل ظاہر کریں۔</string>
<string name="settings_category_yourdevice_label">آپ کا آلہ</string>
<string name="settings_category_compatibility_options_title">مطابقت کے اختیارات</string>
<string name="settings_category_compatibility_options_description">اگر سب کچھ کام کر رہا ہو تو ہاتھ نہ لگائیں ؛)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod bitta shaxs tomonidan ishlab chiqilgan. Yangilash qo\'shimcha funksiyalarni ochadi va ilovani tirik saqlashga yordam beradi.</string>
<string name="upgrade_benefit_themes">Mavzu sozlamalari</string>
<string name="upgrade_benefit_autoplay">Avtomatik ijro &amp; avtomatik to\'xtatish</string>
<string name="upgrade_benefit_autoconnect">Avtomatik ulanish</string>
<string name="upgrade_benefit_popups">Quti ochilganda &amp; ulanishda qalqib chiquvchi oyna</string>
<string name="upgrade_benefit_widgets">Asosiy ekran vidjetlari</string>
<string name="upgrade_benefit_device_settings">Qurilmaning kengaytirilgan sozlamalari</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Qurilmalar</string>
<string name="settings_devices_description">Qurilmalaringizni boshqaring.</string>
<string name="settings_reaction_label">Reaksiyalar</string>
<string name="settings_reaction_description">Voqealar va xatti-harakatlarga munosabat bildiring.</string>
<string name="settings_category_yourdevice_label">Sizning qurilmangiz</string>
<string name="settings_category_compatibility_options_title">Moslik parametrlari</string>
<string name="settings_category_compatibility_options_description">Agar hamma narsa ishlayotgan bo\'lsa, tegmang ;)</string>
-2
View File
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod được phát triển bởi một người duy nhất. Việc nâng cấp sẽ mở khóa các tính năng bổ sung và giúp duy trì ứng dụng.</string>
<string name="upgrade_benefit_themes">Tùy chỉnh giao diện</string>
<string name="upgrade_benefit_autoplay">Tự động phát &amp; tự động tạm dừng</string>
<string name="upgrade_benefit_autoconnect">Tự động kết nối</string>
<string name="upgrade_benefit_popups">Cửa sổ bật lên khi mở hộp &amp; kết nối</string>
<string name="upgrade_benefit_widgets">Widget màn hình chính</string>
<string name="upgrade_benefit_device_settings">Cài đặt thiết bị nâng cao</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">Thiết bị</string>
<string name="settings_devices_description">Quản lý thiết bị của bạn.</string>
<string name="settings_reaction_label">Phản ứng</string>
<string name="settings_reaction_description">Phản ứng với các sự kiện và hành vi.</string>
<string name="settings_category_yourdevice_label">Thiết bị của bạn</string>
<string name="settings_category_compatibility_options_title">Tùy chọn tương thích</string>
<string name="settings_category_compatibility_options_description">Đừng chạm vào nếu mọi thứ hoạt động ;)</string>
@@ -21,7 +21,6 @@
<string name="upgrade_preamble">CAPod 由一个人开发。升级可解锁额外功能,并帮助应用持续运营。</string>
<string name="upgrade_benefit_themes">主题定制</string>
<string name="upgrade_benefit_autoplay">自动播放 &amp; 自动暂停</string>
<string name="upgrade_benefit_autoconnect">自动连接</string>
<string name="upgrade_benefit_popups">打开耳机盒 &amp; 连接时弹出提示</string>
<string name="upgrade_benefit_widgets">主屏幕小组件</string>
<string name="upgrade_benefit_device_settings">高级设备设置</string>
@@ -66,7 +65,6 @@
<string name="settings_devices_label">设备</string>
<string name="settings_devices_description">管理您的设备。</string>
<string name="settings_reaction_label">动作</string>
<string name="settings_reaction_description">响应事件和行为的动作。</string>
<string name="settings_category_yourdevice_label">您的设备</string>
<string name="settings_category_compatibility_options_title">兼容性选项</string>
<string name="settings_category_compatibility_options_description">如果一切正常,请不要修改 ;)</string>

Some files were not shown because too many files have changed in this diff Show More