Compare commits

...
34 Commits
Author SHA1 Message Date
d4rken-org-releaser[bot] a91ef44686 Release: 5.1.10-rc0 2026-06-22 19:00:07 +00:00
darken e3bef4e74b General: Update app translations from Crowdin 2026-06-22 20:42:35 +02:00
darken 358bf5e244 fix(monitor): Drive monitor mode from first addressed profile 2026-06-22 20:16:37 +02:00
d4rken-org-releaser[bot] fba2d3a59d Release: 5.1.9-rc0 2026-06-18 12:00:29 +00:00
darken 0abba4ece2 test(reaction): Harden Conversational Awareness pod-removal coverage 2026-06-18 13:57:07 +02:00
darken e9b0694b67 fix(reaction): Honor One-Pod Mode in CA resume worn-guard 2026-06-18 12:07:19 +02:00
darken 49bbf1bc85 fix(reaction): Settle cold CA terminals to catch pod-removal re-key race 2026-06-18 12:07:19 +02:00
darken f5b6a5c605 fix(reaction): Ignore CA terminals from pod removal/insertion re-key 2026-06-18 12:07:19 +02:00
darken fccc6cedd5 fix(reaction): Restore CA status 6 as a terminal 2026-06-18 12:07:19 +02:00
darken a03766448e fix(reaction): Apply resume age-guard only to the inferred stale-end 2026-06-18 12:07:19 +02:00
darken f0c9d318ff fix(aap): Report speaking=true for Conversational Awareness resume (status 5) 2026-06-18 12:07:19 +02:00
darken 5c5cc6f28e fix(reaction): Refresh CA keep-alive timestamp so long conversations resume 2026-06-18 12:07:19 +02:00
darken 246b96bfb4 fix(reaction): Treat CA status 5 as speech-resume, not a stop 2026-06-18 12:07:19 +02:00
darken 352e020b54 test(aap): Make handshake-timeout test deterministic with real-time bounds 2026-06-15 09:16:51 +02:00
darken 72f5690ea6 test(aap): Stabilize flaky handshake-timeout test under CI load 2026-06-15 09:16:51 +02:00
darken 1ed1199574 fix(ble): Stop foreign same-model pods from hijacking a device's identity 2026-06-15 09:16:51 +02:00
darken fd4a43de96 fix(aap): Bound handshake with watchdog and escalate reconnect backoff 2026-06-14 21:28:42 +02:00
darken e406fd4cc1 fix(monitor): Restore tint on product icons to prevent invisibility on light backgrounds
Without tint, white PNG product icons (AirPods photos) are invisible on
light notification backgrounds. Restore src_in tint with notification_icon_tint
(a reliable day/night color resource) in both the PodInfoItemIcon.Notification
style (covers small layouts) and the big layout product ImageViews that do
not use that style.
2026-06-14 17:52:45 +02:00
darken 1e555cc712 fix(monitor): Fix notification color inconsistency in dark mode on One UI
Remove Theme.Material3.DynamicColors.DayNight from the notification
container style; it does not resolve correctly in the notification host
process, causing light-mode colors to appear in dark mode. Replace all
?attr/colorAccent and ?android:attr/textColorPrimary refs in RemoteViews
layouts with explicit day/night color resources (notification_icon_tint)
and TextAppearance.Compat.Notification.Title defaults. Change tintMode
from multiply to src_in for status glyphs; remove tint from product PNG
icons to prevent silhouette rendering.

Fixes #613
2026-06-14 17:52:45 +02:00
d4rken-org-releaser[bot] 227a6b2a7b Release: 5.1.8-rc0 2026-06-10 18:25:44 +00:00
darken 5f661d71a6 General: Update app translations from Crowdin 2026-06-10 20:20:37 +02:00
darken 2804543b9d feat(reaction): Add charged notification 2026-06-10 18:13:51 +02:00
darken 380397321c fix(reaction): Apply volume reduction slider only on drag release
The conversation volume slider committed a profile write on every
drag frame — laggy dragging, and racing async writes persisted stale
mid-drag values (observed: 78 stored while the UI showed 70). Use
local state while dragging and commit on release, matching the
adaptive-noise and tone-volume sliders.
2026-06-10 11:39:58 +02:00
darken d9c8902d34 fix(reaction): Restore volume when conversation end frame never arrives
With one AirPod in the case the pod deterministically drops the
terminal 0x4B frame: the wind-down flurry ends on a transitional
status (1,2,3,0xB,4 then nothing), so the reaction never disengaged
and the volume stayed low until the 5-minute backstop (#608).
Reproduced on Pro 3 (fw 6589, 6503) and Pro 2 USB-C (fw 6814) —
all three share one firmware train; with both pods worn the terminal
always arrives.

The pod sends no frames during active speech, so any non-START frame
means the wind-down has begun and a terminal is imminent. A HOLD now
arms a short 6s fuse instead of the 5-minute backstop: if no terminal
(or fresh START) follows, the reaction disengages anyway. The fuse
must stay above ~5s — gaps up to 2.8s were observed between
consecutive wind-down frames. STARTs still arm the long backstop,
since the pod stays engaged and silent against ambient noise for
20-30s+ and a short timeout there resumes media mid-conversation.

Validated on hardware on both models: 7/7 single-pod conversations
restored exactly 6s after the last wind-down frame.
2026-06-10 11:39:58 +02:00
darken a1b9abd4cb fix(ble): Drop proximity messages with unsupported payload prefix
AirPods Gen4 emit a one-off type 0x07 frame from their identity address
on connect whose payload prefix is 0x07 instead of 0x01. Its bytes are
not the plaintext status format, but the model bytes happen to match,
so it minted a fresh device tracker and showed as a duplicate device
card until the stale timeout.

Every known plaintext status broadcast (including pairing mode) uses
prefix 0x01; pairing state lives in the suffix byte. Reject anything
else at the decoder, logging the dropped frame's hex.

Fixes #603
2026-06-10 10:44:48 +02:00
d4rken-org-releaser[bot] 5d30844fa8 Release: 5.1.7-rc0 2026-06-08 07:22:52 +00:00
Matthias Urhahn af1b1b4249 Revert #605's cooldown-only mitigation in favor of the root-cause fix
@mvanhorn independently fixed #598 in #605 by no longer resetting the
case cooldown on close, throttling the re-pop. We cherry-picked that
commit above to keep his authorship/credit, but this PR instead removes
the underlying lid-state flapping at its source (out-of-case pod's stale
lid byte -> UNKNOWN), so the cooldown can keep resetting on close and a
genuine close->reopen still shows the popup. Reverting his change here so
the two approaches don't stack; thanks @mvanhorn for the parallel work.
2026-06-08 08:05:50 +02:00
Matt Van Horn 2cce9ae56c fix: case-open popup re-appears after the case is closed 2026-06-08 08:05:50 +02:00
Matthias Urhahn 4bab7c61a9 fix(reaction): Stop case popup flicker when one AirPod is out of case
When one pod is out of the case, the out-of-case pod broadcasts bit4-only
frames whose lid byte is stale and decodes to a phantom OPEN even while the
case is shut, interleaved ~1:1 with the correct in-case-pod (bit6) frames.
The derived lid state flapped OPEN<->CLOSED, so the case-open popup re-popped
~0.5s after closing and sometimes lingered. Verified on AirPods Pro 1 (issue
log) and Pro 3 (live BLE capture).

- Trust the lid bit only from in-case-pod (bit6) or both-in-case (bit2) frames;
  bit4-only frames now decode to UNKNOWN, and the real state is recovered from a
  recent in-case broadcast (matches LibrePods).
- getLatestCaseLidState recovers from history within a 2s age window instead of a
  fixed frame count, so a missed CLOSED can't keep a stale OPEN.
- Don't refresh the show-cooldown on a non-CLOSED hide, so a transient UNKNOWN
  can't suppress a genuine re-open.
- Add a freshness backstop: dismiss the popup if a fresh OPEN broadcast stops
  arriving (device left BLE range while open).
- Key popup/auto-connect de-duplication on the derived lid state, not just raw
  advertisement bytes, since the effective lid can change while bytes don't.

Closes #598
2026-06-08 08:05:50 +02:00
Matthias Urhahn 81e2bc1dba feat(overview): Suggest troubleshooter when a connected device sends no data
Adds a dashboard hint card pointing at the existing Troubleshooter when a profile is connected to the system (audio) but CAPod is receiving no live data — the symptom of a phone dropping AirPods BLE broadcasts (e.g. some HyperOS devices, #603). Debounced ~15s so it doesn't flash during the gap between an audio connection and the first broadcast, and suppressed whenever any pod is live so it never claims 'no data' while data is visibly arriving.
2026-06-08 07:45:29 +02:00
Matthias Urhahn df2783d8a1 feat(troubleshooter): Persist only the minimal working compat combo
Probe compatibility options through a transient in-memory override on BlePodMonitor instead of writing the user's persisted settings on every attempt. Only the winning combo is persisted, and only on success; failure or cancellation clears the override, restoring the user's original settings. Combos are tried fewest-disables-first so a phone that only needs batching disabled isn't left with filtering disabled too. Per-attempt cache clearing plus a freshness cutoff stop a previous combo's cached devices from satisfying the next one, and the 'found' checks now require a fresh live BLE observation rather than cached/AAP state.
2026-06-08 07:45:29 +02:00
Matthias Urhahn 20a6953b54 General: Update app translations from Crowdin 2026-06-07 13:30:43 +02:00
darken fdd4f69247 feat(overview): Add setting to hide unmatched devices 2026-05-31 10:04:26 +02:00
darken 5ee777b196 fix(reaction): Don't resume media mid-talk on Conversational Awareness
The pod only signals CA start and end, not continuous keep-alives. On fw 6861 it held CA engaged for 21s with zero 0x4B frames while the wearer kept talking, so the 12s stale-timeout fired mid-speech and resumed media; the pod never re-sent a start frame, so it didn't re-pause.

Disengage now waits for the explicit not-speaking frame (status 5 added as a terminal STOP, since that firmware winds down 3->5 and never reaches 6/8/9). Transitional/unknown statuses stay engaged. The stale timer is demoted to a long 5min backstop for a fully-dropped terminal frame; constants moved to Kotlin Durations.
2026-05-31 06:39:52 +02:00
142 changed files with 5444 additions and 493 deletions
+1 -1
View File
@@ -1 +1 @@
5.1.6-rc0 50106000
5.1.10-rc0 50110000
+8 -8
View File
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="foss_upgrade_donate_label">تبرع</string>
<string name="foss_upgrade_alreadydonated_label">أنا متبرّع فعلًا</string>
<string name="foss_upgrade_no_money_label">أنفق كل أموالي على AirPods</string>
<string name="upgrade_foss_preamble">CAPod FOSS مجاني ومفتوح المصدر. إذا وجدته مفيدًا، ففكّر في دعم تطويره للمساعدة في استمرار المشروع.</string>
<string name="upgrade_foss_sponsor_action">دعم المشروع</string>
<string name="upgrade_foss_sponsor_subtitle">لا إعلانات. لا تتبع. لا قيود من Google Play.</string>
<string name="upgrade_foss_sponsor_returned_early">هل عدتم فعلًا؟ دعمكم يُبقي CAPod حيًا.</string>
<string name="upgrade_badge_label">البرمجيات الحرة (FOSS)</string>
<string name="foss_upgrade_donate_label">تبرُّع</string>
<string name="foss_upgrade_alreadydonated_label">لقد تبرّعتُ بالفعل</string>
<string name="foss_upgrade_no_money_label">أنفق كل أموالي على سمّاعات AirPods</string>
<string name="upgrade_foss_preamble">برنامج CAPod FOSS مجاني ومفتوح المصدر. إذا وجدتهُ مفيدًا، ففكّر في دعم تطويره للمساعدة في استمرار المشروع.</string>
<string name="upgrade_foss_sponsor_action">دعم التطوير</string>
<string name="upgrade_foss_sponsor_subtitle">لا إعلانات. لا تتبُّع. لا قيود من جوجل بلاي.</string>
<string name="upgrade_foss_sponsor_returned_early">هل عدت بالفعل؟ دعمك يُبقي CAPod حيًّا.</string>
<string name="upgrade_badge_label">البرمجيات الحرة والمفتوحة المصدر</string>
</resources>
+2 -2
View File
@@ -5,7 +5,7 @@
<string name="foss_upgrade_no_money_label">Es iztērēju visu savu naudu AirPods austiņām</string>
<string name="upgrade_foss_preamble">CAPod FOSS ir bezmaksas un atkļējkoda. Ja tā ir noderba, apsveriet attīstības sponsēšanu, lai palīdzētu turpināt projektu.</string>
<string name="upgrade_foss_sponsor_action">Sponsorēt attīstību</string>
<string name="upgrade_foss_sponsor_subtitle">Bez reklamām. Bez sekšanas. Bez Google Play saistībām.</string>
<string name="upgrade_foss_sponsor_returned_early">Jau atpakaļ? Jūsu atbalsts uztur CAPod pie dzīvības.</string>
<string name="upgrade_foss_sponsor_subtitle">Bez reklamām. Bez izsekošanas. Bez Google Play saistībām.</string>
<string name="upgrade_foss_sponsor_returned_early">Jau atpakaļ? Tavs atbalsts uztur CAPod esamību.</string>
<string name="upgrade_badge_label">FOSS</string>
</resources>
+7 -7
View File
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="upgrades_gplay_unavailable_error">خدمات Google Play غير متوفّرة.</string>
<string name="upgrades_no_purchases_found_check_account">لم يتم العثور على أي مشتريات. هل تستخدم الحساب الصحيح؟</string>
<string name="upgrades_gplay_billing_error_label">خطأ في Google Play</string>
<string name="upgrades_gplay_billing_error_description">حدث خطأ في Google Play. يُرجى المحاولة لاحقًا أو إعادة تشغيل هاتفك.\n\nخطأ: %s</string>
<string name="upgrades_gplay_billing_result_error_label">خطأ في فوترة Google Play</string>
<string name="upgrades_gplay_billing_result_error_description">حدث خطأ أثناء طلب تفاصيل عملية الشراء من Google Play. يُرجى مسح ذاكرة التخزين المؤقّت لـ Google Play وإعادة تشغيل هاتفك.\n\nخطأ %s</string>
<string name="upgrade_restore_action">استعادة المشتريات</string>
<string name="upgrades_gplay_unavailable_error">خدمات جوجل بلاي غير متوفّرة.</string>
<string name="upgrades_no_purchases_found_check_account">لم يُعثَر على أيّ مشتريات. هل تستخدم الحساب الصحيح؟</string>
<string name="upgrades_gplay_billing_error_label">خطأ في جوجل بلاي</string>
<string name="upgrades_gplay_billing_error_description">حدث خطأ في سوق جوجل بلاي. يُرجى المحاولة لاحقًا أو إعادة تشغيل هاتفك.\n\nالخطأ: %s</string>
<string name="upgrades_gplay_billing_result_error_label">خطأ في فوترة جوجل بلاي</string>
<string name="upgrades_gplay_billing_result_error_description">حدث خطأ أثناء طلب تفاصيل عملية الشراء من سوق جوجل بلاي. يُرجى مسح ذاكرة التخزين المؤقّت لسوق جوجل بلاي وإعادة تشغيل هاتفك.\n\nالخطأ %s</string>
<string name="upgrade_restore_action">استعادة عملية الشراء</string>
<string name="upgrade_badge_label">النسخة الاحترافية</string>
</resources>
+3 -3
View File
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="upgrades_gplay_unavailable_error">Google Play pakalpojumi nav pieejami.</string>
<string name="upgrades_no_purchases_found_check_account">Nav atrasts neviens pirkums. Vai izmantojat pareizo kontu?</string>
<string name="upgrades_no_purchases_found_check_account">Nav atrasts neviens pirkums. Vai izmanto pareizo kontu?</string>
<string name="upgrades_gplay_billing_error_label">Google Play kļūda</string>
<string name="upgrades_gplay_billing_error_description">Google Play radās kļūda. Lūdzu, mēģiniet vēlreiz vēlāk vai pārstartējiet tālruni.\n\nKļūda: %s</string>
<string name="upgrades_gplay_billing_error_description">Google Play radās kļūda. Lūgums mēģināt vēlreiz vēlāk vai pārsāknēt tālruni.\n\nKļūda: %s</string>
<string name="upgrades_gplay_billing_result_error_label">Google Play norēķinu kļūda</string>
<string name="upgrades_gplay_billing_result_error_description">Radās kļūda, pieprasot no Google Play jūsu pirkuma informāciju. Notīriet Google Play kešatmiņu un pārstartējiet tālruni.\n\nKļūda %s</string>
<string name="upgrades_gplay_billing_result_error_description">Radās kļūda, pieprasot no Google Play pirkuma informāciju. Jāiztīra Google Play kešatmiņa un pārsāknē tālrunis.\n\nKļūda %s</string>
<string name="upgrade_restore_action">Atjaunot pirkumu</string>
<string name="upgrade_badge_label">Pro</string>
</resources>
@@ -83,6 +83,8 @@ class GeneralSettings @Inject constructor(
val reactionsHintDismissed = dataStore.createValue("ui.hint.reactions_per_device.dismissed", false)
val hideUnmatchedDevices = dataStore.createValue("ui.overview.unmatched.hidden", false)
val themeMode = dataStore.createValue(
"core.ui.theme.mode", ThemeMode.SYSTEM, json,
onErrorFallbackToDefault = BuildConfigWrap.BUILD_TYPE != BuildConfigWrap.BuildType.DEV,
@@ -64,6 +64,7 @@ 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 eu.darken.capod.reaction.core.charged.ChargedSlotScope
import eu.darken.capod.reaction.core.conversation.ConversationAction
import java.time.Duration
import java.time.Instant
@@ -175,6 +176,9 @@ fun DeviceSettingsScreenHost(
onAutoConnectConditionChange = { vm.setAutoConnectCondition(it) },
onShowPopUpOnCaseOpenChange = { vm.setShowPopUpOnCaseOpen(it) },
onShowPopUpOnConnectionChange = { vm.setShowPopUpOnConnection(it) },
onNotifyWhenChargedChange = { vm.setNotifyWhenCharged(it) },
onChargedThresholdChange = { vm.setChargedThreshold(it) },
onChargedSlotScopeChange = { vm.setChargedSlotScope(it) },
onOpenIssueTracker = { vm.openIssueTracker() },
onOpenAapTracker = { vm.openAapCompatibilityTracker() },
)
@@ -215,6 +219,9 @@ fun DeviceSettingsScreen(
onAutoConnectConditionChange: (AutoConnectCondition) -> Unit = {},
onShowPopUpOnCaseOpenChange: (Boolean) -> Unit = {},
onShowPopUpOnConnectionChange: (Boolean) -> Unit = {},
onNotifyWhenChargedChange: (Boolean) -> Unit = {},
onChargedThresholdChange: (Int) -> Unit = {},
onChargedSlotScopeChange: (ChargedSlotScope) -> Unit = {},
onOpenIssueTracker: () -> Unit = {},
onOpenAapTracker: () -> Unit = {},
) {
@@ -356,6 +363,9 @@ fun DeviceSettingsScreen(
onAutoConnectConditionChange = onAutoConnectConditionChange,
onShowPopUpOnCaseOpenChange = onShowPopUpOnCaseOpenChange,
onShowPopUpOnConnectionChange = onShowPopUpOnConnectionChange,
onNotifyWhenChargedChange = onNotifyWhenChargedChange,
onChargedThresholdChange = onChargedThresholdChange,
onChargedSlotScopeChange = onChargedSlotScopeChange,
onOpenIssueTracker = onOpenIssueTracker,
)
}
@@ -31,6 +31,7 @@ import eu.darken.capod.profiles.core.DeviceProfilesRepo
import eu.darken.capod.profiles.core.ProfileId
import eu.darken.capod.profiles.core.ReactionConfig
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import eu.darken.capod.reaction.core.charged.ChargedSlotScope
import eu.darken.capod.reaction.core.conversation.ConversationAction
import eu.darken.capod.reaction.core.stem.StemAction
import kotlinx.coroutines.delay
@@ -438,6 +439,24 @@ class DeviceSettingsViewModel @Inject constructor(
proGatedReaction(enabled) { it.copy(showPopUpOnConnection = enabled) }
}
fun setNotifyWhenCharged(enabled: Boolean) {
log(TAG, INFO) { "setNotifyWhenCharged($enabled)" }
proGatedReaction(enabled) { it.copy(notifyWhenCharged = enabled) }
}
fun setChargedSlotScope(scope: ChargedSlotScope) = launch {
log(TAG, INFO) { "setChargedSlotScope($scope)" }
updateProfileNow { it.copy(chargedSlotScope = scope) }
}
fun setChargedThreshold(percent: Int) = launch {
log(TAG, INFO) { "setChargedThreshold($percent)" }
val snapped = (percent.toFloat() / ReactionConfig.CHARGED_THRESHOLD_STEP)
.let { Math.round(it) * ReactionConfig.CHARGED_THRESHOLD_STEP }
.coerceIn(ReactionConfig.MIN_CHARGED_THRESHOLD, ReactionConfig.MAX_CHARGED_THRESHOLD)
updateProfileNow { it.copy(chargedThreshold = snapped) }
}
fun setConversationAction(action: ConversationAction) = launch {
log(TAG, INFO) { "setConversationAction($action)" }
// The action picker is only shown while Conversation Awareness is already enabled (the pod
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.twotone.Message
import androidx.compose.material.icons.automirrored.twotone.VolumeDown
import androidx.compose.material.icons.twotone.BatteryChargingFull
import androidx.compose.material.icons.twotone.BluetoothConnected
import androidx.compose.material.icons.twotone.Hearing
import androidx.compose.material.icons.twotone.LooksOne
@@ -20,6 +21,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -37,6 +39,7 @@ import eu.darken.capod.common.settings.SettingsSection
import eu.darken.capod.common.settings.SettingsSliderItem
import eu.darken.capod.common.settings.SettingsSwitchItem
import eu.darken.capod.main.ui.devicesettings.dialogs.AutoConnectConditionDialog
import eu.darken.capod.main.ui.devicesettings.dialogs.ChargedSlotScopeDialog
import eu.darken.capod.main.ui.devicesettings.dialogs.ConversationActionDialog
import eu.darken.capod.main.ui.devicesettings.previewFullState
import eu.darken.capod.monitor.core.PodDevice
@@ -44,6 +47,7 @@ import eu.darken.capod.pods.core.apple.PodModel
import eu.darken.capod.pods.core.apple.aap.protocol.AapSetting
import eu.darken.capod.profiles.core.ReactionConfig
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import eu.darken.capod.reaction.core.charged.ChargedSlotScope
import eu.darken.capod.reaction.core.conversation.ConversationAction
@Composable
@@ -63,6 +67,9 @@ internal fun ReactionsCard(
onAutoConnectConditionChange: (AutoConnectCondition) -> Unit = {},
onShowPopUpOnCaseOpenChange: (Boolean) -> Unit = {},
onShowPopUpOnConnectionChange: (Boolean) -> Unit = {},
onNotifyWhenChargedChange: (Boolean) -> Unit = {},
onChargedThresholdChange: (Int) -> Unit = {},
onChargedSlotScopeChange: (ChargedSlotScope) -> Unit = {},
onOpenIssueTracker: () -> Unit = {},
) {
val reactions = device.reactions
@@ -70,6 +77,7 @@ internal fun ReactionsCard(
var showAutoConnectConditionDialog by remember { mutableStateOf(false) }
var showConversationActionDialog by remember { mutableStateOf(false) }
var showChargedScopeDialog by remember { mutableStateOf(false) }
SettingsSection(title = stringResource(R.string.settings_reaction_label)) {
if (features.hasEarDetection) {
@@ -159,11 +167,15 @@ internal fun ReactionsCard(
requiresUpgrade = !isPro,
)
if (reactions.conversationAction == ConversationAction.LOWER_VOLUME) {
var sliderValue by remember(reactions.conversationVolumeReduction) {
mutableIntStateOf(reactions.conversationVolumeReduction)
}
SettingsSliderItem(
icon = Icons.AutoMirrored.TwoTone.VolumeDown,
title = stringResource(R.string.settings_conversation_volume_reduction_label),
value = reactions.conversationVolumeReduction.toFloat(),
onValueChange = { onConversationVolumeReductionChange(it.toInt()) },
value = sliderValue.toFloat(),
onValueChange = { sliderValue = it.toInt() },
onValueChangeFinished = { onConversationVolumeReductionChange(sliderValue) },
valueRange = ReactionConfig.MIN_CONVERSATION_VOLUME_REDUCTION.toFloat()..
ReactionConfig.MAX_CONVERSATION_VOLUME_REDUCTION.toFloat(),
enabled = enabled,
@@ -246,6 +258,40 @@ internal fun ReactionsCard(
text = stringResource(R.string.settings_popup_info_not_in_app),
)
}
ReactionsDivider()
SettingsSwitchItem(
icon = Icons.TwoTone.BatteryChargingFull,
title = stringResource(R.string.settings_charged_notification_label),
subtitle = stringResource(R.string.settings_charged_notification_description),
checked = reactions.notifyWhenCharged,
onCheckedChange = onNotifyWhenChargedChange,
requiresUpgrade = !isPro,
)
if (reactions.notifyWhenCharged) {
var thresholdValue by remember(reactions.chargedThreshold) {
mutableIntStateOf(reactions.chargedThreshold)
}
SettingsSliderItem(
icon = Icons.TwoTone.BatteryChargingFull,
title = stringResource(R.string.settings_charged_threshold_label),
value = thresholdValue.toFloat(),
onValueChange = { thresholdValue = it.toInt() },
onValueChangeFinished = { onChargedThresholdChange(thresholdValue) },
valueRange = ReactionConfig.MIN_CHARGED_THRESHOLD.toFloat()..
ReactionConfig.MAX_CHARGED_THRESHOLD.toFloat(),
steps = (ReactionConfig.MAX_CHARGED_THRESHOLD - ReactionConfig.MIN_CHARGED_THRESHOLD) /
ReactionConfig.CHARGED_THRESHOLD_STEP - 1,
valueLabel = { "${it.toInt()}%" },
)
if (features.hasCase) {
SettingsBaseItem(
icon = Icons.TwoTone.Workspaces,
title = stringResource(R.string.settings_charged_scope_label),
subtitle = stringResource(reactions.chargedSlotScope.labelRes),
onClick = { showChargedScopeDialog = true },
)
}
}
}
if (showConversationActionDialog) {
@@ -259,6 +305,17 @@ internal fun ReactionsCard(
)
}
if (showChargedScopeDialog) {
ChargedSlotScopeDialog(
current = reactions.chargedSlotScope,
onSelect = {
onChargedSlotScopeChange(it)
showChargedScopeDialog = false
},
onDismiss = { showChargedScopeDialog = false },
)
}
if (showAutoConnectConditionDialog) {
AutoConnectConditionDialog(
current = reactions.autoConnectCondition,
@@ -0,0 +1,75 @@
package eu.darken.capod.main.ui.devicesettings.dialogs
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.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
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 eu.darken.capod.R
import eu.darken.capod.common.compose.Preview2
import eu.darken.capod.common.compose.PreviewWrapper
import eu.darken.capod.reaction.core.charged.ChargedSlotScope
@Composable
internal fun ChargedSlotScopeDialog(
current: ChargedSlotScope,
onSelect: (ChargedSlotScope) -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(text = stringResource(R.string.settings_charged_scope_label)) },
text = {
Column(Modifier.selectableGroup()) {
ChargedSlotScope.entries.forEach { scope ->
val isSelected = scope == current
Row(
modifier = Modifier
.fillMaxWidth()
.selectable(
selected = isSelected,
onClick = { onSelect(scope) },
role = Role.RadioButton,
)
.padding(vertical = 12.dp, horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(selected = isSelected, onClick = null)
Text(
text = stringResource(scope.labelRes),
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp),
)
}
}
}
},
confirmButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(android.R.string.cancel))
}
},
)
}
@Preview2
@Composable
private fun ChargedSlotScopeDialogPreview() = PreviewWrapper {
ChargedSlotScopeDialog(
current = ChargedSlotScope.PODS_AND_CASE,
onSelect = {},
onDismiss = {},
)
}
@@ -61,6 +61,7 @@ import eu.darken.capod.main.ui.overview.cards.NoProfilesCard
import eu.darken.capod.main.ui.overview.cards.PermissionCard
import eu.darken.capod.main.ui.overview.cards.ReactionsMovedHintCard
import eu.darken.capod.main.ui.overview.cards.SinglePodsCard
import eu.darken.capod.main.ui.overview.cards.TroubleshootSuggestionCard
import eu.darken.capod.main.ui.overview.cards.UnknownPodDeviceCard
import eu.darken.capod.main.ui.overview.cards.UnmatchedDevicesCard
import eu.darken.capod.monitor.core.PodDevice
@@ -172,6 +173,7 @@ fun OverviewScreenHost(vm: OverviewViewModel = hiltViewModel()) {
},
onManageDevices = { vm.goToDeviceManager() },
onSettings = { vm.goToSettings() },
onTroubleShooter = { vm.goToTroubleShooter() },
onUpgrade = { vm.onUpgrade() },
onToggleUnmatched = { vm.toggleUnmatchedDevices() },
onAncModeChange = { device, mode -> vm.setAncMode(device, mode) },
@@ -194,6 +196,7 @@ fun OverviewScreen(
onBluetoothSettings: () -> Unit,
onManageDevices: () -> Unit,
onSettings: () -> Unit,
onTroubleShooter: () -> Unit = {},
onUpgrade: () -> Unit,
onToggleUnmatched: () -> Unit,
onAncModeChange: (PodDevice, AapSetting.AncMode.Value) -> Unit = { _, _ -> },
@@ -351,18 +354,25 @@ fun OverviewScreen(
}
}
// 4c. Troubleshooter suggestion — connected via audio but no live data is reaching us
if (state.showTroubleshootSuggestion) {
item(key = "troubleshoot_suggestion") {
TroubleshootSuggestionCard(onTroubleShooter = onTroubleShooter)
}
}
// 5. Monitoring active card
if (state.profiles.isNotEmpty() && state.devices.isEmpty()) {
if (state.profiles.isNotEmpty() && state.profiledDevices.isEmpty() && !state.shouldShowUnmatchedSection) {
item(key = "monitoring_active") {
MonitoringActiveCard()
}
}
// 6. Unmatched devices section
if (state.unmatchedDevices.isNotEmpty()) {
if (state.shouldShowUnmatchedSection) {
item(key = "unmatched_header") {
UnmatchedDevicesCard(
count = state.unmatchedDevices.size,
count = state.visibleUnmatchedDevices.size,
isExpanded = state.showUnmatchedDevices,
onToggle = onToggleUnmatched,
)
@@ -370,7 +380,7 @@ fun OverviewScreen(
if (state.showUnmatchedDevices) {
itemsIndexed(
items = state.unmatchedDevices,
items = state.visibleUnmatchedDevices,
key = { index, device -> unmatchedDeviceKey(device, index) },
) { _, device ->
PodDeviceCard(
@@ -34,9 +34,12 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.combine as combineFlows
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@@ -78,6 +81,59 @@ class OverviewViewModel @Inject constructor(
private val showUnmatchedDevices = MutableStateFlow(false)
private val userExpansionOverrides = MutableStateFlow<Set<String>>(emptySet())
private data class OverviewUiSettings(
val reactionsHintDismissed: Boolean,
val hideUnmatchedDevices: Boolean,
val showTroubleshootSuggestion: Boolean,
)
/**
* True when a profile is connected to the system (audio) but CAPod has *no* live data for any
* device — the classic "broadcasts are being dropped by the ROM" symptom (e.g. some HyperOS
* phones, see #603). Surfaced as a hint pointing at the Troubleshooter, which can probe and
* persist a working compatibility combo. Debounced so it doesn't flash during the brief window
* between an audio connection and the first BLE broadcast. Suppressed whenever any pod is live,
* so it never claims "no data" while data is visibly arriving (incl. the #603 duplicate state).
*/
private val troubleshootSuggestion = combineFlows(
profilesRepo.profiles,
bluetoothManager.connectedDevices.onStart { emit(emptyList()) },
deviceMonitor.devices,
permissionTool.missingScanPermissions,
) { profiles, connectedDevices, devices, missingScanPermissions ->
val connectedAddresses = connectedDevices.mapTo(mutableSetOf()) { it.address }
val anyProfileConnected = profiles.any { it.address != null && it.address in connectedAddresses }
val anyLivePod = devices.any { it.isLive }
missingScanPermissions.isEmpty() && anyProfileConnected && !anyLivePod
}
.distinctUntilChanged()
.flatMapLatest { conditionMet ->
if (conditionMet) flow {
delay(TROUBLESHOOT_SUGGESTION_DELAY_MS)
emit(true)
} else flowOf(false)
}
.onStart { emit(false) }
.distinctUntilChanged()
private val overviewUiSettings = combineFlows(
generalSettings.reactionsHintDismissed.flow,
generalSettings.hideUnmatchedDevices.flow,
troubleshootSuggestion,
) { reactionsHintDismissed, hideUnmatched, showTroubleshootSuggestion ->
OverviewUiSettings(reactionsHintDismissed, hideUnmatched, showTroubleshootSuggestion)
}
init {
// When the persistent "hide unmatched" setting is enabled, reset the in-session expand
// toggle so the section reappears collapsed if the user later disables the setting.
launch {
generalSettings.hideUnmatchedDevices.flow
.filter { it }
.collect { showUnmatchedDevices.value = false }
}
}
val workerAutolaunch = combine(
permissionTool.missingScanPermissions,
monitorModeResolver.effectiveMode,
@@ -134,9 +190,9 @@ class OverviewViewModel @Inject constructor(
upgradeRepo.upgradeInfo,
showUnmatchedDevices,
userExpansionOverrides,
generalSettings.reactionsHintDismissed.flow,
overviewUiSettings,
profilesRepo.hadLegacyReactionData,
) { _, permissions, devices, isDebug, isBluetoothEnabled, profiles, upgradeInfo, showUnmatched, expandedIds, reactionsHintDismissed, hadLegacyReactionData ->
) { _, permissions, devices, isDebug, isBluetoothEnabled, profiles, upgradeInfo, showUnmatched, expandedIds, uiSettings, hadLegacyReactionData ->
// Prune stale overrides (profiles that no longer exist)
val currentProfileIds = profiles.map { it.id }.toSet()
val prunedExpandedIds = expandedIds.filter { it in currentProfileIds }.toSet()
@@ -151,7 +207,9 @@ class OverviewViewModel @Inject constructor(
upgradeInfo = upgradeInfo,
showUnmatchedDevices = showUnmatched,
userExpandedIds = prunedExpandedIds,
showReactionsHint = hadLegacyReactionData && !reactionsHintDismissed,
showReactionsHint = hadLegacyReactionData && !uiSettings.reactionsHintDismissed,
hideUnmatchedDevices = uiSettings.hideUnmatchedDevices,
showTroubleshootSuggestion = uiSettings.showTroubleshootSuggestion,
)
}.asLiveState()
@@ -168,6 +226,8 @@ class OverviewViewModel @Inject constructor(
val showUnmatchedDevices: Boolean,
val userExpandedIds: Set<String> = emptySet(),
val showReactionsHint: Boolean = false,
val hideUnmatchedDevices: Boolean = false,
val showTroubleshootSuggestion: Boolean = false,
) {
val isScanBlocked: Boolean get() = permissions.any { it.isScanBlocking }
@@ -188,6 +248,11 @@ class OverviewViewModel @Inject constructor(
val hiddenProfiledDeviceCount: Int get() = profiledDevices.size - visibleProfiledDevices.size
val unmatchedDevices: List<PodDevice> get() = devices.filter { it.profileId == null }
/** Unmatched devices actually shown on the dashboard (empty when the hide setting is on). */
val visibleUnmatchedDevices: List<PodDevice>
get() = if (hideUnmatchedDevices) emptyList() else unmatchedDevices
val shouldShowUnmatchedSection: Boolean get() = visibleUnmatchedDevices.isNotEmpty()
val bluetoothIconState: BluetoothIconState
get() = when {
isScanBlocked -> BluetoothIconState.HIDDEN
@@ -226,6 +291,11 @@ class OverviewViewModel @Inject constructor(
navTo(Nav.Settings.Index)
}
fun goToTroubleShooter() {
log(TAG, INFO) { "goToTroubleShooter()" }
navTo(Nav.Main.TroubleShooter)
}
fun goToDeviceManager() {
log(TAG, INFO) { "goToDeviceManager()" }
navTo(Nav.Main.DeviceManager)
@@ -286,6 +356,14 @@ class OverviewViewModel @Inject constructor(
companion object {
private const val FREE_DEVICE_LIMIT = 1
/**
* How long the "connected but no live data" condition must hold before the troubleshooter
* hint appears, so it doesn't flash during the gap between an audio connection and the first
* BLE broadcast.
*/
private const val TROUBLESHOOT_SUGGESTION_DELAY_MS = 15_000L
private val TAG = logTag("Overview", "VM")
}
}
@@ -0,0 +1,71 @@
package eu.darken.capod.main.ui.overview.cards
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.twotone.Troubleshoot
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.darken.capod.R
import eu.darken.capod.common.compose.Preview2
import eu.darken.capod.common.compose.PreviewWrapper
@Composable
fun TroubleshootSuggestionCard(onTroubleShooter: () -> Unit) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
) {
Column(
modifier = Modifier.padding(16.dp),
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = Icons.TwoTone.Troubleshoot,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(end = 8.dp),
)
Text(
text = stringResource(R.string.overview_troubleshoot_suggestion_label),
style = MaterialTheme.typography.titleMedium,
)
}
Spacer(modifier = Modifier.height(4.dp))
Text(
text = stringResource(R.string.overview_troubleshoot_suggestion_description),
style = MaterialTheme.typography.bodyMedium,
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = onTroubleShooter,
modifier = Modifier.align(Alignment.End),
) {
Text(text = stringResource(R.string.overview_troubleshoot_suggestion_action))
}
}
}
}
@Preview2
@Composable
private fun TroubleshootSuggestionCardPreview() = PreviewWrapper {
TroubleshootSuggestionCard(onTroubleShooter = {})
}
@@ -12,6 +12,7 @@ import androidx.compose.material.icons.twotone.FilterList
import androidx.compose.material.icons.automirrored.twotone.Message
import androidx.compose.material.icons.twotone.Notifications
import androidx.compose.material.icons.twotone.Palette
import androidx.compose.material.icons.twotone.VisibilityOff
import androidx.compose.material.icons.automirrored.twotone.ViewList
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -58,6 +59,7 @@ fun GeneralSettingsScreenHost(vm: GeneralSettingsViewModel = hiltViewModel()) {
onOffloadedFilteringDisabledChanged = { disabled -> vm.setOffloadedFilteringDisabled(disabled) },
onOffloadedBatchingDisabledChanged = { disabled -> vm.setOffloadedBatchingDisabled(disabled) },
onUseIndirectScanResultCallbackChanged = { enabled -> vm.setUseIndirectScanResultCallback(enabled) },
onHideUnmatchedDevicesChanged = { enabled -> vm.setHideUnmatchedDevices(enabled) },
onThemeModeSelected = { mode -> vm.setThemeMode(mode) },
onThemeStyleSelected = { style -> vm.setThemeStyle(style) },
onThemeColorSelected = { color -> vm.setThemeColor(color) },
@@ -75,6 +77,7 @@ fun GeneralSettingsScreen(
onOffloadedFilteringDisabledChanged: (Boolean) -> Unit,
onOffloadedBatchingDisabledChanged: (Boolean) -> Unit,
onUseIndirectScanResultCallbackChanged: (Boolean) -> Unit,
onHideUnmatchedDevicesChanged: (Boolean) -> Unit,
onThemeModeSelected: (ThemeMode) -> Unit = {},
onThemeStyleSelected: (ThemeStyle) -> Unit = {},
onThemeColorSelected: (ThemeColor) -> Unit = {},
@@ -197,6 +200,21 @@ fun GeneralSettingsScreen(
},
)
}
item {
SettingsBaseItem(
title = stringResource(R.string.settings_overview_hide_unmatched_label),
subtitle = stringResource(R.string.settings_overview_hide_unmatched_description),
icon = Icons.TwoTone.VisibilityOff,
onClick = { onHideUnmatchedDevicesChanged(!state.hideUnmatchedDevices) },
trailingContent = {
Switch(
checked = state.hideUnmatchedDevices,
onCheckedChange = onHideUnmatchedDevicesChanged,
modifier = Modifier.padding(start = 16.dp),
)
},
)
}
item {
SettingsCategoryHeader(text = stringResource(R.string.settings_category_compatibility_options_title))
}
@@ -267,6 +285,7 @@ private fun previewGeneralState(isPro: Boolean) = GeneralSettingsViewModel.State
isOffloadedFilteringDisabled = false,
isOffloadedBatchingDisabled = false,
useIndirectScanResultCallback = false,
hideUnmatchedDevices = false,
themeState = ThemeState(),
)
@@ -281,6 +300,7 @@ private fun GeneralSettingsScreenProPreview() = PreviewWrapper {
onOffloadedFilteringDisabledChanged = {},
onOffloadedBatchingDisabledChanged = {},
onUseIndirectScanResultCallbackChanged = {},
onHideUnmatchedDevicesChanged = {},
)
}
@@ -295,5 +315,6 @@ private fun GeneralSettingsScreenNonProPreview() = PreviewWrapper {
onOffloadedFilteringDisabledChanged = {},
onOffloadedBatchingDisabledChanged = {},
onUseIndirectScanResultCallbackChanged = {},
onHideUnmatchedDevicesChanged = {},
)
}
@@ -34,6 +34,7 @@ class GeneralSettingsViewModel @Inject constructor(
val isOffloadedFilteringDisabled: Boolean,
val isOffloadedBatchingDisabled: Boolean,
val useIndirectScanResultCallback: Boolean,
val hideUnmatchedDevices: Boolean,
val themeState: ThemeState,
)
@@ -57,7 +58,8 @@ class GeneralSettingsViewModel @Inject constructor(
},
generalSettings.themeState,
isPro,
) { general, compat, themeState, isPro ->
generalSettings.hideUnmatchedDevices.flow,
) { general, compat, themeState, isPro, hideUnmatched ->
State(
isPro = isPro,
showConnectedNotification = general[0] as Boolean,
@@ -65,6 +67,7 @@ class GeneralSettingsViewModel @Inject constructor(
isOffloadedFilteringDisabled = compat[0] as Boolean,
isOffloadedBatchingDisabled = compat[1] as Boolean,
useIndirectScanResultCallback = compat[2] as Boolean,
hideUnmatchedDevices = hideUnmatched,
themeState = themeState,
)
}.asLiveState()
@@ -94,6 +97,11 @@ class GeneralSettingsViewModel @Inject constructor(
generalSettings.useIndirectScanResultCallback.valueBlocking = enabled
}
fun setHideUnmatchedDevices(enabled: Boolean) {
log(TAG, INFO) { "setHideUnmatchedDevices($enabled)" }
generalSettings.hideUnmatchedDevices.valueBlocking = enabled
}
fun setThemeMode(mode: ThemeMode) = launch {
log(TAG, INFO) { "setThemeMode($mode)" }
if (isPro.first()) {
@@ -26,8 +26,14 @@ class MonitorModeResolver @Inject constructor(
profilesRepo.profiles,
nudgeCapabilityStore.availability,
) { profiles, nudge ->
val primary = profiles.firstOrNull() ?: return@combine MonitorMode.MANUAL
primary.requiredMode(nudge)
// The mode is driven by the first *addressed* profile, not just the first profile. An
// address-less profile can neither host an AAP session (AapAutoConnect requires an address)
// nor auto-connect, so it can only ever resolve to MANUAL. Letting such a profile sit at the
// top of the list and force MANUAL would silently stop the foreground service that keeps the
// process — and thus background AAP/stem controls — alive for an addressed profile below it.
// No addressed profile at all => genuinely nothing to monitor => MANUAL.
profiles.firstOrNull { !it.address.isNullOrBlank() }?.requiredMode(nudge)
?: MonitorMode.MANUAL
}
.distinctUntilChanged()
.onEach { log(TAG, VERBOSE) { "effectiveMode = $it" } }
@@ -267,6 +267,14 @@ data class PodDevice(
val isEitherPodInEar: Boolean?
get() = aap?.isEitherPodInEar ?: (ble as? HasEarDetectionDual)?.isEitherPodInEar
/**
* True when ear detection comes from a live AAP reading. The BLE ear-detection bits are
* unreliable for pods resting in the case (they report phantom "in ear" and disagree
* between the two pods' advertisements), so consumers that must not act on a false "worn"
* gate on this.
*/
val hasAapEarDetection: Boolean get() = aap?.aapEarDetection != null
val caseLidState: DualApplePods.LidState?
get() = (ble as? DualApplePods)?.caseLidState
@@ -9,20 +9,22 @@ import eu.darken.capod.common.flow.setupCommonEventHandlers
import eu.darken.capod.monitor.core.ble.BlePodMonitor
import eu.darken.capod.pods.core.apple.PodModel
import eu.darken.capod.pods.core.apple.aap.AapConnectionManager
import eu.darken.capod.pods.core.apple.aap.AapDisconnectEvent
import eu.darken.capod.pods.core.apple.aap.AapPodState
import eu.darken.capod.profiles.core.AppleDeviceProfile
import eu.darken.capod.profiles.core.DeviceProfilesRepo
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.seconds
@@ -37,6 +39,21 @@ class AapAutoConnect @Inject constructor(
private val activeReconnects = java.util.Collections.synchronizedSet(mutableSetOf<String>())
private val processedModelCorrections = java.util.Collections.synchronizedSet(mutableSetOf<String>())
/**
* Per-address count of consecutive connection attempts that never reached READY (failed socket
* connects and handshake-timeout disconnects). Drives the escalating reconnect cooldown so a
* device that keeps stalling its handshake in a crowded RF environment doesn't churn a tight
* reconnect loop. Reset to 0 once a session works (a was-ready disconnect) or the device leaves.
*/
private val preReadyFailures = ConcurrentHashMap<String, Int>()
/** Cooldown (ms) to wait before the next attempt, given how many consecutive pre-READY failures we've seen. */
private fun cooldownFor(address: String): Long {
val failures = preReadyFailures[address] ?: 0
if (failures <= 0) return 0L
return HANDSHAKE_BACKOFF[minOf(failures - 1, HANDSHAKE_BACKOFF.lastIndex)]
}
fun monitor(): Flow<Unit> = merge(
initialConnect(),
reconnectOnDisconnect(),
@@ -74,104 +91,150 @@ class AapAutoConnect @Inject constructor(
return
}
// Escalating cooldown carried over from prior failed attempts (socket failures or handshake
// stalls). 0 on the first attempt so a healthy device connects without delay.
val cooldown = cooldownFor(address)
if (cooldown > 0) {
log(TAG) { "AAP initial connect cooldown ${cooldown}ms for $address (failures=${preReadyFailures[address]})" }
delay(cooldown)
}
log(TAG) { "AAP connecting to $address (${profile.label})" }
try {
aapManager.connect(address, bonded.internal!!, profile.model)
log(TAG) { "AAP connected to $address" }
return
} catch (e: Exception) {
log(TAG, WARN) { "AAP initial connect failed for $address: ${e.message}" }
for ((attempt, delayMs) in RETRY_DELAYS.withIndex()) {
delay(delayMs)
// Bail out if classic BT disconnected
// Bail out if classic BT disconnected — device left, clear the penalty
val currentConnected = bluetoothManager.connectedDevices.first().map { it.address }.toSet()
if (address !in currentConnected) {
log(TAG) { "AAP initial retry: $address no longer classically connected, stopping" }
break
preReadyFailures.remove(address)
return
}
val retryState = aapManager.allStates.value[address]
if (retryState != null && retryState.connectionState != AapPodState.ConnectionState.DISCONNECTED) {
log(TAG) { "AAP initial retry: $address already reconnected, stopping" }
break
return
}
try {
log(TAG) { "AAP initial retry ${attempt + 1} for $address after ${delayMs}ms" }
aapManager.connect(address, bonded.internal!!, profile.model)
log(TAG) { "AAP connected to $address on retry ${attempt + 1}" }
break
return
} catch (retryException: Exception) {
log(TAG, WARN) { "AAP initial retry ${attempt + 1} failed for $address: ${retryException.message}" }
}
}
// Every attempt this episode failed at the socket level — escalate the next round's cooldown.
preReadyFailures.merge(address, 1, Int::plus)
}
}
private fun reconnectOnDisconnect(): Flow<Unit> = aapManager.disconnectEvents
.onEach { address ->
if (!activeReconnects.add(address)) {
log(TAG, VERBOSE) { "AAP reconnect already in progress for $address, skipping" }
return@onEach
}
try {
for ((attempt, delayMs) in RETRY_DELAYS.withIndex()) {
delay(delayMs)
// Check if still profiled
val profile = profilesRepo.profiles.first()
.firstOrNull { it.address == address }
if (profile == null) {
log(TAG) { "AAP reconnect: $address no longer profiled, stopping" }
break
}
// Check if still bonded
val bonded = bluetoothManager.bondedDevices().first()
.firstOrNull { it.address == address }
if (bonded == null) {
log(TAG) { "AAP reconnect: $address no longer bonded, stopping" }
break
}
// Check if still classically connected
val currentConnected = bluetoothManager.connectedDevices.first().map { it.address }.toSet()
if (address !in currentConnected) {
log(TAG) { "AAP reconnect: $address no longer classically connected, stopping" }
break
}
// Check if still visible in BLE
val bleDevices = blePodMonitor.devices.first()
if (bleDevices.none { it.meta?.profile?.address == address }) {
log(TAG) { "AAP reconnect: $address no longer visible in BLE, stopping" }
break
}
// Check if already reconnected (e.g., by initialConnect)
val currentState = aapManager.allStates.value[address]
if (currentState != null && currentState.connectionState != AapPodState.ConnectionState.DISCONNECTED) {
log(TAG) { "AAP reconnect: $address already reconnected" }
break
}
try {
log(TAG) { "AAP reconnect attempt ${attempt + 1} for $address in ${delayMs}ms" }
aapManager.connect(address, bonded.internal!!, profile.model)
log(TAG) { "AAP reconnected to $address" }
break
} catch (e: Exception) {
log(TAG, WARN) { "AAP reconnect attempt ${attempt + 1} failed for $address: ${e.message}" }
}
}
} finally {
activeReconnects.remove(address)
}
// Process each disconnect on its own child coroutine so a long per-address backoff never blocks
// another device's reconnect (the collector would otherwise serialise events). channelFlow gives
// us a scope to launch into; it intentionally emits nothing — it stays subscribed for its lifetime.
private fun reconnectOnDisconnect(): Flow<Unit> = channelFlow<Unit> {
aapManager.disconnectEvents.collect { event ->
launch { handleReconnect(event) }
}
.map { } // SharedFlow<BluetoothAddress> → Flow<Unit>
.setupCommonEventHandlers(TAG) { "reconnect" }
}.setupCommonEventHandlers(TAG) { "reconnect" }
private suspend fun handleReconnect(event: AapDisconnectEvent) {
val address = event.address
// A session that actually worked resets the penalty (prompt reconnect). One that never reached
// READY is a failed handshake/short session — escalate so a persistent stall backs off.
if (event.wasEverReady) {
preReadyFailures.remove(address)
} else {
preReadyFailures.merge(address, 1, Int::plus)
}
if (!activeReconnects.add(address)) {
log(TAG, VERBOSE) { "AAP reconnect already in progress for $address, skipping" }
return
}
try {
// Escalating cooldown before the normal retry cadence when handshakes keep stalling.
val cooldown = cooldownFor(address)
if (cooldown > 0) {
log(TAG) { "AAP reconnect cooldown ${cooldown}ms for $address (failures=${preReadyFailures[address]})" }
delay(cooldown)
}
for ((attempt, delayMs) in RETRY_DELAYS.withIndex()) {
delay(delayMs)
// Check if still profiled
val profile = profilesRepo.profiles.first()
.firstOrNull { it.address == address }
if (profile == null) {
log(TAG) { "AAP reconnect: $address no longer profiled, stopping" }
preReadyFailures.remove(address)
return
}
// Check if still bonded
val bonded = bluetoothManager.bondedDevices().first()
.firstOrNull { it.address == address }
if (bonded == null) {
log(TAG) { "AAP reconnect: $address no longer bonded, stopping" }
preReadyFailures.remove(address)
return
}
// Check if still classically connected
val currentConnected = bluetoothManager.connectedDevices.first().map { it.address }.toSet()
if (address !in currentConnected) {
log(TAG) { "AAP reconnect: $address no longer classically connected, stopping" }
preReadyFailures.remove(address)
return
}
// Check if still visible in BLE
val bleDevices = blePodMonitor.devices.first()
if (bleDevices.none { it.meta?.profile?.address == address }) {
log(TAG) { "AAP reconnect: $address no longer visible in BLE, stopping" }
preReadyFailures.remove(address)
return
}
// Check if already reconnected (e.g., by initialConnect)
val currentState = aapManager.allStates.value[address]
if (currentState != null && currentState.connectionState != AapPodState.ConnectionState.DISCONNECTED) {
log(TAG) { "AAP reconnect: $address already reconnected" }
return
}
try {
log(TAG) { "AAP reconnect attempt ${attempt + 1} for $address in ${delayMs}ms" }
aapManager.connect(address, bonded.internal!!, profile.model)
log(TAG) { "AAP reconnected to $address" }
return
} catch (e: Exception) {
log(TAG, WARN) { "AAP reconnect attempt ${attempt + 1} failed for $address: ${e.message}" }
}
}
// Every attempt threw at the socket level (the device is still present but won't accept a
// socket) — escalate so we don't hammer it. Mirrors connectWithRetries. Handshake stalls
// don't reach here: their reconnect socket succeeds and we return above; they escalate via
// the never-ready disconnect event instead.
preReadyFailures.merge(address, 1, Int::plus)
} finally {
activeReconnects.remove(address)
}
}
private fun correctModelOnDeviceInfo(): Flow<Unit> = aapManager.allStates
.map { states -> states.mapValues { (_, state) -> state.deviceInfo?.modelNumber } }
@@ -224,5 +287,12 @@ class AapAutoConnect @Inject constructor(
companion object {
private val TAG = logTag("Monitor", "AapAutoConnect")
internal val RETRY_DELAYS = longArrayOf(3_000, 3_000, 3_000, 5_000, 5_000, 10_000, 10_000)
/**
* Escalating cooldown (ms) applied before a reconnect/connect attempt, indexed by
* consecutive pre-READY failures minus one. Caps at 60s so a device that perpetually stalls
* its handshake in crowded RF settles into a slow ~minute cadence instead of a tight loop.
*/
internal val HANDSHAKE_BACKOFF = longArrayOf(5_000, 15_000, 30_000, 60_000)
}
}
@@ -59,6 +59,17 @@ class BlePodMonitor @Inject constructor(
private val deviceCache = mutableMapOf<BlePodSnapshot.Id, BlePodSnapshot>()
private val cacheLock = Mutex()
/**
* Drops all cached observations. The troubleshooter calls this between probe attempts so a
* previous compat combo's cached devices (kept up to [STALE_DEVICE_TIMEOUT]) can't leak into
* the next attempt and falsely satisfy it — including via [preferCaseContextPod], which would
* otherwise hand back a stale snapshot whose timestamp predates the fresh scan.
*/
suspend fun clearDeviceCache() = cacheLock.withLock {
log(TAG) { "clearDeviceCache()" }
deviceCache.clear()
}
/**
* Ephemeral override that disables the proximity-pairing scan filter so
* the troubleshooter can collect raw BLE broadcasts. Resets to false on
@@ -70,6 +81,40 @@ class BlePodMonitor @Inject constructor(
unfilteredOverride.value = enabled
}
/**
* Ephemeral override for the three BLE compatibility options. The troubleshooter uses this to
* probe combinations without writing the user's persisted settings: while set, it fully replaces
* the persisted compat values for the active scan. Resets to null on every process start; the
* troubleshooter is the only writer and always clears it when finished, so clearing it restores
* the user's original settings for free.
*/
private val compatOverride = MutableStateFlow<CompatOverride?>(null)
fun setCompatOverride(override: CompatOverride?) {
log(TAG) { "setCompatOverride($override)" }
compatOverride.value = override
}
data class CompatOverride(
val offloadedFilteringDisabled: Boolean,
val offloadedBatchingDisabled: Boolean,
val indirectCallback: Boolean,
)
/** Persisted compat settings, transparently replaced by [compatOverride] while it is set. */
private val effectiveCompat: Flow<CompatOverride> = combine(
compatOverride,
generalSettings.isOffloadedFilteringDisabled.flow,
generalSettings.isOffloadedBatchingDisabled.flow,
generalSettings.useIndirectScanResultCallback.flow,
) { override, filteringDisabled, batchingDisabled, indirectCallback ->
override ?: CompatOverride(
offloadedFilteringDisabled = filteringDisabled,
offloadedBatchingDisabled = batchingDisabled,
indirectCallback = indirectCallback,
)
}
val devices: Flow<List<BlePodSnapshot>> = combine(
permissionTool.missingScanPermissions,
bluetoothManager.isBluetoothEnabled
@@ -145,22 +190,14 @@ class BlePodMonitor @Inject constructor(
private fun createBleScanner() = combine(
bleScanModeController.scannerMode,
unfilteredOverride,
generalSettings.isOffloadedBatchingDisabled.flow,
generalSettings.isOffloadedFilteringDisabled.flow,
generalSettings.useIndirectScanResultCallback.flow,
) {
scannermode,
showUnfiltered,
isOffloadedBatchingDisabled,
isOffloadedFilteringDisabled,
useIndirectScanResultCallback,
->
effectiveCompat,
) { scannermode, showUnfiltered, compat ->
ScannerOptions(
scannerMode = scannermode,
showUnfiltered = showUnfiltered,
offloadedFilteringDisabled = isOffloadedFilteringDisabled,
offloadedBatchingDisabled = isOffloadedBatchingDisabled,
disableDirectCallback = useIndirectScanResultCallback,
offloadedFilteringDisabled = compat.offloadedFilteringDisabled,
offloadedBatchingDisabled = compat.offloadedBatchingDisabled,
disableDirectCallback = compat.indirectCallback,
)
}
.throttleLatest(1000)
@@ -43,6 +43,8 @@ import eu.darken.capod.reaction.core.autoconnect.AutoConnect
import eu.darken.capod.reaction.core.playpause.PlayPause
import eu.darken.capod.reaction.core.popup.PopUpReaction
import eu.darken.capod.reaction.core.conversation.ConversationReaction
import eu.darken.capod.reaction.core.charged.ChargedReaction
import eu.darken.capod.reaction.core.charged.ChargedReactionNotifications
import eu.darken.capod.reaction.core.sleep.SleepReaction
import eu.darken.capod.reaction.ui.popup.PopUpWindow
import kotlinx.coroutines.CancellationException
@@ -79,6 +81,8 @@ class MonitorService : Service() {
@Inject lateinit var autoConnect: AutoConnect
@Inject lateinit var popUpReaction: PopUpReaction
@Inject lateinit var sleepReaction: SleepReaction
@Inject lateinit var chargedReaction: ChargedReaction
@Inject lateinit var chargedReactionNotifications: ChargedReactionNotifications
@Inject lateinit var conversationReaction: ConversationReaction
@Inject lateinit var popUpWindow: PopUpWindow
@Inject lateinit var profilesRepo: DeviceProfilesRepo
@@ -333,6 +337,23 @@ class MonitorService : Service() {
.catch { log(TAG, WARN) { "sleepReaction failed:\n${it.asLog()}" } }
.launchIn(monitorScope)
chargedReaction.monitor()
.onEach { event ->
when (event) {
is ChargedReaction.Event.ShowNotification -> chargedReactionNotifications.show(
profileId = event.profileId,
deviceLabel = event.deviceLabel,
thresholdPercent = event.thresholdPercent,
)
is ChargedReaction.Event.CancelNotification ->
chargedReactionNotifications.cancel(event.profileId)
}
}
.setupCommonEventHandlers(TAG) { "chargedReaction" }
.catch { log(TAG, WARN) { "chargedReaction failed:\n${it.asLog()}" } }
.launchIn(monitorScope)
conversationReaction.monitor()
.setupCommonEventHandlers(TAG) { "conversationReaction" }
.catch { log(TAG, WARN) { "conversationReaction failed:\n${it.asLog()}" } }
@@ -348,6 +369,11 @@ class MonitorService : Service() {
monitorScope.cancel("Service destroyed")
if (injectionComplete) {
try {
chargedReactionNotifications.cancelAll()
} catch (e: Exception) {
log(TAG, WARN) { "Failed to cancel charged notifications: ${e.message}" }
}
val snapshot = latestNotificationSettings
if (snapshot.useExtraNotification && !snapshot.keepAfterDisconnect) {
try {
@@ -54,8 +54,8 @@ class AapConnectionManager @Inject constructor(
private val _allStates = MutableStateFlow<Map<BluetoothAddress, AapPodState>>(emptyMap())
val allStates: StateFlow<Map<BluetoothAddress, AapPodState>> = _allStates.asStateFlow()
private val _disconnectEvents = MutableSharedFlow<BluetoothAddress>(extraBufferCapacity = 16)
val disconnectEvents: SharedFlow<BluetoothAddress> = _disconnectEvents.asSharedFlow()
private val _disconnectEvents = MutableSharedFlow<AapDisconnectEvent>(extraBufferCapacity = 16)
val disconnectEvents: SharedFlow<AapDisconnectEvent> = _disconnectEvents.asSharedFlow()
/** Emits when a connection receives private keys (IRK/ENC) from the device. */
private val _keysReceived = MutableSharedFlow<Pair<BluetoothAddress, KeyExchangeResult>>(extraBufferCapacity = 16)
@@ -75,10 +75,10 @@ class AapConnectionManager @Inject constructor(
val sleepEvents: SharedFlow<BluetoothAddress> = _sleepEvents.asSharedFlow()
/**
* Emits when a connected device reports a Conversational Awareness speaking transition
* (START/STOP, AAP command 0x4B). Paired with the origin address so the conversation
* reaction can gate on the primary device. Only the known 0x01/0x04 markers reach here —
* the engine drops unknown raw values (see [AapSessionEngine]).
* Emits when a connected device reports a Conversational Awareness transition (START / RESUME /
* HOLD / STOP, AAP command 0x4B). Paired with the origin address so the conversation reaction
* can gate on the primary device. Every well-formed frame is classified and emitted (unknown
* status bytes map to HOLD); only structurally malformed frames are dropped (see [AapSessionEngine]).
*/
private val _conversationalAwarenessEvents =
MutableSharedFlow<Pair<BluetoothAddress, ConversationAwarenessEvent>>(extraBufferCapacity = 16)
@@ -188,7 +188,7 @@ class AapConnectionManager @Inject constructor(
}
if (!wasIntentional) {
_disconnectEvents.tryEmit(address)
_disconnectEvents.tryEmit(AapDisconnectEvent(address, connection.wasEverReady))
}
// End this collector coroutine (also cancels child key-forwarding coroutine)
@@ -217,3 +217,13 @@ class AapConnectionManager @Inject constructor(
connection.send(command)
}
}
/**
* Emitted on an unintentional AAP disconnect. [wasEverReady] tells the reconnect layer whether this
* session ever completed the handshake (reached READY) — a never-ready disconnect is a failed
* handshake/short session and feeds the escalating reconnect backoff; a was-ready drop reconnects promptly.
*/
data class AapDisconnectEvent(
val address: BluetoothAddress,
val wasEverReady: Boolean,
)
@@ -23,12 +23,14 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.withTimeoutOrNull
import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.time.Duration
@@ -46,10 +48,14 @@ internal class AapConnection(
private val socketFactory: L2capSocketFactory,
timeSource: TimeSource,
private val connectTimeout: Duration = DEFAULT_CONNECT_TIMEOUT,
private val handshakeTimeout: Duration = DEFAULT_HANDSHAKE_TIMEOUT,
) {
private val engine = AapSessionEngine(profile, timeSource)
/** True once this connection's session reached READY at least once. Survives the engine reset. */
val wasEverReady: Boolean get() = engine.wasEverReady
val state: StateFlow<AapPodState> get() = engine.state
val keysReceived: SharedFlow<KeyExchangeResult> get() = engine.keysReceived
val stemPressEvents: SharedFlow<StemPressEvent> get() = engine.stemPressEvents
@@ -60,6 +66,7 @@ internal class AapConnection(
private var socket: BluetoothSocket? = null
private var readerJob: Job? = null
private val disconnected = AtomicBoolean(false)
private val writeMutex = Mutex()
private val framer = AapFramer()
@@ -109,6 +116,27 @@ internal class AapConnection(
// Launch read loop in the provided scope — connect() returns immediately
readerJob = scope.launch(Dispatchers.IO) { readLoop(sock) }
// Handshake watchdog: the socket can connect and the handshake be sent, but if the peer
// never replies the engine sits in HANDSHAKING forever (blocking read, no deadline).
// Bound it: if neither READY nor DISCONNECTED is reached in time, tear the socket down so
// the reconnect path can recover. READY / an earlier DISCONNECTED end the wait with no action.
scope.launch {
val settled = withTimeoutOrNull(handshakeTimeout) {
state.first {
it.connectionState == AapPodState.ConnectionState.READY ||
it.connectionState == AapPodState.ConnectionState.DISCONNECTED
}
}
// Re-check after the timeout: READY may have landed in the boundary race between
// withTimeoutOrNull cancelling and us getting here — don't tear down a live session.
if (settled == null && state.value.connectionState != AapPodState.ConnectionState.READY) {
log(TAG, Logging.Priority.WARN) {
"Handshake timed out after $handshakeTimeout for ${device.address} — disconnecting"
}
disconnect()
}
}
} catch (e: Exception) {
log(TAG, Logging.Priority.ERROR) { "Connection failed: $e" }
cleanupSocket()
@@ -118,6 +146,9 @@ internal class AapConnection(
}
suspend fun disconnect() = withContext(Dispatchers.IO) {
// Idempotent: the handshake watchdog and the manager's DISCONNECTED observer can both reach
// here for the same dying session. Run the teardown exactly once.
if (!disconnected.compareAndSet(false, true)) return@withContext
log(TAG, Logging.Priority.INFO) { "Disconnecting" }
readerJob?.cancel()
readerJob = null
@@ -261,6 +292,13 @@ internal class AapConnection(
companion object {
private const val PSM = 0x1001
internal val DEFAULT_CONNECT_TIMEOUT = 5.seconds
/**
* Upper bound on the post-handshake wait for the first sign of life (READY). Normal
* handshakes complete in well under 2s; 10s tolerates a congested 2.4 GHz band before
* giving up so the reconnect path can recover instead of wedging in HANDSHAKING forever.
*/
internal val DEFAULT_HANDSHAKE_TIMEOUT = 10.seconds
private val TAG = logTag("AAP", "Connection")
}
}
@@ -86,6 +86,15 @@ internal class AapSessionEngine(
private var activeSendRaw: (suspend (AapCommand) -> Unit)? = null
private var runtimeState = EngineRuntimeState()
/**
* True once this session has reached [AapPodState.ConnectionState.READY] at least once.
* Deliberately NOT cleared by [reset] — consumers read it at disconnect time to tell a
* working session that dropped apart from one that never completed the handshake (drives
* the reconnect backoff). Cleared only when a fresh session starts.
*/
private var _wasEverReady: Boolean = false
val wasEverReady: Boolean get() = _wasEverReady
fun start(scope: CoroutineScope) {
dispatch(AapEngineEvent.SessionStarted(scope))
}
@@ -130,6 +139,7 @@ internal class AapSessionEngine(
when (event) {
is AapEngineEvent.SessionStarted -> {
scope = event.scope
_wasEverReady = false
runtimeState = runtimeState.copy(handshakeResponseReceived = false)
_state.value = _state.value.copy(connectionState = AapPodState.ConnectionState.CONNECTING)
}
@@ -159,11 +169,14 @@ internal class AapSessionEngine(
private fun handleConnectResponse(packet: AapPacket.ConnectResponse) {
if (packet.status != 0) {
log(TAG, ERROR) {
"ConnectResponse failed: status=0x${"%04X".format(packet.status)} " +
"ConnectResponse rejected (status=0x${"%04X".format(packet.status)}) — tearing down: " +
"major=${packet.major} minor=${packet.minor} " +
"features=0x${"%016X".format(packet.features.toLong())}"
}
_state.value = _state.value.copy(connectResponseStatus = packet.status)
// Hard protocol rejection: don't wait out the handshake watchdog — disconnect now so
// the reconnect path can recover (or back off). Nested dispatch mirrors the existing
// inbound-update re-dispatch pattern.
dispatch(AapEngineEvent.ResetRequested)
return
}
@@ -192,6 +205,7 @@ internal class AapSessionEngine(
_state.value.connectionState == AapPodState.ConnectionState.HANDSHAKING
) {
runtimeState = runtimeState.copy(handshakeResponseReceived = true)
_wasEverReady = true
_state.value = _state.value.copy(connectionState = AapPodState.ConnectionState.READY)
log(TAG) { "Connection READY" }
}
@@ -309,8 +323,8 @@ internal class AapSessionEngine(
}
// Re-emit every (well-formed) Conversational Awareness frame as a classified event for the
// conversation reaction: START / STOP / HOLD (keep-alive). The decoder already dropped
// malformed frames (rawValue stays null only in that case). The raw payload remains logged.
// conversation reaction: START / RESUME / HOLD / STOP. The decoder already dropped malformed
// frames (rawValue stays null only in that case). The raw payload remains logged.
if (value is AapSetting.ConversationalAwarenessState) {
value.rawValue?.let { _conversationalAwarenessEvents.tryEmit(ConversationAwarenessEvent.fromStatus(it)) }
}
@@ -102,10 +102,11 @@ sealed class AapSetting {
/**
* Push-only from device — reports speaking detection state (command 0x4B).
*
* [rawValue] is the first payload byte, preserved so consumers can distinguish the known
* speaking-start (0x01) and speaking-stop (0x04) markers from other values (e.g. 0x00, seen
* in captures with unclear meaning). [speaking] collapses everything non-0x01 to false for
* storage/UI; reaction logic must gate on [rawValue] to avoid acting on unknown values.
* [rawValue] is the status byte: the last byte of the 4-byte `02 00 01 XX` form (or the single
* byte of the legacy form), preserved so consumers can classify it. [speaking] is `true` while
* the wearer is talking — onset (`1`, `2`) or resumed after a pause (`5`); every other value
* (`0`, `3`, `4`, `0x0B`, …) is `false`. START/RESUME/HOLD/STOP classification for the reaction
* lives in [ConversationAwarenessEvent].
*/
data class ConversationalAwarenessState(
val speaking: Boolean,
@@ -3,27 +3,46 @@ package eu.darken.capod.pods.core.apple.aap.protocol
/**
* Classified Conversational Awareness signal derived from the status byte of a `0x4B` frame.
*
* Status-byte mapping (confirmed against a live AirPods Pro 3 capture and the librepods project):
* - `1`, `2` → [START] (wearer started / is speaking → engage the reaction)
* - `6`, `8`, `9` → [STOP] (wearer stopped → disengage)
* - any other value (`3`, `4`, `0x0B`, …) → [HOLD] (intermediate "still in session" frame; the pod
* streams these while speaking — they act as a keep-alive and must NOT disengage the reaction)
* Status-byte mapping, derived from a labelled capture set across AirPods Pro 3 and Pro 2 USB-C
* (`protocol-research/conversationalawareness/` — both models share one firmware train and emit
* byte-identical sequences). Each scenario was captured with a known action (normal talking,
* bursty talking, single-pod, volume-up abort, pod removal/case):
* - `1`, `2` → [START] (conversation onset / wind-up → engage the reaction). A conversation always
* opens `1` then `2`; re-onset only ever happens after a terminal.
* - `5` → [RESUME] (speech resumed after a pause; the wind-down was aborted, CA stays engaged). In
* bursty speech the pod cycles `3,5,3,5,…`; `5` is NEVER a terminal. Misreading `5` as a stop was
* the root cause of the premature-resume bug — see [ConversationReaction].
* - `6`, `8`, `9` → [STOP] (conversation ended → disengage). The usual terminal is the `8`→`9`
* pair; `6` is a standalone terminal seen live on Pro 2 USB-C fw `…6814`. Pod removal / case-close
* also emit `8`,`9` (sometimes with no prior `1`,`2`).
* - any other value (`3` pause, `4` / `0x0B` wind-down, `7` abort, and anything unrecognised)
* → [HOLD]: a transitional "possible/real wind-down" frame. The real wind-down runs `3→0x0B→4`
* then the `8,9` terminal; `7` precedes an aborted terminal. Unknown values are deliberately
* classified as HOLD (arm the safety fuse, never resume immediately) rather than guessed at.
*
* The pod emits no `0x4B` frames at all during silence, so [HOLD] frames ceasing is itself a
* reliable "speaking ended" signal (used as a stale-timeout fallback for a missed [STOP]).
* The pod sends NO frames during active speech — it stays engaged (and silent) for as long as it
* hears nearby voices, 20-30s+ observed. So frame-silence must NOT be read as "speaking ended".
* A HOLD means the wind-down may have begun; with only ONE pod worn the `8,9` terminal is
* deterministically dropped — the flurry ends on `4` (#608, reproduced on Pro 3 and Pro 2) — so
* [ConversationReaction] treats a HOLD as "terminal imminent" and arms a short fuse, with a long
* stale backstop for a fully-dropped flurry. A RESUME (`5`) cancels that fuse and re-arms the long
* backstop; trailing frames after a terminal are ignored once disengaged.
*/
enum class ConversationAwarenessEvent {
START,
RESUME,
HOLD,
STOP,
;
companion object {
val SPEAKING_STATUSES = setOf(1, 2)
val RESUME_STATUSES = setOf(5)
val STOPPED_STATUSES = setOf(6, 8, 9)
fun fromStatus(status: Int): ConversationAwarenessEvent = when (status) {
in SPEAKING_STATUSES -> START
in RESUME_STATUSES -> RESUME
in STOPPED_STATUSES -> STOP
else -> HOLD
}
@@ -197,8 +197,11 @@ class DefaultAapDeviceProfile(
p[3].toInt() and 0xFF
else -> return null
}
// speaking = the "started/active speaking" statuses (1,2); see ConversationAwarenessEvent.
val speaking = status in ConversationAwarenessEvent.SPEAKING_STATUSES
// speaking = the wearer is currently speaking: onset (1,2) or resumed after a pause (5).
// See ConversationAwarenessEvent. (Consumers read rawValue for full classification; this
// bool just exposes "is talking now", so a resume must count as speaking too.)
val speaking = status in ConversationAwarenessEvent.SPEAKING_STATUSES ||
status in ConversationAwarenessEvent.RESUME_STATUSES
return AapSetting.ConversationalAwarenessState::class to
AapSetting.ConversationalAwarenessState(speaking, rawValue = status)
}
@@ -4,6 +4,14 @@ import eu.darken.capod.common.bluetooth.BleScanResult
import eu.darken.capod.pods.core.apple.ble.history.KnownDevice
import eu.darken.capod.pods.core.apple.ble.protocol.ProximityMessage
import eu.darken.capod.pods.core.apple.ble.protocol.ProximityPayload
import java.time.Duration
/**
* How far back to look when recovering the lid state from a recent in-case-pod broadcast.
* Time-bounded rather than count-bounded: BLE scan batching means a fixed number of frames is not a
* stable time window, and an old reading must not be allowed to resurrect a stale OPEN/CLOSED.
*/
private val MAX_LID_RECOVERY_AGE: Duration = Duration.ofSeconds(2)
interface ApplePodsFactory {
fun isResponsible(message: ProximityMessage): Boolean
@@ -22,7 +30,8 @@ interface ApplePodsFactory {
fun KnownDevice.getLatestCaseBattery(): Float? = this.lastCaseBattery
fun KnownDevice.getLatestCaseLidState(basic: DualApplePods): DualApplePods.LidState? {
// A pod broadcasting from inside the case has authoritative case state
// A pod broadcasting from inside the case has authoritative case state. Out-of-case frames
// (one pod removed) report UNKNOWN via DualApplePods.caseLidState and are skipped here.
if (basic.hasCaseContext && basic.caseLidState in setOf(
DualApplePods.LidState.OPEN,
DualApplePods.LidState.CLOSED,
@@ -31,11 +40,14 @@ interface ApplePodsFactory {
return basic.caseLidState
}
// Current pod lacks case context (e.g. pod on desk) or reports UNKNOWN.
// Check recent history for a sibling broadcast that has case context.
val fromCaseContext = history
.takeLast(4)
// Current pod lacks case context (e.g. pod on desk) or reports UNKNOWN (out-of-case pod's
// stale lid byte). Recover the last authoritative reading from a recent in-case broadcast,
// bounded by time so a missed CLOSED can't keep a stale OPEN alive across scan gaps.
val recentHistory = history
.filterIsInstance<DualApplePods>()
.filter { Duration.between(it.seenLastAt, basic.seenLastAt).abs() <= MAX_LID_RECOVERY_AGE }
val fromCaseContext = recentHistory
.lastOrNull { it.hasCaseContext && it.caseLidState != DualApplePods.LidState.UNKNOWN }
?.caseLidState
@@ -44,10 +56,8 @@ interface ApplePodsFactory {
// No case-context broadcast in recent history — current value is best we have
if (basic.caseLidState != DualApplePods.LidState.UNKNOWN) return basic.caseLidState
// Last resort: any non-UNKNOWN from history
return history
.takeLast(2)
.filterIsInstance<DualApplePods>()
// Last resort: any non-UNKNOWN from recent history
return recentHistory
.lastOrNull { it.caseLidState != DualApplePods.LidState.UNKNOWN }
?.caseLidState
?: DualApplePods.LidState.NOT_IN_CASE
@@ -148,7 +148,14 @@ interface DualApplePods : ApplePods, HasChargeDetectionDual, DualBlePodSnapshot,
get() = isThisPodInThecase || isOnePodInCase || areBothPodsInCase
val caseLidState: LidState
get() = LidState.fromRaw(pubCaseLidState, hasCaseContext)
get() = LidState.fromRaw(
raw = pubCaseLidState,
hasCaseContext = hasCaseContext,
// The lid bit is only trustworthy from a pod broadcasting inside the case (bit 6), or
// while both pods are in the case (bit 2). A bit4-only frame comes from the out-of-case
// pod and carries a stale lid byte (see LidState.fromRaw).
lidReadingReliable = isThisPodInThecase || areBothPodsInCase,
)
/**
* TODO this is glitchy
@@ -165,8 +172,20 @@ interface DualApplePods : ApplePods, HasChargeDetectionDual, DualBlePodSnapshot,
UNKNOWN;
companion object {
fun fromRaw(raw: UByte, hasCaseContext: Boolean): LidState {
/**
* Derives the lid state from the raw lid byte.
*
* The open/closed bit is only meaningful when broadcast by a pod that is itself inside
* the case ([isThisPodInThecase]) or while both pods are in the case ([areBothPodsInCase]).
* When only one pod is in the case and the *other*, out-of-case pod is the one
* broadcasting (bit4-only), its lid byte is stale and decodes to a phantom OPEN even while
* the case is physically shut (verified on AirPods Pro 1 & Pro 3). Such frames must report
* [UNKNOWN] so they don't drive case-open reactions; consumers recover the real state from
* an in-case-pod broadcast instead.
*/
fun fromRaw(raw: UByte, hasCaseContext: Boolean, lidReadingReliable: Boolean): LidState {
if (!hasCaseContext) return NOT_IN_CASE
if (!lidReadingReliable) return UNKNOWN
return when ((raw.toInt() shr 3) and 0x01) {
0 -> OPEN
@@ -16,6 +16,12 @@ data class KnownDevice(
val seenCounter: Int,
val history: List<ApplePods>,
val lastCaseBattery: Float?,
/**
* Profile id this device has ever IRK-resolved to, or null if it has only ever been seen as a
* keyless device. Durable — kept even when [history] is trimmed — so the weak history-recovery
* paths can reliably refuse to hand an IRK-backed identity to a foreign same-model frame.
*/
val boundProfileId: String? = null,
) {
val lastPayload: ProximityPayload
get() = history.last().payload
@@ -76,7 +76,8 @@ class PodHistoryRepo @Inject constructor(
val caseIgnored = if (current is DualApplePods) {
val target = current.getCaseMatchMarkings()
knownDevices.values.filter { known ->
known.history.filterIsInstance<DualApplePods>().any { it.getCaseMatchMarkings() == target }
known.history.filterIsInstance<DualApplePods>().any { it.getCaseMatchMarkings() == target } &&
known.isIrkConsistentWith(current)
}
} else {
emptySet()
@@ -143,7 +144,7 @@ class PodHistoryRepo @Inject constructor(
if (recognizedDevice == null) {
val currentMarkers = payload.getFuzzyIdentifier()
recognizedDevice = knownDevices.values
.firstOrNull { it.lastPayload.getFuzzyIdentifier() == currentMarkers }
.firstOrNull { it.lastPayload.getFuzzyIdentifier() == currentMarkers && it.isIrkConsistentWith(current) }
?.also { log(TAG, DEBUG) { "search1: Similarity match for device=${current.model}" } }
}
@@ -154,6 +155,24 @@ class PodHistoryRepo @Inject constructor(
return recognizedDevice
}
/**
* The weak history paths (fuzzy markers, case-ignored markings) match on low-entropy broadcast
* data — model + battery nibbles + colour — which a stranger's same-model AirPods at a similar
* battery satisfies. Those paths must not let a foreign frame inherit the identity of one of OUR
* keyed (IRK-backed) devices, or the foreign snapshot poisons that device's cache slot and the
* dashboard card glitches (Symptom B).
*
* A [KnownDevice] is "IRK-backed" if it has ever resolved against a profile's IRK
* ([KnownDevice.boundProfileId], latched durably so history trimming can't erode it). Such a
* device may only be claimed via the strong address/IRK paths, or by a current frame that
* resolved to the SAME profile. Keyless devices (never IRK-backed) are unaffected — fuzzy
* recovery still works for them exactly as before.
*/
private fun KnownDevice.isIrkConsistentWith(current: ApplePods): Boolean {
val bound = boundProfileId ?: return true // not IRK-backed -> keyless, weak match allowed
return current.meta.profile?.id == bound
}
fun updateHistory(device: ApplePods) {
val existing = knownDevices[device.identifier]
@@ -162,12 +181,16 @@ class PodHistoryRepo @Inject constructor(
.mapNotNull { it.batteryCasePercent }
.lastOrNull()
// Latch the IRK-resolved profile id (never cleared by an unbound frame), so it survives history trimming.
val boundProfileId = device.meta.profile?.id?.takeIf { device.meta.isIRKMatch }
knownDevices[device.identifier] = if (existing != null) {
val history = existing.history.plus(device)
existing.copy(
seenCounter = existing.seenCounter + 1,
history = history,
lastCaseBattery = history.determineLatestCaseBattery() ?: existing.lastCaseBattery
lastCaseBattery = history.determineLatestCaseBattery() ?: existing.lastCaseBattery,
boundProfileId = boundProfileId ?: existing.boundProfileId,
)
} else {
log(TAG, DEBUG) { "Creating new history for ${device.logSummary()}" }
@@ -177,7 +200,8 @@ class PodHistoryRepo @Inject constructor(
seenFirstAt = device.seenFirstAt,
seenCounter = 1,
history = history,
lastCaseBattery = history.determineLatestCaseBattery()
lastCaseBattery = history.determineLatestCaseBattery(),
boundProfileId = boundProfileId,
)
}
}
@@ -2,7 +2,9 @@ package eu.darken.capod.pods.core.apple.ble.protocol
import android.bluetooth.le.ScanFilter
import dagger.Reusable
import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import javax.inject.Inject
@@ -16,6 +18,17 @@ object ProximityPairing {
return null
}
// Pods also emit type 0x07 frames whose payload does not use the plaintext status
// format, e.g. prefix 0x07 from the identity address on connect (#603). Their bytes
// are garbage at the standard offsets and would create a ghost device.
if (message.data.firstOrNull() != PAIRING_MESSAGE_PREFIX) {
log(TAG, DEBUG) {
val hex = message.data.joinToString(" ") { "%02X".format(it.toInt()) }
"Dropping proximity pairing message with unsupported prefix: [$hex]"
}
return null
}
return ProximityMessage(
type = message.type,
length = message.length,
@@ -49,4 +62,9 @@ object ProximityPairing {
// This is the default message length among official Apple devices, clones may have different length
internal const val PAIRING_MESSAGE_LENGTH = 25
// First payload byte of every known plaintext status broadcast, including pairing mode
internal val PAIRING_MESSAGE_PREFIX = 0x01.toUByte()
private val TAG = logTag("Pod", "Apple", "ProximityPairing")
}
@@ -5,6 +5,7 @@ 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 eu.darken.capod.reaction.core.charged.ChargedSlotScope
import eu.darken.capod.reaction.core.conversation.ConversationAction
import eu.darken.capod.reaction.core.stem.StemActionsConfig
import kotlinx.parcelize.Parcelize
@@ -34,6 +35,9 @@ data class AppleDeviceProfile(
@SerialName("reactionShowPopUpOnConnection") val showPopUpOnConnection: Boolean = false,
@SerialName("reactionConversationAction") val conversationAction: ConversationAction = ConversationAction.NOTHING,
@SerialName("reactionConversationVolumeReduction") val conversationVolumeReduction: Int = ReactionConfig.DEFAULT_CONVERSATION_VOLUME_REDUCTION,
@SerialName("reactionNotifyWhenCharged") val notifyWhenCharged: Boolean = false,
@SerialName("reactionChargedThreshold") val chargedThreshold: Int = ReactionConfig.DEFAULT_CHARGED_THRESHOLD,
@SerialName("reactionChargedSlotScope") val chargedSlotScope: ChargedSlotScope = ChargedSlotScope.PODS_AND_CASE,
/**
* Last-known device-side AllowOffOption (AAP setting 0x34). Persisted so the UI can honor
* the learned value across sessions — AAP state is dropped on disconnect, but whether OFF
@@ -61,6 +65,9 @@ data class AppleDeviceProfile(
showPopUpOnConnection = showPopUpOnConnection,
conversationAction = conversationAction,
conversationVolumeReduction = conversationVolumeReduction,
notifyWhenCharged = notifyWhenCharged,
chargedThreshold = chargedThreshold,
chargedSlotScope = chargedSlotScope,
)
override fun toString(): String = "AppleDeviceProfile(" +
@@ -76,6 +83,9 @@ data class AppleDeviceProfile(
"showPopUpOnConnection=$showPopUpOnConnection, " +
"conversationAction=$conversationAction, " +
"conversationVolumeReduction=$conversationVolumeReduction, " +
"notifyWhenCharged=$notifyWhenCharged, " +
"chargedThreshold=$chargedThreshold, " +
"chargedSlotScope=$chargedSlotScope, " +
"learnedAllowOffEnabled=$learnedAllowOffEnabled, " +
"lastRequestedListeningModeCycleMask=$lastRequestedListeningModeCycleMask, " +
"stemActions=$stemActions" +
@@ -1,6 +1,7 @@
package eu.darken.capod.profiles.core
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
import eu.darken.capod.reaction.core.charged.ChargedSlotScope
import eu.darken.capod.reaction.core.conversation.ConversationAction
data class ReactionConfig(
@@ -15,8 +16,17 @@ data class ReactionConfig(
val conversationAction: ConversationAction = ConversationAction.NOTHING,
/** Percentage to lower media volume by when [conversationAction] is LOWER_VOLUME (clamped 10..90 on use). */
val conversationVolumeReduction: Int = DEFAULT_CONVERSATION_VOLUME_REDUCTION,
val notifyWhenCharged: Boolean = false,
/** Battery percentage at which the charged notification fires (clamped 50..100 on use). */
val chargedThreshold: Int = DEFAULT_CHARGED_THRESHOLD,
val chargedSlotScope: ChargedSlotScope = ChargedSlotScope.PODS_AND_CASE,
) {
companion object {
const val DEFAULT_CHARGED_THRESHOLD = 100
const val MIN_CHARGED_THRESHOLD = 50
const val MAX_CHARGED_THRESHOLD = 100
const val CHARGED_THRESHOLD_STEP = 10
const val DEFAULT_CONVERSATION_VOLUME_REDUCTION = 50
const val MIN_CONVERSATION_VOLUME_REDUCTION = 10
@@ -39,7 +39,9 @@ class AutoConnect @Inject constructor(
combine(
bluetoothManager.connectedDevices,
deviceMonitor.primaryDevice().filterNotNull().distinctUntilChangedBy {
Triple(it.rawDataHex, it.reactions.autoConnectCondition, it.reactions.onePodMode)
// Include caseLidState: for the CASE_OPEN condition it is derived from history
// and can flip to OPEN while the selected frame's raw bytes are unchanged.
listOf(it.rawDataHex, it.reactions.autoConnectCondition, it.reactions.onePodMode, it.caseLidState)
},
) { connectedDevices, mainDevice ->
connectedDevices to mainDevice
@@ -0,0 +1,199 @@
package eu.darken.capod.reaction.core.charged
import eu.darken.capod.common.debug.logging.Logging.Priority.INFO
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.flow.setupCommonEventHandlers
import eu.darken.capod.monitor.core.DeviceMonitor
import eu.darken.capod.monitor.core.PodDevice
import eu.darken.capod.monitor.core.devicesWithProfiles
import eu.darken.capod.pods.core.apple.aap.AapPodState
import eu.darken.capod.pods.core.apple.ble.DualBlePodSnapshot
import eu.darken.capod.pods.core.apple.ble.devices.DualApplePods
import eu.darken.capod.pods.core.apple.ble.SingleBlePodSnapshot
import eu.darken.capod.pods.core.apple.ble.devices.HasCase
import eu.darken.capod.pods.core.apple.ble.devices.HasChargeDetection
import eu.darken.capod.pods.core.apple.ble.devices.HasChargeDetectionDual
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.reaction.core.charged.ChargingSessionStateMachine.Input
import eu.darken.capod.reaction.core.charged.ChargingSessionStateMachine.Output
import eu.darken.capod.reaction.core.charged.ChargingSessionStateMachine.Slot
import eu.darken.capod.reaction.core.charged.ChargingSessionStateMachine.SlotData
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ChargedReaction @Inject constructor(
private val deviceMonitor: DeviceMonitor,
private val profilesRepo: DeviceProfilesRepo,
) {
sealed class Event {
data class ShowNotification(
val profileId: String,
val deviceLabel: String,
val thresholdPercent: Int,
) : Event()
data class CancelNotification(val profileId: String) : Event()
}
private data class ChargedConfig(val scope: ChargedSlotScope, val thresholdPercent: Int)
fun monitor(): Flow<Event> = flow {
// Machines live in the collection scope: a monitor (service) restart starts fresh sessions.
val machines = mutableMapOf<String, ChargingSessionStateMachine>()
val configs = mutableMapOf<String, ChargedConfig>()
combine(
profilesRepo.profiles,
deviceMonitor.devicesWithProfiles(),
) { profiles, devices -> profiles.filterIsInstance<AppleDeviceProfile>() to devices }
.collect { (profiles, devices) ->
val enabled = profiles.filter { it.notifyWhenCharged }.associateBy { it.id }
// Profile deleted or toggle disabled → reset; a missing device snapshot is
// handled below as staleness, never as a reset.
machines.keys.filter { it !in enabled }.forEach { profileId ->
val output = machines.remove(profileId)!!.process(Input.Reset)
configs.remove(profileId)
if (output == Output.CANCEL) emit(Event.CancelNotification(profileId))
}
for (profile in enabled.values) {
val machine = machines.getOrPut(profile.id) { ChargingSessionStateMachine() }
val thresholdPercent = profile.chargedThreshold.coerceIn(
ReactionConfig.MIN_CHARGED_THRESHOLD,
ReactionConfig.MAX_CHARGED_THRESHOLD,
)
// A persisted CASE scope on a caseless model (restored backup, model change)
// would otherwise produce an eternally-empty slot set.
val scope = if (profile.model.features.hasCase) profile.chargedSlotScope else ChargedSlotScope.PODS
val config = ChargedConfig(scope, thresholdPercent)
val previousConfig = configs.put(profile.id, config)
if (previousConfig != null && previousConfig != config) {
// Scope/threshold changed: stale highwater slots and an already-shown
// notification don't fit the new settings — start evaluation over.
log(TAG, INFO) { "Settings changed for ${profile.id} ($previousConfig -> $config), resetting" }
if (machine.process(Input.Reset) == Output.CANCEL) {
emit(Event.CancelNotification(profile.id))
}
}
val device = devices.firstOrNull { it.profileId == profile.id }
val slots = device?.liveChargingSlots(scope).orEmpty()
// No live slot data (device gone, lid closed, or AAP hasn't pushed battery
// yet) is treated as staleness — the session suspends instead of resetting.
val input = if (device == null || slots.isEmpty()) {
Input.StaleUpdate
} else {
Input.LiveUpdate(
slots = slots,
threshold = thresholdPercent / 100f,
activity = device.chargingActivity(),
)
}
val phaseBefore = machine.phase
val output = machine.process(input)
if (machine.phase != phaseBefore) {
log(TAG, VERBOSE) {
"${profile.id}: $phaseBefore -> ${machine.phase} (output=$output, input=$input)"
}
}
when (output) {
Output.SHOW -> {
val label = device?.label ?: profile.label
log(TAG, INFO) { "Charge complete for ${profile.id} ($label) at $thresholdPercent%" }
emit(Event.ShowNotification(profile.id, label, thresholdPercent))
}
Output.CANCEL -> {
log(TAG, INFO) { "Charging session over for ${profile.id}, cancelling notification" }
emit(Event.CancelNotification(profile.id))
}
Output.NONE -> Unit
}
}
}
}
.setupCommonEventHandlers(TAG) { "chargedReaction" }
companion object {
private val TAG = logTag("Reaction", "Charged")
}
}
/**
* Per-slot live readings only — AAP first, then live BLE. The [PodDevice] facade getters are
* deliberately bypassed because they silently fall back to the disk cache; stale cached values
* must never start, complete, or end a charging session.
*/
/**
* Signals that the user is handling the device, used to dismiss an already-shown notification.
* All sources are live (ear detection: AAP/BLE; lid: BLE; DISCONNECTED slots: AAP) — the cache
* never feeds in here.
*/
internal fun PodDevice.chargingActivity(): ChargingSessionStateMachine.Activity =
ChargingSessionStateMachine.Activity(
// Only trust AAP ear detection — BLE ear bits are phantom for in-case pods (see
// PodDevice.hasAapEarDetection). Unknown when there's no AAP session, which is the
// normal state while charging in the case, so phantom "worn" never dismisses.
wornSlots = when {
!hasAapEarDetection -> null
hasDualPods -> buildSet {
if (isLeftInEar == true) add(Slot.LEFT)
if (isRightInEar == true) add(Slot.RIGHT)
}
else -> if (isBeingWorn == true) setOf(Slot.HEADSET) else emptySet()
},
lid = when (caseLidState) {
DualApplePods.LidState.OPEN -> ChargingSessionStateMachine.Lid.OPEN
DualApplePods.LidState.CLOSED -> ChargingSessionStateMachine.Lid.CLOSED
DualApplePods.LidState.NOT_IN_CASE -> ChargingSessionStateMachine.Lid.NOT_IN_CASE
else -> null
},
disconnectedSlots = buildSet {
if (leftPodChargingState == AapPodState.ChargingState.DISCONNECTED) add(Slot.LEFT)
if (rightPodChargingState == AapPodState.ChargingState.DISCONNECTED) add(Slot.RIGHT)
if (caseChargingState == AapPodState.ChargingState.DISCONNECTED) add(Slot.CASE)
if (headsetChargingState == AapPodState.ChargingState.DISCONNECTED) add(Slot.HEADSET)
},
)
internal fun PodDevice.liveChargingSlots(scope: ChargedSlotScope): Map<Slot, SlotData> {
val slots = mutableMapOf<Slot, SlotData>()
fun add(slot: Slot, battery: Float?, charging: Boolean?) {
if (battery == null || battery < 0f || charging == null) return
slots[slot] = SlotData(battery = battery, isCharging = charging)
}
if (scope != ChargedSlotScope.CASE) {
add(
Slot.LEFT,
aap?.batteryLeft ?: (ble as? DualBlePodSnapshot)?.batteryLeftPodPercent,
aap?.isLeftCharging ?: (ble as? HasChargeDetectionDual)?.isLeftPodCharging,
)
add(
Slot.RIGHT,
aap?.batteryRight ?: (ble as? DualBlePodSnapshot)?.batteryRightPodPercent,
aap?.isRightCharging ?: (ble as? HasChargeDetectionDual)?.isRightPodCharging,
)
add(
Slot.HEADSET,
aap?.batteryHeadset ?: (ble as? SingleBlePodSnapshot)?.batteryHeadsetPercent,
aap?.isHeadsetCharging ?: (ble as? HasChargeDetection)?.isHeadsetBeingCharged,
)
}
if (scope != ChargedSlotScope.PODS) {
add(
Slot.CASE,
aap?.batteryCase ?: (ble as? HasCase)?.batteryCasePercent,
aap?.isCaseCharging ?: (ble as? HasCase)?.isCaseCharging,
)
}
return slots
}
@@ -0,0 +1,87 @@
package eu.darken.capod.reaction.core.charged
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import eu.darken.capod.R
import eu.darken.capod.common.BuildConfigWrap
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.notifications.PendingIntentCompat
import eu.darken.capod.main.ui.MainActivity
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ChargedReactionNotifications @Inject constructor(
@ApplicationContext private val context: Context,
private val notificationManager: NotificationManager,
) {
init {
notificationManager.createNotificationChannel(
NotificationChannel(
CHANNEL_ID,
context.getString(R.string.reaction_charged_channel_label),
NotificationManager.IMPORTANCE_LOW,
)
)
}
fun show(profileId: String, deviceLabel: String, thresholdPercent: Int) {
if (!notificationManager.areNotificationsEnabled()) {
log(TAG, WARN) { "Notifications disabled — charged notification suppressed" }
return
}
val openPi = PendingIntent.getActivity(
context,
PENDING_INTENT_REQUEST_CODE,
Intent(context, MainActivity::class.java),
PendingIntentCompat.FLAG_IMMUTABLE,
)
val text = if (thresholdPercent >= 100) {
context.getString(R.string.reaction_charged_notification_text_full, deviceLabel)
} else {
context.getString(R.string.reaction_charged_notification_text_partial, deviceLabel, thresholdPercent)
}
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.device_earbuds_generic_both)
.setContentTitle(context.getString(R.string.reaction_charged_notification_title))
.setContentText(text)
.setStyle(NotificationCompat.BigTextStyle().bigText(text))
.setContentIntent(openPi)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
notificationManager.notify(profileId.toTag(), NOTIFICATION_ID, notification)
}
fun cancel(profileId: String) {
notificationManager.cancel(profileId.toTag(), NOTIFICATION_ID)
}
/**
* Drops every charged notification still on screen. Used when monitoring stops — without a
* running monitor the auto-dismiss-on-unplug promise can't be kept, so don't leave them up.
*/
fun cancelAll() {
notificationManager.activeNotifications
.filter { it.id == NOTIFICATION_ID && it.tag?.startsWith(TAG_PREFIX) == true }
.forEach { notificationManager.cancel(it.tag, it.id) }
}
private fun String.toTag() = "$TAG_PREFIX$this"
companion object {
private val TAG = logTag("Reaction", "Charged", "Notifications")
private val CHANNEL_ID = "${BuildConfigWrap.APPLICATION_ID}.notification.channel.reaction.charged"
private const val NOTIFICATION_ID = 4
private const val TAG_PREFIX = "charged:"
private const val PENDING_INTENT_REQUEST_CODE = 1
}
}
@@ -0,0 +1,16 @@
package eu.darken.capod.reaction.core.charged
import androidx.annotation.StringRes
import eu.darken.capod.R
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/** Which battery slots the charged notification watches. */
@Serializable
enum class ChargedSlotScope(
@StringRes val labelRes: Int,
) {
@SerialName("charged.scope.pods") PODS(R.string.settings_charged_scope_pods_label),
@SerialName("charged.scope.case") CASE(R.string.settings_charged_scope_case_label),
@SerialName("charged.scope.podsandcase") PODS_AND_CASE(R.string.settings_charged_scope_both_label),
}
@@ -0,0 +1,287 @@
package eu.darken.capod.reaction.core.charged
/**
* Tracks one charging session for one profile and decides when the "charged" notification
* should be shown or cancelled. Pure Kotlin, no Android/DI/Flow dependencies; instances are
* driven sequentially from a single coroutine (no internal locking).
*
* A session starts when any slot reports charging and collects every slot that charges while
* the session runs. Per-slot battery highwater marks decide completion: a slot that stops
* charging at/above the threshold finished naturally (firmware flips the charging flag off at
* 100%), while a slot that stops below the threshold was genuinely unplugged and resets the
* session. Stale data suspends the session instead of resetting it — brief BLE gaps while the
* device sits on the charger must not lose progress.
*
* After firing, the notification is taken down again when the user demonstrably reacted to it:
* battery discharging below the threshold, a new charging session starting, or any activity
* signal showing the pods are being handled (worn-pod set changed, pod removed from the case,
* case lid moved). Activity is judged against baselines captured at fire time so pre-existing
* state doesn't dismiss — only a change does:
* - Worn pods and DISCONNECTED slots baseline on the firing frame. They only apply to
* sessions containing pod slots — wearing pods says nothing about a case-only charge.
* - The lid signal baselines on the UNION of values seen before the fire (this session plus
* a few frames leading into it). With one pod worn and one charging, both pods broadcast
* and the monitor's dedup alternates between their frames (OPEN from the in-case pod,
* NOT_IN_CASE from the worn pod) — a single-frame baseline would read that steady flapping
* as activity. Lid movement is a handling signal for any session, including case-only.
*
* An activity dismissal latches into [Phase.DISMISSED] so a still-full, still-charging device
* can't immediately re-fire.
*/
class ChargingSessionStateMachine {
enum class Slot { LEFT, RIGHT, CASE, HEADSET }
/** [battery] is a fraction 0..1, matching the monitor layer's battery values. */
data class SlotData(val battery: Float, val isCharging: Boolean)
/**
* Case posture from the BLE lid byte. NOT_IN_CASE isn't a lid position — it means the
* broadcasting pod is physically outside the case, which is just as much a handling
* signal as a lid movement (it's the only BLE-side trace of "pod taken out").
*/
enum class Lid { OPEN, CLOSED, NOT_IN_CASE }
/** Signals that the user is physically handling the device. All optional/unknown-safe. */
data class Activity(
/** Pods currently worn (per-side); null when no ear data at all. */
val wornSlots: Set<Slot>? = null,
val lid: Lid? = null,
/** Slots physically absent from the case (AAP ChargingState.DISCONNECTED). */
val disconnectedSlots: Set<Slot> = emptySet(),
)
sealed interface Input {
/**
* Fresh data from a live source (BLE/AAP). [slots] only contains slots with live
* readings — cached values must never be fed in here. [threshold] is a fraction 0..1.
*/
data class LiveUpdate(
val slots: Map<Slot, SlotData>,
val threshold: Float,
val activity: Activity = Activity(),
) : Input
/** Device has no live data right now (out of range, lid closed, cache-only). */
data object StaleUpdate : Input
/** Toggle disabled, settings changed, or profile deleted. */
data object Reset : Input
}
enum class Output { NONE, SHOW, CANCEL }
enum class Phase { IDLE, CHARGING, FIRED, DISMISSED, SUSPENDED }
var phase: Phase = Phase.IDLE
private set
/** Phase to resume into when live data returns; only meaningful while SUSPENDED. */
private var suspendedFrom: Phase = Phase.IDLE
/** Battery highwater per slot that joined the session. */
private val highwater = mutableMapOf<Slot, Float>()
/**
* Rolling window of the most recent lid observations across all phases. Seeds the at-fire
* baseline so the OPEN/NOT_IN_CASE alternation (worn pod broadcasts NOT_IN_CASE while the
* in-case pod broadcasts OPEN; the monitor's dedup serves them in turn) is absorbed — even
* for an instant fire right after a settings-change reset, since the window is never cleared.
*/
private val recentLids = ArrayDeque<Lid>()
// Activity baselines frozen at fire; see class docs.
private val baselineLids = mutableSetOf<Lid>()
private var baselineWorn: Set<Slot>? = null
private var baselineDisconnected: Set<Slot> = emptySet()
fun process(input: Input): Output {
if (input is Input.LiveUpdate) input.activity.lid?.let(::recordRecentLid)
return when (phase) {
Phase.IDLE -> processIdle(input)
Phase.CHARGING -> processCharging(input)
Phase.FIRED -> processFired(input)
Phase.DISMISSED -> processDismissed(input)
Phase.SUSPENDED -> processSuspended(input)
}
}
private fun processIdle(input: Input): Output {
if (input !is Input.LiveUpdate) return Output.NONE
val charging = input.slots.filterValues { it.isCharging }
if (charging.isEmpty()) return Output.NONE
highwater.clear()
charging.forEach { (slot, data) -> highwater[slot] = data.battery }
phase = Phase.CHARGING
return fireIfComplete(input)
}
private fun processCharging(input: Input): Output = when (input) {
is Input.Reset -> reset(cancel = false)
is Input.StaleUpdate -> suspend(Phase.CHARGING)
is Input.LiveUpdate -> {
// Charging slots join the session (e.g. case plugged in later); slots already in
// it advance their mark; slots absent from this update stay frozen.
input.slots.forEach { (slot, data) ->
if (data.isCharging || slot in highwater) {
highwater[slot] = maxOf(highwater[slot] ?: 0f, data.battery)
}
}
val unplugged = highwater.any { (slot, mark) ->
input.slots[slot]?.isCharging == false && mark < input.threshold
}
if (unplugged) reset(cancel = false) else fireIfComplete(input)
}
}
private fun processFired(input: Input): Output = when (input) {
is Input.Reset -> reset(cancel = true)
is Input.StaleUpdate -> suspend(Phase.FIRED)
is Input.LiveUpdate -> when {
// "All slots stopped charging" alone is NOT an unplug signal — firmware flips the
// charging flag off at 100% while still on power. Slots that never charged this
// session (e.g. an idle half-empty case) carry no signal either. The session ends
// on: a new charge context, discharge below threshold, or user activity.
isNewChargeContext(input) -> {
// Only CANCEL is reported now; the next update finds IDLE and starts (and, if
// the data already satisfies the threshold, fires) the new session.
phase = Phase.IDLE
highwater.clear()
Output.CANCEL
}
isSessionDischarged(input) -> reset(cancel = true)
isActivityDetected(input.activity) -> {
phase = Phase.DISMISSED
Output.CANCEL
}
else -> Output.NONE
}
}
/** Like FIRED, but the notification is already gone — same exits, silent. */
private fun processDismissed(input: Input): Output = when (input) {
is Input.Reset -> reset(cancel = false)
is Input.StaleUpdate -> suspend(Phase.DISMISSED)
is Input.LiveUpdate -> when {
isNewChargeContext(input) -> {
// Nothing to cancel, so unlike FIRED the new session can start right away.
phase = Phase.IDLE
highwater.clear()
processIdle(input)
}
isSessionDischarged(input) -> reset(cancel = false)
else -> Output.NONE
}
}
private fun processSuspended(input: Input): Output = when (input) {
is Input.Reset -> reset(cancel = suspendedFrom == Phase.FIRED)
is Input.StaleUpdate -> Output.NONE
is Input.LiveUpdate -> {
phase = suspendedFrom
if (phase == Phase.CHARGING && hasRegressed(input)) {
// Battery dropped well below a session mark while we were blind — the device
// was unplugged and used in the meantime. Start over with the fresh data.
phase = Phase.IDLE
highwater.clear()
processIdle(input)
} else {
process(input)
}
}
}
/** Something is charging below the threshold — a fresh charging session is beginning. */
private fun isNewChargeContext(input: Input.LiveUpdate): Boolean =
input.slots.any { it.value.isCharging && it.value.battery < input.threshold }
/** A session slot is off power and drained below the threshold — device is in use. */
private fun isSessionDischarged(input: Input.LiveUpdate): Boolean = highwater.keys.any { slot ->
input.slots[slot]?.let { !it.isCharging && it.battery < input.threshold } == true
}
private fun isActivityDetected(activity: Activity): Boolean {
// Worn pods and pod removal only speak about pod slots; a case-only session ignores them.
if (highwater.keys.any { it != Slot.CASE }) {
activity.wornSlots?.let { worn ->
when (val baseline = baselineWorn) {
// No ear data at fire time: pods can't be worn while charging in the case,
// so any worn pod is activity — only "nothing worn" is adoptable as baseline.
null -> if (worn.isNotEmpty()) return true else baselineWorn = emptySet()
else -> if (worn != baseline) return true
}
}
val newlyDisconnected = activity.disconnectedSlots.any {
it != Slot.CASE && it in highwater && it !in baselineDisconnected
}
if (newlyDisconnected) return true
}
activity.lid?.let { lid ->
if (baselineLids.isEmpty()) {
// Lid never observed pre-fire: first sighting is the baseline — it was most
// likely in that posture all along (open is the normal charging posture).
baselineLids.add(lid)
} else if (lid !in baselineLids) {
return true
}
}
return false
}
private fun hasRegressed(input: Input.LiveUpdate): Boolean = highwater.any { (slot, mark) ->
input.slots[slot]?.let { it.battery < mark - REGRESSION_TOLERANCE } == true
}
private fun recordRecentLid(lid: Lid) {
recentLids.addLast(lid)
while (recentLids.size > RECENT_LID_FRAMES) recentLids.removeFirst()
}
private fun fireIfComplete(input: Input.LiveUpdate): Output {
if (highwater.isEmpty() || highwater.any { it.value < input.threshold }) return Output.NONE
phase = Phase.FIRED
baselineLids.clear()
baselineLids += recentLids
baselineWorn = input.activity.wornSlots
baselineDisconnected = input.activity.disconnectedSlots.intersect(highwater.keys)
return Output.SHOW
}
private fun reset(cancel: Boolean): Output {
phase = Phase.IDLE
highwater.clear()
// recentLids is an ambient rolling window — intentionally kept across resets so an
// instant re-fire after a settings change still has the recent lid alternation.
baselineLids.clear()
baselineWorn = null
baselineDisconnected = emptySet()
return if (cancel) Output.CANCEL else Output.NONE
}
private fun suspend(from: Phase): Output {
suspendedFrom = from
phase = Phase.SUSPENDED
return Output.NONE
}
companion object {
/**
* Battery drop (fraction) below a slot's highwater mark that counts as a real
* regression on resume. Public BLE reports in 10% steps, so a single-step flicker
* (exactly 0.1) must not reset the session.
*/
private const val REGRESSION_TOLERANCE = 0.1f
/**
* Pre-fire lid observations kept as baseline context. At the observed 0.5-1.5s
* emission cadence this is a few seconds — enough to capture dedup alternation
* leading into an instant fire without dragging in long-stale postures.
*/
private const val RECENT_LID_FRAMES = 8
}
}
@@ -12,6 +12,8 @@ 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.aap.AapConnectionManager
import eu.darken.capod.pods.core.apple.aap.AapPodState
import eu.darken.capod.pods.core.apple.aap.protocol.AapSetting
import eu.darken.capod.pods.core.apple.aap.protocol.ConversationAwarenessEvent
import eu.darken.capod.profiles.core.ReactionConfig
import kotlinx.coroutines.CoroutineScope
@@ -30,17 +32,38 @@ import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
/**
* Reacts to Conversational Awareness speaking transitions (AAP `0x4B`) by either lowering media
* volume or pausing, per the primary device's [ReactionConfig.conversationAction], and reverts when
* speaking stops. On Android the pod firmware does not duck audio itself, so CAPod performs it.
*
* The pod streams classified frames while you talk ([ConversationAwarenessEvent.START] at onset,
* then [ConversationAwarenessEvent.HOLD] keep-alives) and an explicit [ConversationAwarenessEvent.STOP]
* when you finish; no frames at all during silence. Disengage happens on STOP, or — if a STOP is
* dropped — via a stale timeout that fires once frames stop arriving. Each frame (START or HOLD)
* resets that timer, so a long conversation stays engaged.
* Disengage is driven by the pod's explicit end-of-speech frame ([ConversationAwarenessEvent.STOP],
* status `8,9`). The pod sends NO frames during active speech — it stays engaged for as long as it
* hears nearby voices (observed: CA held engaged 21-32s with zero `0x4B` frames, indefinitely
* against ambient noise). So frame-silence must NOT be read as "speaking ended"; after a START only
* the long [STALE_TIMEOUT] backstop applies, and a link drop is handled by the owner-disconnect revert.
*
* A [ConversationAwarenessEvent.HOLD] frame (`3` pause, `0x0B`/`4` wind-down, `7` abort) is evidence
* the wind-down may have begun. The real wind-down is a short flurry `3→0x0B→4` then the `8,9`
* terminal — but the terminal is sometimes dropped entirely (single-pod wear: fw `…6589`/`…6861`
* emitted `3,0xB,4` then nothing, stranding the volume low — #608). So a HOLD frame re-arms the
* timer with the short [WIND_DOWN_TIMEOUT] fuse: if no terminal (or resume) follows, speech is
* treated as ended anyway.
*
* A [ConversationAwarenessEvent.RESUME] frame (`5`) means speech resumed after a pause — in bursty
* talking the pod cycles `3,5,3,5,…` while CA stays engaged. It is NOT a terminal: it cancels any
* armed wind-down fuse and re-arms the long backstop, so media stays paused/ducked through the whole
* conversation. (Treating `5` as a stop was the premature-resume + stuck bug.)
*
* Removing/inserting a pod makes the firmware re-key CA — it emits a terminal then a fresh onset
* around the physical change even though the conversation continues. A terminal arriving within
* [EAR_TRANSITION_WINDOW] of an AAP ear-detection change is therefore treated as a re-key artifact:
* it defers to the wind-down fuse instead of disengaging, so a brief pod removal mid-conversation
* neither strands a pause nor causes a duck→restore→re-duck volume blip.
*
* State is a single global slot (media volume / playback is system-wide, not per-device) guarded by
* a [Mutex] — events, AAP-state-removal, the stale timer, and monitor completion all mutate it.
@@ -68,16 +91,42 @@ class ConversationReaction @Inject constructor(
val at: Long,
)
/** What the single pending [disengageJob] is currently waiting for. */
private enum class TimerPhase {
/** Long backstop while only START/RESUME seen — inferred end if it fires. */
STALE_BACKSTOP,
/** Short fuse armed by a wind-down HOLD — terminal imminent (or dropped, #608). */
WIND_DOWN_FUSE,
/** Brief wait on an uncorroborated cold terminal to see if a pod-removal ear change follows. */
STOP_SETTLE,
}
private val mutex = Mutex()
private var active: Active? = null
private var staleJob: Job? = null
private var disengageJob: Job? = null
private var timerPhase: TimerPhase? = null
// Bumped on every (re)arm. A timer job captures its generation and only acts if still current —
// guards against a stale job that already passed its delay (so cancel() no longer stops it) being
// re-armed to the SAME phase while it blocks on the mutex. This is a runtime concurrency guard: the
// single-threaded virtual-time test harness serializes the timer callback and event handlers, so a
// re-arm there always cancels the prior job before it runs — the race is not reproducible in a unit
// test (a test would exercise cancel(), not this check). Left deliberately uncovered, not an oversight.
private var timerGeneration = 0L
private var idCounter = 0L
// Per-owner AAP ear-detection tracking, so a CA terminal that lands right after a pod
// removal/insertion can be recognised as a re-key artifact rather than a real conversation end.
private val lastEarDetection = mutableMapOf<BluetoothAddress, AapSetting.EarDetection?>()
private val earTransitionAt = mutableMapOf<BluetoothAddress, Long>()
fun monitor(): Flow<Unit> = merge(
aapManager.conversationalAwarenessEvents.onEach { (address, event) -> onEvent(address, event) },
// Reverts a stranded duck when the owning device leaves the AAP state map for any reason
// (intentional or not) — disconnectEvents only fires for unintentional drops.
aapManager.allStates.onEach { states -> onActiveDevicesChanged(states.keys) },
// Tracks ear-detection transitions (for terminal-artifact suppression) and reverts a stranded
// duck when the owning device leaves the AAP state map for any reason (intentional or not) —
// disconnectEvents only fires for unintentional drops.
aapManager.allStates.onEach { states -> onStatesUpdated(states) },
)
.map { }
// Service stop / scope cancellation: undo any active duck so we don't leave volume lowered.
@@ -86,6 +135,7 @@ class ConversationReaction @Inject constructor(
private suspend fun onEvent(address: BluetoothAddress, event: ConversationAwarenessEvent) = when (event) {
ConversationAwarenessEvent.START -> onSpeakingStart(address)
ConversationAwarenessEvent.RESUME -> onSpeakingResume(address)
ConversationAwarenessEvent.HOLD -> onSpeakingHold(address)
ConversationAwarenessEvent.STOP -> onSpeakingStop(address)
}
@@ -103,12 +153,17 @@ class ConversationReaction @Inject constructor(
val current = active
if (current != null && current.owner == address) {
// Duplicate START for the same speaker — don't re-act, just keep the session alive.
restartStaleTimer(current)
// A START also cancels a pending wind-down fuse / settle: the wearer is speaking again.
armTimer(current, TimerPhase.STALE_BACKSTOP)
log(TAG) { "START from $address — already active ($action), keep-alive" }
return
}
// A different device started speaking while we were active — undo the old one first.
if (current != null) revert(current, "superseded by $address")
// A different device started speaking while we were active — undo the old one first and
// cancel its pending timer (the no-op engage paths below would otherwise leak it).
if (current != null) {
revert(current, "superseded by $address")
clearActive()
}
when (action) {
ConversationAction.PAUSE -> {
@@ -116,7 +171,7 @@ class ConversationReaction @Inject constructor(
if (paused) {
val record = Active(nextId(), address, Kind.Paused, timeSource.elapsedRealtime())
active = record
restartStaleTimer(record)
armTimer(record, TimerPhase.STALE_BACKSTOP)
log(TAG, INFO) { "START on $address → paused media" }
} else {
active = null
@@ -139,7 +194,7 @@ class ConversationReaction @Inject constructor(
timeSource.elapsedRealtime(),
)
active = record
restartStaleTimer(record)
armTimer(record, TimerPhase.STALE_BACKSTOP)
log(TAG, INFO) { "START on $address → ducked volume ${duck.priorVolume}${duck.appliedVolume}" }
} else {
active = null
@@ -152,11 +207,30 @@ class ConversationReaction @Inject constructor(
}
}
/** Intermediate keep-alive frame: the wearer is still speaking — refresh the stale timer. */
/**
* Speech resumed (status `5`) after a pause — the wind-down was aborted, the wearer is talking
* again. Cancel any armed wind-down fuse and re-arm the long [STALE_TIMEOUT] backstop, exactly
* like a duplicate-START keep-alive, so media stays paused/ducked through the conversation. Does
* NOT engage from scratch: a RESUME with no active session is ignored (a conversation always
* opens with a START, and a stray `5` should never start a pause/duck on its own).
*/
private suspend fun onSpeakingResume(address: BluetoothAddress) = mutex.withLock {
val current = active ?: return
if (current.owner != address) return
armTimer(current, TimerPhase.STALE_BACKSTOP)
log(TAG) { "RESUME from $address — speech resumed, keep-alive" }
}
/**
* Transitional wind-down frame (`3` pause, `0x0B`/`4` wind-down, `7` abort). The pod is silent
* during active speech, so this frame means the wind-down may have begun and a terminal frame is
* imminent — but firmware sometimes drops it (#608, single-pod wear). Arm the short fuse: if no
* terminal (or a fresh START / RESUME) follows, disengage anyway.
*/
private suspend fun onSpeakingHold(address: BluetoothAddress) = mutex.withLock {
val current = active ?: return
if (current.owner != address) return
restartStaleTimer(current)
armTimer(current, TimerPhase.WIND_DOWN_FUSE)
}
private suspend fun onSpeakingStop(address: BluetoothAddress) {
@@ -167,13 +241,42 @@ class ConversationReaction @Inject constructor(
log(TAG) { "STOP from $address ignored — owner is ${current.owner}" }
return
}
clearActive()
disengage(current, primary, "STOP on $address")
// The 0x06 ear-detection frame may have arrived but not yet been processed by the
// allStates collector — fold the latest snapshot in before deciding (in-app ordering race).
refreshEarTransition(address)
// Pulling/inserting a pod makes the firmware re-key CA — a terminal (8,9) then a fresh
// onset (1,2) around the physical change, even though the conversation continues.
when {
// Ear change already seen → re-key artifact. Defer to the fuse; a re-onset cancels it.
isRecentEarTransition(address) -> {
armTimer(current, TimerPhase.WIND_DOWN_FUSE)
log(TAG) { "STOP from $address during ear transition — deferring to fuse" }
}
// Corroborated by a preceding wind-down (3,0xB,4 / abort 7): a real end → resume now.
timerPhase == TimerPhase.WIND_DOWN_FUSE -> {
clearActive()
disengage(current, primary, "STOP on $address", applyAgeGuard = false)
}
// Cold terminal with no wind-down and no ear change yet. On primary-pod removal the
// firmware sends the terminal tens of ms BEFORE the ear-detection frame (measured ~30ms
// on Pro 3), so wait a short settle to see if an ear change lands before treating it as
// a real end.
else -> {
armTimer(current, TimerPhase.STOP_SETTLE)
log(TAG) { "STOP from $address — uncorroborated, settling" }
}
}
}
}
/** Graceful disengage (STOP event or stale timeout). Must be called under [mutex]. */
private suspend fun disengage(record: Active, primary: PodDevice?, reason: String) {
/**
* Graceful disengage (STOP event or timer expiry). Must be called under [mutex]. [applyAgeGuard]
* gates resume on [PAUSE_RESUME_WINDOW]: `true` only for the inferred stale-backstop end (we lost
* track and timed out — surprise-resuming long after is worse than a stranded pause); `false` for
* an explicit terminal or the wind-down fuse, where a recent/real end signal makes resume correct.
*/
private suspend fun disengage(record: Active, primary: PodDevice?, reason: String, applyAgeGuard: Boolean) {
when (val kind = record.kind) {
is Kind.Paused -> {
// Resume the pause WE caused, regardless of the current action setting. Gating on
@@ -182,11 +285,11 @@ class ConversationReaction @Inject constructor(
// surprising behaviour. The remaining guards are about real device/playback state.
val age = timeSource.elapsedRealtime() - record.at
when {
age > PAUSE_RESUME_WINDOW_MS ->
applyAgeGuard && age.milliseconds > PAUSE_RESUME_WINDOW ->
log(TAG) { "$reason — resume skipped (stale, ${age}ms)" }
primary?.address != record.owner ->
log(TAG) { "$reason — resume skipped (primary switched)" }
primary.isBeingWorn == false ->
wornForResume(primary) == false ->
log(TAG) { "$reason — resume skipped (not worn)" }
mediaControl.isPlaying ->
log(TAG) { "$reason — resume skipped (already playing)" }
@@ -201,14 +304,35 @@ class ConversationReaction @Inject constructor(
}
}
private suspend fun onActiveDevicesChanged(addresses: Set<BluetoothAddress>) = mutex.withLock {
private suspend fun onStatesUpdated(states: Map<BluetoothAddress, AapPodState>) = mutex.withLock {
// Record when each device's AAP ear-detection last changed (pod removed/inserted/cased).
for ((address, state) in states) recordEarIfChanged(address, state.aapEarDetection)
lastEarDetection.keys.retainAll(states.keys)
earTransitionAt.keys.retainAll(states.keys)
val current = active ?: return
if (current.owner !in addresses) {
if (current.owner !in states.keys) {
clearActive()
revert(current, "owner ${current.owner} gone")
}
}
/**
* Must be called under [mutex]. Notes an AAP ear-detection transition for [address]. The very
* first observation of a device only seeds the baseline — it is not counted as a transition.
*/
private fun recordEarIfChanged(address: BluetoothAddress, ear: AapSetting.EarDetection?) {
if (lastEarDetection.containsKey(address) && lastEarDetection[address] != ear) {
earTransitionAt[address] = timeSource.elapsedRealtime()
}
lastEarDetection[address] = ear
}
/** Must be called under [mutex]. Folds the latest allStates snapshot in for [address]. */
private fun refreshEarTransition(address: BluetoothAddress) {
recordEarIfChanged(address, aapManager.allStates.value[address]?.aapEarDetection)
}
private suspend fun onMonitorCompleted() = mutex.withLock {
val current = active ?: return
clearActive()
@@ -234,48 +358,133 @@ class ConversationReaction @Inject constructor(
mediaControl.restoreMusicVolume(kind.priorVolume)
}
/** Must be called under [mutex]. Clears the active slot and cancels its stale timer. */
/** Must be called under [mutex]. Clears the active slot and cancels its pending timer. */
private fun clearActive() {
staleJob?.cancel()
staleJob = null
disengageJob?.cancel()
disengageJob = null
timerPhase = null
active = null
}
/**
* Must be called under [mutex]. (Re)starts the stale timer for [record]. Reset on every frame
* (START/HOLD); if no frame arrives for [STALE_TIMEOUT_MS] the speaking session is treated as
* ended (recovers from a dropped STOP). Identity-checked so a late timer can't disengage a newer
* session.
* Must be called under [mutex]. (Re)arms the single disengage timer for [record] in [phase],
* replacing whatever was pending. On expiry [onTimerExpired] decides per phase. Guarded on both
* [Active.id] and [phase] so a late timer can't act on a newer session or a re-armed phase.
*/
private fun restartStaleTimer(record: Active) {
staleJob?.cancel()
staleJob = appScope.launch {
delay(STALE_TIMEOUT_MS)
private fun armTimer(record: Active, phase: TimerPhase) {
disengageJob?.cancel()
timerPhase = phase
val generation = ++timerGeneration
val timeout = when (phase) {
TimerPhase.STALE_BACKSTOP -> STALE_TIMEOUT
TimerPhase.WIND_DOWN_FUSE -> WIND_DOWN_TIMEOUT
TimerPhase.STOP_SETTLE -> STOP_SETTLE_DELAY
}
disengageJob = appScope.launch {
delay(timeout)
val primary = deviceMonitor.primaryDevice().first()
mutex.withLock {
if (active?.id == record.id) {
val current = active!!
clearActive()
disengage(current, primary, "stale timeout (frames ceased)")
}
// generation guards against a stale job re-armed to the same phase for the same record.
if (active?.id == record.id && timerGeneration == generation) onTimerExpired(record, phase, primary)
}
}
}
/**
* Must be called under [mutex] from inside the firing timer job. Detaches the slot WITHOUT
* cancelling (we ARE that job — self-cancel could abort a following suspension), then acts:
* - STOP_SETTLE + an ear change appeared meanwhile → re-key artifact, hand off to the fuse.
* - otherwise force-end the session. The age guard applies only to the inferred STALE backstop;
* the wind-down fuse and a settled cold terminal carry real/recent end evidence → resume regardless.
*/
private suspend fun onTimerExpired(record: Active, phase: TimerPhase, primary: PodDevice?) {
disengageJob = null
timerPhase = null
if (phase == TimerPhase.STOP_SETTLE && isRecentEarTransition(record.owner)) {
armTimer(record, TimerPhase.WIND_DOWN_FUSE)
log(TAG) { "STOP settle elapsed for ${record.owner} — ear transition appeared, deferring to fuse" }
return
}
active = null
val reason = when (phase) {
TimerPhase.STALE_BACKSTOP -> "no terminal within backstop"
TimerPhase.WIND_DOWN_FUSE -> "no terminal within wind-down fuse"
TimerPhase.STOP_SETTLE -> "cold terminal settled"
}
disengage(record, primary, reason, applyAgeGuard = phase == TimerPhase.STALE_BACKSTOP)
}
/**
* Whether the pod is worn enough to resume into, honoring One-Pod Mode (mirrors
* [eu.darken.capod.reaction.core.autoconnect.AutoConnect]): with One-Pod Mode on, a single pod
* in ear counts as worn, falling back to the both-pods reading only when the single-pod signal is
* unknown. Returns `null` when ear state is genuinely unknown — the caller treats only an explicit
* `false` as not-worn, so an unknown stays lenient (resumes).
*/
private fun wornForResume(device: PodDevice): Boolean? =
if (device.reactions.onePodMode) device.isEitherPodInEar ?: device.isBeingWorn
else device.isBeingWorn
/** Must be called under [mutex]. True if [address] had an AAP ear-detection change very recently. */
private fun isRecentEarTransition(address: BluetoothAddress): Boolean {
val at = earTransitionAt[address] ?: return false
return (timeSource.elapsedRealtime() - at).milliseconds <= EAR_TRANSITION_WINDOW
}
private fun nextId(): Long = ++idCounter
companion object {
private val TAG = logTag("Reaction", "Conversation")
/**
* Disengage if no `0x4B` frame arrives for this long while engaged. The pod streams frames
* (~1/s) throughout active speech and none during silence, so this both recovers a dropped
* STOP and bounds how long a duck can linger. Long enough not to disengage mid-conversation
* between frames.
* Backstop fuse while engaged with no wind-down evidence yet (START/RESUME frames seen).
* Must stay LONG: the pod sends zero frames during active speech and stays engaged against
* ambient noise, so a short timeout here resumes media mid-conversation (the original 12s
* value did exactly that). Only recovers a session whose entire wind-down flurry was lost
* while the link stays up. Kept longer than [PAUSE_RESUME_WINDOW] so a back-stopped pause
* is never auto-resumed (only a duck is restored — a stranded low volume is the worse
* failure).
*/
private const val STALE_TIMEOUT_MS = 12L * 1000L
private val STALE_TIMEOUT = 5.minutes
/** A disengage older than this no longer auto-resumes a pause — unexpected late playback is worse. */
private const val PAUSE_RESUME_WINDOW_MS = 2L * 60L * 1000L
/**
* Short fuse armed by a transitional [ConversationAwarenessEvent.HOLD] frame: the wind-down
* has begun, so a terminal frame should follow within seconds. With only one pod worn the
* pod deterministically drops the terminal (#608, reproduced on Pro 3 and Pro 2) — this
* fuse disengages instead of stranding the volume low for [STALE_TIMEOUT]. Must be ≥ ~5s:
* gaps up to 2.8s were observed between consecutive wind-down frames, and each HOLD re-arms
* this fuse. A fresh START or RESUME (`5`, speech resumed) re-arms the long fuse instead.
*/
private val WIND_DOWN_TIMEOUT = 6.seconds
/**
* For an *inferred* end only (the [STALE_TIMEOUT] backstop fired — we lost track of the
* conversation), a pause older than this no longer auto-resumes: surprise playback long after
* is worse than a stranded pause. An explicit terminal frame, or the short wind-down fuse,
* resumes regardless of age — those carry real/recent evidence the conversation just ended.
*/
private val PAUSE_RESUME_WINDOW = 2.minutes
/**
* A CA terminal landing within this window of an AAP ear-detection change is treated as a pod
* removal/insertion re-key artifact (firmware emits 8,9 then 1,2 around the physical change),
* not a real end. The artifact terminal and the ear change land within tens of ms of each other
* (measured ~30ms on Pro 3, either side depending on which pod); a real end is seconds away.
* Kept well under that gap so genuine terminals aren't deferred to the fuse. (The ear-detection
* 0x06 frames are emitted on removal even when the EarDetectionEnabled setting is off, so this
* suppression does not depend on that setting being enabled.)
*/
private val EAR_TRANSITION_WINDOW = 2.seconds
/**
* How long to wait on an *uncorroborated cold* terminal (no preceding wind-down HOLD, no ear
* change yet) before treating it as a real end. Covers the reverse frame-ordering on
* primary-pod removal, where the firmware sends the terminal tens of ms BEFORE the ear-detection
* frame (measured ~30ms on Pro 3) — too early for the backward-looking check. Only cold
* terminals settle; a normal end
* (`…3,0xB,4,8`) and an abort (`7,8`) are already corroborated by the fuse and resume instantly,
* so this adds no latency to genuine conversation ends.
*/
private val STOP_SETTLE_DELAY = 250.milliseconds
}
}
@@ -13,9 +13,12 @@ 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 kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import java.time.Duration
@@ -34,8 +37,12 @@ class PopUpReaction @Inject constructor(
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)
// Re-emit on profile changes (eligibility), raw BLE changes (content), AND the derived
// lid state. The latter is essential: caseLidState is recovered from history, so it can
// flip OPEN<->CLOSED while the *selected* frame's raw bytes stay identical (e.g. a steady
// out-of-case frame while a sibling in-case frame updates). Keying on rawDataHex alone
// would swallow that transition and the popup would miss its show/hide.
listOf(it?.profileId, it?.reactions?.showPopUpOnCaseOpen, it?.rawDataHex, it?.caseLidState)
}
.withPrevious()
.setupCommonEventHandlers(TAG) { "popUpCase" }
@@ -71,7 +78,7 @@ class PopUpReaction @Inject constructor(
throttleCasePopUps(current)
}
private fun throttleCasePopUps(current: PodDevice): Event? {
internal fun throttleCasePopUps(current: PodDevice): Event? {
val cooldownKey = current.profileId ?: current.identifier?.toString() ?: return null
val now = timeSource.now()
val lastShown = caseCoolDowns[cooldownKey]
@@ -95,9 +102,9 @@ class PopUpReaction @Inject constructor(
}
decision.shouldHide -> {
if (!decision.shouldResetCooldown) {
caseCoolDowns[cooldownKey] = now
}
// Don't stamp the cooldown on a non-CLOSED hide (UNKNOWN/NOT_IN_CASE). Refreshing it
// here would let a transient UNKNOWN (e.g. a brief out-of-case frame) suppress a
// genuine OPEN for the whole cooldown window. CLOSED still resets it above.
Event.PopupHide(now)
}
@@ -192,7 +199,48 @@ class PopUpReaction @Inject constructor(
}
.setupCommonEventHandlers(TAG) { "popUpConnection" }
fun monitor(): Flow<Event> = merge(monitorCase(), monitorConnection())
/**
* Backstop for case-open popups that never receive a CLOSED frame because the device left BLE
* range while the lid was open — otherwise the overlay lingers until manually dismissed (one of
* the symptoms in #598). A ticker re-checks the primary device's freshness; once a previously
* fresh OPEN broadcast goes stale past [CASE_OPEN_STALE_TIMEOUT] (no newer advertisement, or the
* device dropped to cache-only), a single Hide is emitted. The lid-driven [monitorCase] still
* handles the normal close; a redundant Hide here is harmless ([PopUpWindow.close] is idempotent).
*/
private fun monitorCaseStaleClose(): Flow<Event> = combine(
deviceMonitor.primaryDevice(),
staleCheckTicker(),
) { device, _ -> isCaseOpenBroadcastFresh(device) }
.distinctUntilChanged()
.withPrevious()
.mapNotNull { (wasFresh, isFresh) ->
if (wasFresh == true && !isFresh) {
log(TAG) { "Case-open broadcast went stale, emitting Hide" }
Event.PopupHide(timeSource.now())
} else {
null
}
}
.setupCommonEventHandlers(TAG) { "popUpCaseStale" }
/** True while the primary device is eligible and currently advertising a fresh OPEN lid. */
internal fun isCaseOpenBroadcastFresh(device: PodDevice?): Boolean {
if (device?.reactions?.showPopUpOnCaseOpen != true) return false
if (device.caseLidState != DualApplePods.LidState.OPEN) return false
// Track BLE freshness specifically, not PodDevice.seenLastAt (which also counts AAP/cache):
// the lid is a BLE-only signal, so a live AAP socket must not keep a stale OPEN on screen.
val bleSeenLastAt = device.ble?.seenLastAt ?: return false
return Duration.between(bleSeenLastAt, timeSource.now()) <= CASE_OPEN_STALE_TIMEOUT
}
private fun staleCheckTicker(): Flow<Unit> = flow {
while (true) {
emit(Unit)
delay(STALE_CHECK_INTERVAL.toMillis())
}
}
fun monitor(): Flow<Event> = merge(monitorCase(), monitorConnection(), monitorCaseStaleClose())
sealed class Event {
data class PopupShow(
@@ -296,5 +344,11 @@ class PopUpReaction @Inject constructor(
companion object {
private val TAG = logTag("Reaction", "PopUp")
/** A case-open popup is force-dismissed once its OPEN broadcast hasn't refreshed for this long. */
private val CASE_OPEN_STALE_TIMEOUT: Duration = Duration.ofSeconds(4)
/** How often the stale-close backstop re-evaluates freshness. */
private val STALE_CHECK_INTERVAL: Duration = Duration.ofSeconds(2)
}
}
@@ -9,6 +9,7 @@ import eu.darken.capod.common.bluetooth.ScannerMode
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.datastore.valueBlocking
import eu.darken.capod.common.debug.logging.Logging.Priority.INFO
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.uix.ViewModel4
@@ -22,14 +23,13 @@ import eu.darken.capod.pods.core.unknown.UnknownSnapshotBle
import eu.darken.capod.profiles.core.AppleDeviceProfile
import eu.darken.capod.profiles.core.DeviceProfilesRepo
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.withTimeoutOrNull
import javax.inject.Inject
@@ -47,6 +47,9 @@ class TroubleShooterViewModel @Inject constructor(
private val _bleState = MutableStateFlow<BleState>(BleState.Intro())
/** Guards against re-entrant runs (e.g. a double tap on "Try again"). */
private val runLock = Mutex()
data class State(val bleState: BleState)
val state = _bleState.map { State(it) }.asLiveState()
@@ -82,169 +85,184 @@ class TroubleShooterViewModel @Inject constructor(
}
fun troubleShootBle() = launch(context = dispatcherProvider.IO) {
if (!runLock.tryLock()) {
log(TAG, WARN) { "troubleShootBle() ignored, a run is already in progress" }
return@launch
}
log(TAG, INFO) { "troubleShootBle()" }
bleScanModeController.withTemporaryOverride(ScannerMode.LOW_LATENCY) override@{
try {
run {
progress("Checking for headphones...")
val mainDevice = withTimeoutOrNull(STEP_TIME) {
deviceMonitor.primaryDevice().filterNotNull().firstOrNull()
}
if (mainDevice != null) {
success("Headphones found, nothing to troubleshoot.")
return@override
} else {
progress("Headphones not detected.\n")
}
}
try {
bleScanModeController.withTemporaryOverride(ScannerMode.LOW_LATENCY) override@{
// The combo under which supported headphones were detected (set in sweep 2).
var supportedCombo: BlePodMonitor.CompatOverride? = null
// Set only when the run reaches a terminal success. Persisted on exit; staying null
// (any failure, or cancellation) means we just clear the override, which restores the
// user's original — never-touched — settings.
var comboToPersist: BlePodMonitor.CompatOverride? = null
try {
run {
progress("Checking for headphones...")
if (findLiveBleHeadphones()) {
success("Headphones found, nothing to troubleshoot.")
return@override
} else {
progress("Headphones not detected.\n")
}
}
val doScan: suspend (Boolean, Boolean, Boolean, Boolean) -> Collection<BlePodSnapshot> =
{ hardwareFilteringDisabled,
hardwareBatchingDisabled,
indirectCallback,
unfiltered ->
val sb = StringBuilder("SCAN - Settings: ")
sb.append("hardwareFilteringDisabled=$hardwareFilteringDisabled, ")
sb.append("hardwareBatchingDisabled=$hardwareBatchingDisabled, ")
sb.append("indirectCallback=$indirectCallback, ")
sb.append("unfiltered=$unfiltered")
progress(sb.toString())
generalSettings.isOffloadedFilteringDisabled.valueBlocking = hardwareFilteringDisabled
generalSettings.isOffloadedBatchingDisabled.valueBlocking = hardwareBatchingDisabled
generalSettings.useIndirectScanResultCallback.valueBlocking = indirectCallback
blePodMonitor.setUnfilteredOverride(unfiltered)
val doScan: suspend (BlePodMonitor.CompatOverride, Boolean) -> Collection<BlePodSnapshot> =
{ combo, unfiltered ->
progress(
"SCAN - Settings: filteringDisabled=${combo.offloadedFilteringDisabled}, " +
"batchingDisabled=${combo.offloadedBatchingDisabled}, " +
"indirectCallback=${combo.indirectCallback}, unfiltered=$unfiltered"
)
blePodMonitor.setCompatOverride(combo)
blePodMonitor.setUnfilteredOverride(unfiltered)
val devices = collectFreshDevices()
log(TAG) { "SCAN: Fresh BLE devices: $devices" }
if (devices.isNotEmpty()) {
progress("SCAN: Received data from ${devices.size} BLE devices")
} else {
progress("SCAN: No data received")
}
devices
}
val start = timeSource.elapsedRealtime()
val devices = withTimeoutOrNull(STEP_TIME) {
blePodMonitor.devices
.take(10)
.takeWhile { timeSource.elapsedRealtime() - start < STEP_TIME - 1000 }
.toList()
.flatten()
.distinctBy { it.address }
} ?: emptyList()
log(TAG) { "SCAN: BLE Devices: $devices" }
if (devices.isNotEmpty()) {
progress("SCAN: Received data from ${devices.size} BLE devices")
devices
} else {
progress("SCAN: No data received")
devices
run {
progress("Checking if we can receive BLE data at all.")
val gotData = COMPAT_COMBOS.any { combo -> doScan(combo, true).isNotEmpty() }
if (!gotData) {
failure("Phone is not receiving BLE data.", BleState.Result.Failure.Type.PHONE)
return@override
}
}
progress("We received at least some BLE data.\n")
run {
progress("Checking for supported headphones.")
supportedCombo = COMPAT_COMBOS.firstOrNull { combo ->
doScan(combo, false).any { it !is UnknownSnapshotBle }
}
if (supportedCombo == null) {
failure("No compatible headphones found", BleState.Result.Failure.Type.HEADPHONES)
return@override
}
}
progress("Found some headphones that are supported by CAPod.\n")
run {
progress("Checking for your headphones with new BLE settings...")
if (findLiveBleHeadphones()) {
comboToPersist = supportedCombo
success("Found your headphones, new BLE settings worked :)!")
return@override
}
}
progress("Still no headphones detected that count as yours.\n")
run {
progress("Checking all closeby headphones.")
val otherDevices = collectFreshDevices()
otherDevices.forEachIndexed { index, dev -> log(TAG) { "Device #$index: $dev" } }
val candidate = otherDevices
.filter { it !is UnknownSnapshotBle }
.maxByOrNull { it.signalQuality }
if (candidate == null) {
failure(
"No supported headphones found near your device.",
BleState.Result.Failure.Type.HEADPHONES,
)
return@override
}
progress("Headphones found nearby, but not detected as yours.\n")
progress("Creating profile for closest headphones.")
log(TAG, INFO) { "Candidate is $candidate" }
profilesRepo.addProfile(
profile = AppleDeviceProfile(
label = context.getString(R.string.troubleshooter_title),
model = candidate.model,
),
addFirst = true,
)
if (findLiveBleHeadphones()) {
comboToPersist = supportedCombo
success("Success! Detected your headphones.")
} else {
failure("No headphones detected near your device.", BleState.Result.Failure.Type.HEADPHONES)
}
}
} finally {
blePodMonitor.setUnfilteredOverride(false)
try {
// Persist the winning combo before dropping the override so the effective scan
// settings stay equal with no restart flicker. Done in its own try so the
// override is still cleared (restoring originals) even if a write throws.
comboToPersist?.let { persistCompat(it) }
} finally {
blePodMonitor.setCompatOverride(null)
}
}
run {
progress("Checking if we can receive BLE data at all.")
if (doScan(false, false, false, true).isNotEmpty()) return@run
if (doScan(false, false, true, true).isNotEmpty()) return@run
if (doScan(true, true, true, true).isNotEmpty()) return@run
if (doScan(true, true, false, true).isNotEmpty()) return@run
if (doScan(true, false, true, true).isNotEmpty()) return@run
if (doScan(true, false, false, true).isNotEmpty()) return@run
if (doScan(false, true, true, true).isNotEmpty()) return@run
if (doScan(false, true, false, true).isNotEmpty()) return@run
failure("Phone is not receiving BLE data.", BleState.Result.Failure.Type.PHONE)
generalSettings.isOffloadedFilteringDisabled.valueBlocking = false
generalSettings.isOffloadedBatchingDisabled.valueBlocking = false
generalSettings.useIndirectScanResultCallback.valueBlocking = false
return@override
}
progress("We received at least some BLE data.\n")
run {
progress("Checking for supported headphones.")
if (doScan(false, false, false, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(false, false, true, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(true, true, true, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(true, true, false, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(true, false, true, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(true, false, false, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(false, true, true, false).any { it !is UnknownSnapshotBle }) return@run
if (doScan(false, true, false, false).any { it !is UnknownSnapshotBle }) return@run
failure("No compatible headphones found", BleState.Result.Failure.Type.HEADPHONES)
generalSettings.isOffloadedFilteringDisabled.valueBlocking = false
generalSettings.isOffloadedBatchingDisabled.valueBlocking = false
generalSettings.useIndirectScanResultCallback.valueBlocking = false
return@override
}
progress("Found some headphones that are supported by CAPod.\n")
run {
progress("Checking for your headphones with new BLE settings...")
val mainDevice = withTimeoutOrNull(STEP_TIME) {
deviceMonitor.primaryDevice().filterNotNull().firstOrNull()
}
if (mainDevice != null) {
success("Found your headphones, new BLE settings worked :)!")
return@override
}
}
progress("Still no headphones detected that count as yours.\n")
run {
progress("Checking all closeby headphones.")
val otherDevices = withTimeoutOrNull(STEP_TIME) {
val start = timeSource.elapsedRealtime()
blePodMonitor.devices
.take(10)
.takeWhile { timeSource.elapsedRealtime() - start < STEP_TIME - 1000 }
.toList()
.flatten()
.distinctBy { it.address }
} ?: emptyList()
otherDevices.forEachIndexed { index, dev -> log(TAG) { "Device #$index: $dev" } }
if (otherDevices.isEmpty()) {
failure("No supported headphones found near your device.", BleState.Result.Failure.Type.HEADPHONES)
return@override
}
progress("Headphones found nearby, but not detected as yours.\n")
progress("Creating profile for closest headphones.")
val candidate = otherDevices
.filter { it !is UnknownSnapshotBle }
.maxBy { it.signalQuality }
log(TAG, INFO) { "Candidate is $candidate" }
profilesRepo.addProfile(
profile = AppleDeviceProfile(
label = context.getString(R.string.troubleshooter_title),
model = candidate.model,
),
addFirst = true,
)
val mainDevice = withTimeoutOrNull(STEP_TIME) {
deviceMonitor.primaryDevice().filterNotNull().firstOrNull()
}
if (mainDevice != null) {
success("Success! Detected your headphones.")
} else {
failure("No headphones detected near your device.", BleState.Result.Failure.Type.HEADPHONES)
}
}
} finally {
blePodMonitor.setUnfilteredOverride(false)
}
} finally {
runLock.unlock()
}
}
/**
* Waits up to [STEP_TIME] for the primary profile to be backed by a *fresh, live BLE*
* observation. A cached-only / AAP-only primary does not count — the troubleshooter is about
* whether BLE advertisements are actually reaching us. The freshness cutoff (snapshot seen at or
* after this call) means it reflects the currently-active scan settings and doesn't rely on the
* device cache having been cleared beforehand.
*/
private suspend fun findLiveBleHeadphones(): Boolean {
val threshold = timeSource.now()
return withTimeoutOrNull(STEP_TIME) {
deviceMonitor.primaryDevice().firstOrNull { device ->
device?.ble != null && (device.seenLastAt?.let { it >= threshold } == true)
} != null
} ?: false
}
/**
* Collects BLE devices observed *after the current scan settings take effect*. Option changes
* restart the scan after a throttle, and [BlePodMonitor] keeps a 20s device cache, so without a
* freshness cutoff a stale observation from a previous combo could be mistaken for a "win".
*/
private suspend fun collectFreshDevices(): List<BlePodSnapshot> {
// Drop anything cached under a previous combo so it can't satisfy this attempt.
blePodMonitor.clearDeviceCache()
val freshThreshold = timeSource.now().plusMillis(SCAN_SETTLE_MS)
val start = timeSource.elapsedRealtime()
val collected = mutableListOf<BlePodSnapshot>()
// Accumulate as we go: a timeout must not discard what we already observed. toList() only
// returns once the flow completes, which a quiet channel may never do within the window.
withTimeoutOrNull(STEP_TIME) {
blePodMonitor.devices
.takeWhile { timeSource.elapsedRealtime() - start < STEP_TIME - 1000 }
.collect { snapshots -> collected.addAll(snapshots) }
}
return collected
.filter { it.seenLastAt >= freshThreshold }
.distinctBy { it.address }
}
private fun persistCompat(combo: BlePodMonitor.CompatOverride) {
generalSettings.isOffloadedFilteringDisabled.valueBlocking = combo.offloadedFilteringDisabled
generalSettings.isOffloadedBatchingDisabled.valueBlocking = combo.offloadedBatchingDisabled
generalSettings.useIndirectScanResultCallback.valueBlocking = combo.indirectCallback
}
sealed class BleState {
class Intro : BleState()
@@ -295,6 +313,29 @@ class TroubleShooterViewModel @Inject constructor(
companion object {
const val STEP_TIME = 10 * 1000L
/**
* Grace period after switching compat settings before an observation counts as "fresh".
* Covers [BlePodMonitor]'s ~1s scan-option throttle plus the scanner restart.
*/
const val SCAN_SETTLE_MS = 1500L
/**
* Compatibility combinations to probe, ordered fewest-disables-first so the first one that
* works (and gets persisted) is the *minimal* set of overrides — e.g. a phone that only
* needs batching disabled won't also get filtering disabled. Triple semantics:
* (offloadedFilteringDisabled, offloadedBatchingDisabled, indirectCallback).
*/
val COMPAT_COMBOS: List<BlePodMonitor.CompatOverride> = listOf(
BlePodMonitor.CompatOverride(false, false, false), // baseline (no overrides)
BlePodMonitor.CompatOverride(false, true, false), // batching only
BlePodMonitor.CompatOverride(true, false, false), // filtering only
BlePodMonitor.CompatOverride(false, false, true), // indirect callback only
BlePodMonitor.CompatOverride(false, true, true), // batching + indirect
BlePodMonitor.CompatOverride(true, false, true), // filtering + indirect
BlePodMonitor.CompatOverride(true, true, false), // filtering + batching
BlePodMonitor.CompatOverride(true, true, true), // everything
)
val TAG = logTag("TroubleShooter", "VM")
}
}
@@ -12,7 +12,7 @@
<clip>
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="?android:attr/colorAccent" />
<solid android:color="@color/brand_primary" />
</shape>
</clip>
</item>
@@ -24,8 +24,8 @@
android:id="@+id/pod_left_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/device_airpods_gen1_left" />
<ProgressBar
@@ -58,8 +58,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
@@ -67,8 +67,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -88,8 +88,8 @@
android:id="@+id/pod_case_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/device_airpods_gen1_case" />
<ProgressBar
@@ -122,8 +122,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
</LinearLayout>
@@ -142,8 +142,8 @@
android:id="@+id/pod_right_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/device_airpods_gen1_right" />
<ProgressBar
@@ -176,8 +176,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
@@ -185,8 +185,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -38,6 +38,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
@@ -46,6 +48,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -76,6 +80,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
</LinearLayout>
@@ -105,6 +111,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
@@ -113,6 +121,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -24,8 +24,8 @@
android:id="@+id/headphones_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/twotone_headphones_24" />
<TextView
@@ -71,8 +71,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
@@ -80,8 +80,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tintMode="multiply"
android:tint="?android:attr/colorAccent"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -30,6 +30,8 @@
android:id="@+id/headphones_battery_icon"
style="@style/PodInfoItemIcon.Notification"
android:layout_marginStart="12dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_battery_unknown_24" />
<TextView
@@ -46,6 +48,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
@@ -54,6 +58,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="2dp"
android:tint="@color/notification_icon_tint"
android:tintMode="src_in"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
+17 -1
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Wys verbindingsopspringer</string>
<string name="settings_popup_connected_description">Wys \'n opspringer wanneer die toestel vir die eerste keer koppel.</string>
<string name="settings_popup_info_not_in_app">Opspringvensters word slegs gewys as jy nie in die program is nie.</string>
<string name="settings_charged_notification_label">Gelaaide kennisgewing</string>
<string name="settings_charged_notification_description">Wys \'n kennisgewing sodra alles wat laai die teikenlaai vlak bereik.</string>
<string name="settings_charged_threshold_label">Teikenlaai vlak</string>
<string name="settings_charged_scope_label">Gemonitorde batterye</string>
<string name="settings_charged_scope_pods_label">Slegs pods</string>
<string name="settings_charged_scope_case_label">Slegs kis</string>
<string name="settings_charged_scope_both_label">Pods en kis</string>
<string name="device_settings_experimental_title">Eksperimentele kenmerk</string>
<string name="device_settings_experimental_description">Hierdie kenmerk is nog nie op alle toestelle getoets nie. As iets nie korrek werk nie, open asseblief \'n kwessie met \'n foutopsporingsloglêer.</string>
<string name="device_settings_experimental_action">Open Kwessiespoorder</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Ontfout</string>
<string name="settings_general_label">Algemene instellings</string>
<string name="settings_general_description">Algemene aanpassings wat die hele toepassing beïnvloed.</string>
<string name="settings_overview_hide_unmatched_label">Versteek onooreenstemmende toestelle</string>
<string name="settings_overview_hide_unmatched_description">Moenie naby toestelle wys wat nie ooreenstem met enige van jou profiele in die oorsig nie, bv. ander mense se AirPods.</string>
<string name="settings_acknowledgements_label">Erkennings</string>
<string name="settings_debug_autoreports_label">Outomatiese foutverslae</string>
<string name="settings_debug_autoreports_description">Rapporteer probleme outomaties, bv. besonderhede oor \'n toepassingstorting sodat ek kan uitvind hoe om dit reg te stel.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth is gedeaktiveer, aktiveer dit ;)</string>
<string name="overview_monitoring_active_label">Moniteer vir toestelle</string>
<string name="overview_monitoring_active_description">Maak seker jou toestel is naby en aktief.</string>
<string name="overview_troubleshoot_suggestion_label">Verbind, maar geen data nie</string>
<string name="overview_troubleshoot_suggestion_description">Jou toestel is verbind, maar CAPod ontvang geen lewende data daarvan nie. Jou foon het dalk \'n versoenbaarheidsopsie nodig — die probleemoplosser kan probeer om een outomaties te vind.</string>
<string name="overview_troubleshoot_suggestion_action">Voer probleemoplosser uit</string>
<string name="overview_unmatched_devices_label">Ongepasde toestelle</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d toestel sonder ooreenstemmende profiel</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Slaapopsporing</string>
<string name="reaction_sleep_notification_title">Gepauseer deur Slaapopsporing</string>
<string name="reaction_sleep_notification_text">%1$s het aangemeld dat jy aan die slaap geraak het, so jou musiek is gepauseer. Jy kan dit in die toestelinstellings deaktiveer.</string>
<string name="reaction_charged_channel_label">Gelaaide kennisgewing</string>
<string name="reaction_charged_notification_title">Laai voltooi</string>
<string name="reaction_charged_notification_text_full">%1$s is volledig gelaai.</string>
<string name="reaction_charged_notification_text_partial">%1$s is na %2$d%% gelaai.</string>
<string name="device_settings_rename_label">Hernoem</string>
<string name="device_settings_rename_hint">Toestelnaam</string>
<string name="device_settings_rename_confirm">Hernoem</string>
@@ -506,7 +522,7 @@
<string name="device_settings_category_connections_label">Gekoppelde toestelle</string>
<string name="device_settings_connected_devices_description">Ander toestelle wat tans aan hierdie AirPods gekoppel is</string>
<string name="device_settings_connected_device_label">Toestel %d</string>
<string name="device_settings_connected_device_call">In \n oproep</string>
<string name="device_settings_connected_device_call">In n oproep</string>
<string name="device_settings_connected_device_media">Speel media</string>
<string name="device_settings_noise_control_label">Geraasbeheer</string>
<string name="device_settings_eq_label">Egaliseerder</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">የግንኙነት ብቅ-ባይ አሳይ</string>
<string name="settings_popup_connected_description">መሳሪያው ለመጀመሪያ ጊዜ ሲገናኝ ብቅ-ባይ አሳይ።</string>
<string name="settings_popup_info_not_in_app">ፖፕ-አፕ መልዕክቶች በፕሮግራሙ ውስጥ ሳታሉ ብቻ ይታያሉ።</string>
<string name="settings_charged_notification_label">የተሞላ ማሳወቂያ</string>
<string name="settings_charged_notification_description">ሁሉም ነገር ወደ ታለመው የኃይል ደረጃ ሲደርስ ማሳወቂያ አሳይ።</string>
<string name="settings_charged_threshold_label">ታለመው የኃይል ደረጃ</string>
<string name="settings_charged_scope_label">የሚታዩ ባትሪዎች</string>
<string name="settings_charged_scope_pods_label">ፖድስ ብቻ</string>
<string name="settings_charged_scope_case_label">ኬዝ ብቻ</string>
<string name="settings_charged_scope_both_label">ፖድስ እና ኬዝ</string>
<string name="device_settings_experimental_title">ሙከራዊ ባህሪ</string>
<string name="device_settings_experimental_description">ይህ ባህሪ በሁሉም መሳሪያዎች ላይ ገና አልተሞከረም። ሆኖም ካልሰራ፣ እባክዎ የዲበግ ምዝግብ ማስታወሻ ጨምረው ጉዳዩን ይክፈቱ።</string>
<string name="device_settings_experimental_action">የጉዳይ መከታተያ ክፈት</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">ዲባግ</string>
<string name="settings_general_label">ቅንብሮች</string>
<string name="settings_general_description">ሙሉውን መተግበሪያ የሚነኩ አጠቃላይ ማስተካከያዎች።</string>
<string name="settings_overview_hide_unmatched_label">ያልተዛመዱ መሳሪያዎችን ደብቅ</string>
<string name="settings_overview_hide_unmatched_description">ከፕሮፋይሎቻቸው ጋር የማይዛመዱ አቅራቢያ ያሉ መሳሪያዎችን በዝርዝሩ ውስጥ አታሳይ፣ ለምሳሌ የሌሎች ሰዎች AirPods።</string>
<string name="settings_acknowledgements_label">ምስጋናዎች</string>
<string name="settings_debug_autoreports_label">ራስ-ሰር የሳንካ ሪፖርቶች</string>
<string name="settings_debug_autoreports_description">ችግሮችን በራስ-ሰር ሪፖርት ያደርጋል፣ ለምሳሌ የመተግበሪያ ብልሽት ዝርዝሮችን እንዴት ማስተካከል እንዳለብኝ እንድገነዘብ።</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ተሰናክሏል፣ ያንቁት ;)</string>
<string name="overview_monitoring_active_label">መሣሪያዎችን በመከታተል ላይ</string>
<string name="overview_monitoring_active_description">መሣሪያዎ ቅርብ እና ንቁ መሆኑን ያረጋግጡ።</string>
<string name="overview_troubleshoot_suggestion_label">ተገናኝቷል፣ ግን ምንም ዳታ የለም</string>
<string name="overview_troubleshoot_suggestion_description">መሳሪያህ ተገናኝቷል፣ ግን CAPod ከእሱ ምንም ቀጥታ ዳታ አይቀበልም። ስልክህ የተኳሃኝነት አማራጭ ሊፈልግ ይችላል — ችግር ፈቺው በራስ-ሰር ለማግኘት ሊሞክር ይችላል።</string>
<string name="overview_troubleshoot_suggestion_action">ችግር ፈቺን አስጀምር</string>
<string name="overview_unmatched_devices_label">ያልተዛመዱ መሣሪያዎች</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">ተዛማጅ መገለጫ የሌለው %d መሣሪያ</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">የእንቅልፍ ማወቂያ</string>
<string name="reaction_sleep_notification_title">በእንቅልፍ ማወቂያ ምክንያት ታግዷል</string>
<string name="reaction_sleep_notification_text">%1$s እርስዎ ተኝተዋል ብሎ ዘገበ፣ ስለዚህ ሙዚቃዎ ተቋርጧል። ይህን በመሣሪያ ቅንብሮች ውስጥ ማሰናከል ይችላሉ።</string>
<string name="reaction_charged_channel_label">የተሞላ ማሳወቂያ</string>
<string name="reaction_charged_notification_title">ኃይል መሙላት ተጠናቋል</string>
<string name="reaction_charged_notification_text_full">%1$s ሙሉ በሙሉ ተሞልቷል።</string>
<string name="reaction_charged_notification_text_partial">%1$s ወደ %2$d%% ተሞልቷል።</string>
<string name="device_settings_rename_label">ስም ቀይር</string>
<string name="device_settings_rename_hint">የመሣሪያ ስም</string>
<string name="device_settings_rename_confirm">ስም ቀይር</string>
+32 -16
View File
@@ -6,10 +6,10 @@
<string name="general_copy_action">نسخ</string>
<string name="general_thank_you_label">شكرًا لك</string>
<string name="general_upgrade_action">ترقية</string>
<string name="common_feature_requires_pro_msg">رقّي للفتح.</string>
<string name="common_upgrade_required_label">يتطلب الترقية</string>
<string name="general_donate_action">تبرع</string>
<string name="general_check_action">تحقق</string>
<string name="common_feature_requires_pro_msg">رقِّ للفتح.</string>
<string name="common_upgrade_required_label">يتطلب ترقية</string>
<string name="general_donate_action">تبرُّع</string>
<string name="general_check_action">فحص</string>
<string name="general_close_action">إغلاق</string>
<string name="general_edit_action">تعديل</string>
<string name="general_save_action">حفظ</string>
@@ -28,12 +28,12 @@
<string name="upgrade_benefit_device_settings">إعدادات الجهاز المتقدّمة</string>
<string name="upgrade_benefit_device_controls">عناصر التحكم في الجهاز &#8212; الضوضاء، &amp; السيقان، &amp; المزيد</string>
<string name="upgrade_benefit_support">دعم المطوّر</string>
<string name="upgrade_benefit_disclaimer">يعتمد توفر الميزات على سماعات الرأس والجهاز المستخدَم.</string>
<string name="upgrade_benefit_disclaimer">يعتمد توفر الميزات على سمّاعات الرأس والجهاز المستخدَم.</string>
<string name="upgrade_screen_options_description">نفس الميزات، أسعار مختلفة. يشمل الاشتراك فترة تجريبية مجانية ويمكن إلغاؤه في أي وقت.</string>
<string name="upgrade_screen_subscription_trial_action">بدء التجربة المجانية</string>
<string name="upgrade_screen_subscription_action">الاشتراك سنويًا</string>
<string name="upgrade_screen_subscription_action_hint">%s/سنة</string>
<string name="upgrade_screen_iap_action">اشترِ مرة واحدة</string>
<string name="upgrade_screen_iap_action">الشراء مرة واحدة</string>
<string name="upgrade_screen_iap_action_hint">الشراء لمرة واحدة: %s</string>
<string name="upgrade_screen_restore_purchase_action">استعادة المشتريات</string>
<string name="upgrade_screen_restore_purchase_message">لم يتم العثور على أي مشتريات. هل تستخدم الحساب الصحيح؟</string>
@@ -44,18 +44,18 @@
<string name="settings_monitor_connected_notification_description">يعرض إشعارًا إضافيًا عند توصيل جهاز. يتيح لك هذا إخفاء الإشعار الدائم \"لا توجد أجهزة\" عن طريق تعطيل قناة \"حالة الجهاز\".</string>
<string name="settings_keep_notification_after_disconnect_label">الاحتفاظ بالإشعار بعد قطع الاتصال</string>
<string name="settings_keep_notification_after_disconnect_description">الاستمرار في عرض مستويات البطارية المعروفة الأخيرة حتى بعد قطع اتصال AirPods</string>
<string name="settings_autopause_label">إيقاف مؤقت تلقائي</string>
<string name="settings_autopause_description">إيقاف الصوت مؤقتًا عند إزالة الجهاز من أذنك.</string>
<string name="settings_autopause_label">إيقاف مؤقّت تلقائي</string>
<string name="settings_autopause_description">إيقاف الصوت مؤقّتًا عند إزالة الجهاز من أذنك.</string>
<string name="settings_autopplay_label">تشغيل تلقائي</string>
<string name="settings_autoplay_description">استئناف الموسيقى عند ارتداء السماعات مجددًا، ولكن فقط إذا أوقفها الإيقاف التلقائي. الإيقافات التي قمت بتشغيلها بنفسك (الهاتف، ذراع AirPods، وضع السكون) تبقى متوقفة.</string>
<string name="settings_autoplay_description">استئناف الموسيقى عند ارتداء السماعات مجدّدًا، ولكن فقط إذا أوقفها الإيقاف التلقائي. الإيقافات التي شغّلتها بنفسك (الهاتف، ذراع AirPods، وضع السكون) تبقى متوقّفة.</string>
<string name="settings_start_music_on_wear_label">تشغيل الموسيقى عند الارتداء</string>
<string name="settings_start_music_on_wear_description">يحاول دائمًا تشغيل الموسيقى عند وضع السماعات، حتى بعد الإيقاف اليدوي.</string>
<string name="settings_start_music_on_wear_description">يحاول دائمًا تشغيل الموسيقى عند وضع السمّاعات، حتى بعد الإيقاف اليدوي.</string>
<string name="settings_eardetection_info_label">ملاحظة اكتشاف الأذن</string>
<string name="settings_eardetection_info_description">إذا كان اكتشاف الأذن يعمل لسماعة واحدة فقط، فهذا قيد من Apple. يتم اكتشاف \"السماعة الأساسية\" فقط (المستخدمة للميكروفون). قم بالتكوين على أجهزة Apple: الإعدادات → Bluetooth → AirPods → الميكروفون.</string>
<string name="settings_eardetection_info_description">إذا كان اكتشاف الأذن يعمل لسماعة واحدة فقط، فهذا قيدٌ من Apple. يتم اكتشاف \"السمّاعة الأساسية\" فقط (المستخدَمة للميكروفون). اضبط على أجهزة Apple: الإعدادات → Bluetooth → AirPods → الميكروفون.</string>
<string name="settings_signal_minimum_label">الحد الأدنى لجودة الإشارة</string>
<string name="settings_signal_minimum_description">الحد الأدنى لجودة الإشارة التي يجب أن يتمتع بها الجهاز حتى يعتبر ملكك.</string>
<string name="settings_signal_minimum_description">الحد الأدنى لجودة الإشارة التي يجب أن يتمتّع بها الجهاز حتى يُعدّ ملكك.</string>
<string name="settings_autoconnect_label">اتصال تلقائي</string>
<string name="settings_autoconnect_description">إذا لم يتصل Android تلقائيًا، فيمكننا أن نطلب منه ذلك أيضًا. سيؤدي هذا إلى ضبط إعداد وضع الشاشة على \"دائمًا\".</string>
<string name="settings_autoconnect_description">إذا لم يتّصل Android تلقائيًا، فيمكننا أن نطلب منه ذلك أيضًا. سيؤدي هذا إلى ضبط إعداد وضع الشاشة على \"دائمًا\".</string>
<string name="settings_autoconnect_info_android12">يعتمد الاتصال التلقائي على ميزة نظام يقيّدها Android 12 والإصدارات الأحدث. قد لا تعمل على جهازك.</string>
<string name="settings_autoconnect_condition_label">شرط الاتصال التلقائي</string>
<string name="settings_autoconnect_condition_description">متى يجب أن نحاول الاتصال بجهازك؟</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">إظهار نافذة منبثقة للاتصال</string>
<string name="settings_popup_connected_description">إظهار نافذة منبثقة عند اتصال الجهاز لأول مرة.</string>
<string name="settings_popup_info_not_in_app">تظهر النوافذ المنبثقة فقط عندما لا تكون داخل التطبيق.</string>
<string name="settings_charged_notification_label">إشعار الشحن الكامل</string>
<string name="settings_charged_notification_description">اعرض إشعارًا بمجرد وصول جميع الأجهزة التي يتم شحنها إلى مستوى الشحن المستهدف.</string>
<string name="settings_charged_threshold_label">مستوى الشحن المستهدف</string>
<string name="settings_charged_scope_label">البطاريات المُراقبة</string>
<string name="settings_charged_scope_pods_label">السمّاعات فقط</string>
<string name="settings_charged_scope_case_label">الحافظة فقط</string>
<string name="settings_charged_scope_both_label">السماعات والحافظة</string>
<string name="device_settings_experimental_title">ميزة تجريبية</string>
<string name="device_settings_experimental_description">لم يتم اختبار هذه الميزة على جميع الأجهزة بعد. إذا كان هناك شيء لا يعمل بشكل صحيح، يرجى فتح تقرير مشكلة مع سجل تصحيح.</string>
<string name="device_settings_experimental_action">فتح متتبع المشكلات</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">تصحيح الأخطاء</string>
<string name="settings_general_label">الإعدادات</string>
<string name="settings_general_description">تعديلات عامة تؤثر على التطبيق بأكمله.</string>
<string name="settings_overview_hide_unmatched_label">إخفاء الأجهزة غير المتطابقة</string>
<string name="settings_overview_hide_unmatched_description">لا تعرض الأجهزة القريبة التي لا تتطابق مع أي من ملفات تعريفك في النظرة العامة، على سبيل المثال سمّاعات AirPods الخاصة بالآخرين.</string>
<string name="settings_acknowledgements_label">شكر وتقدير</string>
<string name="settings_debug_autoreports_label">تقارير الأخطاء التلقائية</string>
<string name="settings_debug_autoreports_description">الإبلاغ تلقائيًا عن المشكلات، على سبيل المثال تفاصيل حول تعطل التطبيق حتى أتمكن من معرفة كيفية إصلاحه.</string>
@@ -127,14 +136,14 @@
<string name="anc_widget_config_aap_required_hint">يتطلب هذا الودجت اتصالاً مباشراً (AAP) بجهازك. تأكد من إقران جهازك وتوصيله في التطبيق قبل استخدام هذا الودجت.</string>
<string name="anc_widget_no_anc_support_label">هذا الجهاز لا يدعم التحكم في الضوضاء</string>
<string name="anc_widget_aap_not_connected_label">غير متصل</string>
<string name="anc_widget_aap_not_connected_nearby_description">قريب ولكن غير متصل</string>
<string name="anc_widget_aap_not_connected_nearby_description">قريب ولكن غير متّصل</string>
<string name="anc_widget_aap_not_connected_not_nearby_description">غير قريب</string>
<string name="anc_widget_aap_connecting_label">جارٍ الاتصال…</string>
<string name="tile_anc_label">التحكم في الضوضاء</string>
<string name="tile_anc_subtitle_permission_required">الإذن مطلوب</string>
<string name="tile_anc_subtitle_no_device">لا يوجد جهاز</string>
<string name="tile_anc_subtitle_no_anc_support">لا يوجد تحكم في الضوضاء</string>
<string name="tile_anc_subtitle_bluetooth_off">البلوتوث مُغلق</string>
<string name="tile_anc_subtitle_bluetooth_off">البلوتوث مغلق</string>
<string name="widget_config_screen_title">إعداد عنصر الواجهة</string>
<string name="widget_configuration_title">اختيار الجهاز</string>
<string name="widget_configuration_description">اختر ملف تعريف الجهاز الذي يجب أن تعرضه هذه الأداة.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">البلوتوث معطل، قم بتمكينه ;)</string>
<string name="overview_monitoring_active_label">جارٍ مراقبة الأجهزة</string>
<string name="overview_monitoring_active_description">تأكد من أن جهازك قريب ونشط.</string>
<string name="overview_troubleshoot_suggestion_label">متصل، ولكن لا توجد بيانات</string>
<string name="overview_troubleshoot_suggestion_description">جهازك متصل، لكن تطبيق CAPod لا يستقبل أي بيانات مباشرة منه. قد يحتاج هاتفك إلى خيار توافق - يمكن لمُستكشف الأخطاء ومُصلحها محاولة إيجاد واحد تلقائيًّا.</string>
<string name="overview_troubleshoot_suggestion_action">تشغيل مُستكشف الأخطاء ومُصلحها</string>
<string name="overview_unmatched_devices_label">أجهزة غير متطابقة</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="zero">%d أجهزة بدون ملف تعريف مطابق</item>
@@ -488,7 +500,7 @@
<!-- New device settings -->
<string name="device_settings_category_general_label">عام</string>
<string name="device_settings_microphone_mode_label">ميكروفون</string>
<string name="device_settings_microphone_mode_description">سماعة الأذن المستخدمة كميكروفون</string>
<string name="device_settings_microphone_mode_description">سمّاعة الأذن المستخدمة كميكروفون</string>
<string name="device_settings_microphone_mode_auto">تلقائي</string>
<string name="device_settings_microphone_mode_right">يمين</string>
<string name="device_settings_microphone_mode_left">يسار</string>
@@ -510,6 +522,10 @@
<string name="reaction_sleep_channel_label">اكتشاف النوم</string>
<string name="reaction_sleep_notification_title">تم الإيقاف المؤقت بواسطة اكتشاف النوم</string>
<string name="reaction_sleep_notification_text">%1$s أفاد بأنك نمت، لذا تم إيقاف موسيقاك مؤقتًا. يمكنك تعطيل هذا في إعدادات الجهاز.</string>
<string name="reaction_charged_channel_label">إشعار الشحن الكامل</string>
<string name="reaction_charged_notification_title">اكتمل الشحن</string>
<string name="reaction_charged_notification_text_full">%1$s مشحون بالكامل.</string>
<string name="reaction_charged_notification_text_partial">تم شحن %1$s إلى %2$d%%.</string>
<string name="device_settings_rename_label">إعادة تسمية</string>
<string name="device_settings_rename_hint">اسم الجهاز</string>
<string name="device_settings_rename_confirm">إعادة تسمية</string>
+17 -1
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Qoşulma pop-up-ını göstər</string>
<string name="settings_popup_connected_description">Cihaz ilk dəfə qoşulduqda pop-up göstər.</string>
<string name="settings_popup_info_not_in_app">Açılan pəncərələr yalnız tətbiqdə olmadığınız zaman göstərilir.</string>
<string name="settings_charged_notification_label">Şarj bildirişi</string>
<string name="settings_charged_notification_description">Şarj olunan hər şey hədəf şarj səviyyəsinə çatdıqda bildiriş göndərin.</string>
<string name="settings_charged_threshold_label">Hədəf şarj səviyyəsi</string>
<string name="settings_charged_scope_label">İzlənilən akkumulyatorlar</string>
<string name="settings_charged_scope_pods_label">Yalnız qulaqcıqlar</string>
<string name="settings_charged_scope_case_label">Yalnız qutu</string>
<string name="settings_charged_scope_both_label">Qulaqcıqlar və qutu</string>
<string name="device_settings_experimental_title">Eksperimental funksiya</string>
<string name="device_settings_experimental_description">Bu funksiya hələ bütün cihazlarda sınaqdan keçirilməyib. Bir şey düzgün işləmirsə, debug loqu ilə problem bildirin.</string>
<string name="device_settings_experimental_action">Problem İzləyicisini Aç</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Sazlama</string>
<string name="settings_general_label">Parametrlər</string>
<string name="settings_general_description">Bütün tətbiqə təsir edən ümumi düzəlişlər.</string>
<string name="settings_overview_hide_unmatched_label">Uyğun olmayan cihazları gizlət</string>
<string name="settings_overview_hide_unmatched_description">İcmalda profillərinizə uyğun gəlməyən yaxın cihazları göstərməyin, məs. başqalarının AirPods-ları.</string>
<string name="settings_acknowledgements_label">Təşəkkürlər</string>
<string name="settings_debug_autoreports_label">Avtomatik səhv hesabatları</string>
<string name="settings_debug_autoreports_description">Problemləri avtomatik olaraq bildirir, məsələn, tətbiqin çökməsi ilə bağlı təfərrüatları, beləliklə onu necə düzəldəcəyimi anlaya bilim.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth deaktivdir, onu aktivləşdirin ;)</string>
<string name="overview_monitoring_active_label">Cihazlar axtarılır</string>
<string name="overview_monitoring_active_description">Cihazınızın yaxında və aktiv olduğundan əmin olun.</string>
<string name="overview_troubleshoot_suggestion_label">Qoşuldu, lakin məlumat yoxdur</string>
<string name="overview_troubleshoot_suggestion_description">Cihazınız qoşulub, lakin CAPod ondan canlı məlumat almır. Telefonunuz uyğunluq seçiminə ehtiyac duya bilər — problem aradan qaldırıcı birini avtomatik tapmağa çalışa bilər.</string>
<string name="overview_troubleshoot_suggestion_action">Problem aradan qaldırıcını işə sal</string>
<string name="overview_unmatched_devices_label">Uyğunlaşdırılmamış cihazlar</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">Uyğun profili olmayan %d cihaz</item>
@@ -223,7 +235,7 @@
<string name="pods_dual_left_label">Sol qulaqlıq</string>
<string name="pods_dual_right_label">Sağ qulaqlıq</string>
<string name="pods_dual_left_short_label">S</string>
<string name="pods_dual_right_short_label">Sğ</string>
<string name="pods_dual_right_short_label">S</string>
<string name="pods_case_label">Qutu</string>
<string name="battery_unavailable_label">Batareya məlumatı yoxdur</string>
<string name="pods_case_status_open_label">Açıq</string>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Yuxu Aşkarlaması</string>
<string name="reaction_sleep_notification_title">Yuxu Aşkarlaması ilə dayandırıldı</string>
<string name="reaction_sleep_notification_text">%1$s sizin yuxuya getdiyinizi bildirdi, buna görə musiqiniz dayandırıldı. Bunu cihaz parametrlərindən söndürə bilərsiniz.</string>
<string name="reaction_charged_channel_label">Şarj Bildirişi</string>
<string name="reaction_charged_notification_title">Şarj tamamlandı</string>
<string name="reaction_charged_notification_text_full">%1$s tam şarj olundu.</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% şarj olundu.</string>
<string name="device_settings_rename_label">Adı dəyişdirin</string>
<string name="device_settings_rename_hint">Cihaz adı</string>
<string name="device_settings_rename_confirm">Adı dəyişdirin</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Паказаць усплывальнае акно падключэння</string>
<string name="settings_popup_connected_description">Паказваць усплывальнае акно пры першым падключэнні прылады.</string>
<string name="settings_popup_info_not_in_app">Усплывальныя вокны паказваюцца толькі тады, калі вы не знаходзіцеся ў прыкладанні.</string>
<string name="settings_charged_notification_label">Апавяшчэнне аб зарадцы</string>
<string name="settings_charged_notification_description">Паказваць апавяшчэнне, калі ўсё, што зараджаецца, дасягне мэтавага ўзроўню зарадкі.</string>
<string name="settings_charged_threshold_label">Мэтавы ўзровень зарадкі</string>
<string name="settings_charged_scope_label">Адсочваемыя батарэі</string>
<string name="settings_charged_scope_pods_label">Толькі навушнікі</string>
<string name="settings_charged_scope_case_label">Толькі футарал</string>
<string name="settings_charged_scope_both_label">Навушнікі і футарал</string>
<string name="device_settings_experimental_title">Эксперыментальная функцыя</string>
<string name="device_settings_experimental_description">Гэта функцыя яшчэ не была праверана на ўсіх прыладах. Калі нешта не працуе правільна, калі ласка, стварыце запыт з журналам адладкі.</string>
<string name="device_settings_experimental_action">Адкрыць трэкер задач</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Адладка</string>
<string name="settings_general_label">Налады</string>
<string name="settings_general_description">Агульныя налады, якія ўплываюць на ўсю праграму.</string>
<string name="settings_overview_hide_unmatched_label">Хаваць непрызнаныя прылады</string>
<string name="settings_overview_hide_unmatched_description">Не паказваць у агляднічку блізкія прылады, якія не адпавядаюць ніводнаму з вашых профіляў, напр. AirPods іншых людзей.</string>
<string name="settings_acknowledgements_label">Падзякі</string>
<string name="settings_debug_autoreports_label">Аўтаматычныя справаздачы пра памылкі</string>
<string name="settings_debug_autoreports_description">Аўтаматычна паведамляе пра праблемы, напрыклад, звесткі пра збой праграмы, каб я мог зразумець, як гэта выправіць.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth адключаны, уключыце яго ;)</string>
<string name="overview_monitoring_active_label">Маніторынг прылад</string>
<string name="overview_monitoring_active_description">Пераканайцеся, што ваша прылада побач і актыўная.</string>
<string name="overview_troubleshoot_suggestion_label">Падлучана, але дадзеных няма</string>
<string name="overview_troubleshoot_suggestion_description">Ваша прылада падлучана, але CAPod не атрымлівае ніякіх жывых дадзеных з яе. Вашаму тэлефону можа спатрэбіцца параметр сумяшчальнасці — ліквідатар непаладак можа паспрабаваць знайсці яго аўтаматычна.</string>
<string name="overview_troubleshoot_suggestion_action">Запусціць ліквідатар непаладак</string>
<string name="overview_unmatched_devices_label">Неадпаведныя прылады</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d прылада без адпаведнага профілю</item>
@@ -500,6 +512,10 @@
<string name="reaction_sleep_channel_label">Выяўленне сну</string>
<string name="reaction_sleep_notification_title">Прыпынена функцыяй выяўлення сну</string>
<string name="reaction_sleep_notification_text">%1$s паведаміла, што вы заснулі, таму музыка была прыпынена. Вы можаце адключыць гэта ў наладах прылады.</string>
<string name="reaction_charged_channel_label">Апавяшчэнне аб зарадцы</string>
<string name="reaction_charged_notification_title">Зарадка завершана</string>
<string name="reaction_charged_notification_text_full">%1$s поўнасцю зараджаны.</string>
<string name="reaction_charged_notification_text_partial">%1$s зараджаны да %2$d%%.</string>
<string name="device_settings_rename_label">Перайменаваць</string>
<string name="device_settings_rename_hint">Назва прылады</string>
<string name="device_settings_rename_confirm">Перайменаваць</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Показване на изскачащ прозорец за връзка</string>
<string name="settings_popup_connected_description">Показване на изскачащ прозорец, когато устройството се свърже за първи път.</string>
<string name="settings_popup_info_not_in_app">Изскачащите прозорци се показват само когато не сте в приложението.</string>
<string name="settings_charged_notification_label">Известие за зареждане</string>
<string name="settings_charged_notification_description">Показва известие, когато всичко, което се зарежда, достигне желаното ниво на заряд.</string>
<string name="settings_charged_threshold_label">Целево ниво на заряд</string>
<string name="settings_charged_scope_label">Наблюдавани батерии</string>
<string name="settings_charged_scope_pods_label">Само слушалки</string>
<string name="settings_charged_scope_case_label">Само калъф</string>
<string name="settings_charged_scope_both_label">Слушалки и калъф</string>
<string name="device_settings_experimental_title">Експериментална функция</string>
<string name="device_settings_experimental_description">Тази функция все още не е тествана на всички устройства. Ако нещо не работи правилно, моля отворете проблем с дневник за отстраняване на грешки.</string>
<string name="device_settings_experimental_action">Отвори проследявач на проблеми</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Отстраняване на грешки</string>
<string name="settings_general_label">Настройки</string>
<string name="settings_general_description">Общи настройки, които засягат цялото приложение.</string>
<string name="settings_overview_hide_unmatched_label">Скриване на несъответстващи устройства</string>
<string name="settings_overview_hide_unmatched_description">Не показвай намиращи се наблизо устройства, които не съответстват на нито един от профилите ти в прегледа, напр. AirPods на други хора.</string>
<string name="settings_acknowledgements_label">Благодарности</string>
<string name="settings_debug_autoreports_label">Автоматични доклади за грешки</string>
<string name="settings_debug_autoreports_description">Автоматично докладва проблеми, напр. подробности за срив на приложението, за да мога да разбера как да го поправя.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth е деактивиран, активирайте го ;)</string>
<string name="overview_monitoring_active_label">Наблюдение на устройства</string>
<string name="overview_monitoring_active_description">Уверете се, че устройството ви е наблизо и активно.</string>
<string name="overview_troubleshoot_suggestion_label">Свързан, но без данни</string>
<string name="overview_troubleshoot_suggestion_description">Устройството ти е свързано, но CAPod не получава данни от него в реално време. Телефонът ти може да се нуждае от опция за съвместимост — инструментът за отстраняване на неизправности може да се опита да намери такава автоматично.</string>
<string name="overview_troubleshoot_suggestion_action">Стартирай отстраняване на неизправности</string>
<string name="overview_unmatched_devices_label">Несъвпадащи устройства</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d устройство без съвпадащ профил</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Откриване на сън</string>
<string name="reaction_sleep_notification_title">Поставено на пауза от Откриване на сън</string>
<string name="reaction_sleep_notification_text">%1$s откри, че сте заспали, затова музиката ви беше поставена на пауза. Можете да деактивирате това в настройките на устройството.</string>
<string name="reaction_charged_channel_label">Известие за зареждане</string>
<string name="reaction_charged_notification_title">Зареждането е завършено</string>
<string name="reaction_charged_notification_text_full">%1$s е напълно зареден.</string>
<string name="reaction_charged_notification_text_partial">%1$s е зареден до %2$d%%.</string>
<string name="device_settings_rename_label">Преименуване</string>
<string name="device_settings_rename_hint">Наименование на устройството</string>
<string name="device_settings_rename_confirm">Преименуване</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">সংযোগ পপআপ দেখান</string>
<string name="settings_popup_connected_description">ডিভাইস প্রথমবার সংযুক্ত হলে একটি পপআপ দেখান।</string>
<string name="settings_popup_info_not_in_app">পপআপগুলি শুধুমাত্র তখনই দেখানো হয় যখন আপনি অ্যাপে থাকেন না।</string>
<string name="settings_charged_notification_label">চার্জ সম্পন্ন বিজ্ঞপ্তি</string>
<string name="settings_charged_notification_description">চার্জ হচ্ছে এমন সবকিছু লক্ষ্যমাত্রা চার্জ স্তরে পৌঁছালে একটি বিজ্ঞপ্তি দেখান।</string>
<string name="settings_charged_threshold_label">লক্ষ্যমাত্রা চার্জ স্তর</string>
<string name="settings_charged_scope_label">পর্যবেক্ষণ করা ব্যাটারি</string>
<string name="settings_charged_scope_pods_label">শুধুমাত্র পড</string>
<string name="settings_charged_scope_case_label">শুধুমাত্র কেস</string>
<string name="settings_charged_scope_both_label">পড এবং কেস</string>
<string name="device_settings_experimental_title">পরীক্ষামূলক ফিচার</string>
<string name="device_settings_experimental_description">এই ফিচারটি এখনো সব ডিভাইসে পরীক্ষা করা হয়নি। যদি কিছু সঠিকভাবে কাজ না করে, দয়া করে একটি ডিবাগ লগ সহ একটি ইস্যু খুলুন।</string>
<string name="device_settings_experimental_action">ইস্যু ট্র্যাকার খুলুন</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">ডিবাগ</string>
<string name="settings_general_label">সেটিংস</string>
<string name="settings_general_description">পুরো অ্যাপকে প্রভাবিত করে এমন সাধারণ পরিবর্তন।</string>
<string name="settings_overview_hide_unmatched_label">অমিল ডিভাইস লুকান</string>
<string name="settings_overview_hide_unmatched_description">ওভারভিউতে কাছের এমন ডিভাইস দেখাবে না যেগুলো আপনার কোনো প্রোফাইলের সাথে মেলে না, যেমন অন্যদের AirPods।</string>
<string name="settings_acknowledgements_label">স্বীকৃতি</string>
<string name="settings_debug_autoreports_label">স্বয়ংক্রিয় বাগ রিপোর্ট</string>
<string name="settings_debug_autoreports_description">স্বয়ংক্রিয়ভাবে সমস্যাগুলি রিপোর্ট করে, যেমন অ্যাপ ক্র্যাশের বিবরণ যাতে আমি এটি কীভাবে ঠিক করতে পারি তা বের করতে পারি।</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth নিষ্ক্রিয়, এটি সক্রিয় করুন ;)</string>
<string name="overview_monitoring_active_label">ডিভাইসের জন্য পর্যবেক্ষণ চলছে</string>
<string name="overview_monitoring_active_description">নিশ্চিত করুন যে আপনার ডিভাইস কাছে আছে এবং সক্রিয়।</string>
<string name="overview_troubleshoot_suggestion_label">সংযুক্ত, কিন্তু কোনো ডেটা নেই</string>
<string name="overview_troubleshoot_suggestion_description">আপনার ডিভাইসটি সংযুক্ত, কিন্তু CAPod এটি থেকে কোনো লাইভ ডেটা পাচ্ছে না। আপনার ফোনের একটি সামঞ্জস্যতা বিকল্পের প্রয়োজন হতে পারে — সমস্যা সমাধানকারী স্বয়ংক্রিয়ভাবে একটি খুঁজে পেতে চেষ্টা করতে পারে।</string>
<string name="overview_troubleshoot_suggestion_action">সমস্যা সমাধানকারী চালান</string>
<string name="overview_unmatched_devices_label">অমিলিত ডিভাইস</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">মিলিত প্রোফাইল ছাড়া %d ডিভাইস</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">ঘুম শনাক্তকরণ</string>
<string name="reaction_sleep_notification_title">ঘুম শনাক্তকরণ দ্বারা বিরতি দেওয়া হয়েছে</string>
<string name="reaction_sleep_notification_text">%1$s জানিয়েছে আপনি ঘুমিয়ে পড়েছেন, তাই আপনার সঙ্গীত বিরতি দেওয়া হয়েছে। আপনি ডিভাইস সেটিংসে এটি নিষ্ক্রিয় করতে পারেন।</string>
<string name="reaction_charged_channel_label">চার্জ সম্পন্ন বিজ্ঞপ্তি</string>
<string name="reaction_charged_notification_title">চার্জিং সম্পন্ন</string>
<string name="reaction_charged_notification_text_full">%1$s সম্পূর্ণ চার্জ হয়েছে।</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% পর্যন্ত চার্জ হয়েছে।</string>
<string name="device_settings_rename_label">নাম বদলান</string>
<string name="device_settings_rename_hint">ডিভাইসের নাম</string>
<string name="device_settings_rename_confirm">নাম বদলান</string>
+22 -6
View File
@@ -47,9 +47,9 @@
<string name="settings_autopause_label">Pausa automàtica</string>
<string name="settings_autopause_description">Pausa l\'àudio quan ús tragueu el dispositiu de l\'orella.</string>
<string name="settings_autopplay_label">Reproducció automàtica</string>
<string name="settings_autoplay_description">Repren la música quan tornes a posar-te els auriculars, però només si la pausa automàtica l\'havia aturat. Les pauses que has activat tu mateix (telèfon, pal dels AirPods, son) romanen en pausa.</string>
<string name="settings_start_music_on_wear_label">Inicia la música en posar-se els auriculars</string>
<string name="settings_start_music_on_wear_description">Sempre intenta reproduir música quan et poses els auriculars, fins i tot després d\'una pausa manual.</string>
<string name="settings_autoplay_description">Reprèn la música quan torneu a posar-vos els auriculars, però només si la pausa automàtica l\'havia aturat. Les pauses que heu activat vos mateix (telèfon, pliques dels AirPods, son) romanen en pausa.</string>
<string name="settings_start_music_on_wear_label">Inicia la música en posar-vos els auriculars</string>
<string name="settings_start_music_on_wear_description">Sempre intenta reproduir música quan us poseu els auriculars, fins i tot després d\'una pausa manual.</string>
<string name="settings_eardetection_info_label">Nota de detecció de l\'oïda</string>
<string name="settings_eardetection_info_description">Si la detecció de l\'oïda només funciona per a un auricular, això és degut a una limitació d\'Apple. Només es detecta «l\'auricular principal» (utilitzat per al micròfon). Configureu-ho en dispositius Apple: Configuració → Bluetooth → AirPods → Micròfon.</string>
<string name="settings_signal_minimum_label">Qualitat de senyal mínima</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostra la finestra emergent de connexió</string>
<string name="settings_popup_connected_description">Mostra una finestra emergent quan el dispositiu es connecti per primera vegada.</string>
<string name="settings_popup_info_not_in_app">Les finestres emergents només es mostren quan no esteu a l\'aplicació.</string>
<string name="settings_charged_notification_label">Notificació de càrrega completa</string>
<string name="settings_charged_notification_description">Mostra una notificació quan tots els dispositius que s\'estiguin carregant arribin al nivell de càrrega desitjat.</string>
<string name="settings_charged_threshold_label">Nivell de càrrega objectiu</string>
<string name="settings_charged_scope_label">Bateries monitoritzades</string>
<string name="settings_charged_scope_pods_label">Només els auriculars</string>
<string name="settings_charged_scope_case_label">Només la funda</string>
<string name="settings_charged_scope_both_label">Auriculars i funda</string>
<string name="device_settings_experimental_title">Funció experimental</string>
<string name="device_settings_experimental_description">Aquesta funció encara no s\'ha provat a tots els dispositius. Si alguna cosa no funciona correctament, obriu una incidència amb un registre de depuració.</string>
<string name="device_settings_experimental_action">Obre el seguidor d\'incidències</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuració</string>
<string name="settings_general_label">Configuració</string>
<string name="settings_general_description">Configuracions generals que afecten a tota l\'aplicació.</string>
<string name="settings_overview_hide_unmatched_label">Amaga els dispositius no coincidents</string>
<string name="settings_overview_hide_unmatched_description">No mostris els dispositius propers que no coincideixen amb cap dels perfils a la vista general. P. ex. els AirPods daltres persones.</string>
<string name="settings_acknowledgements_label">Agraïments</string>
<string name="settings_debug_autoreports_label">Informes automàtics d\'errors</string>
<string name="settings_debug_autoreports_description">Informa automàticament de problemes. Per exemple: detalls sobre un bloqueig de l\'aplicació perquè pugui esbrinar com solucionar-ho.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">El Bluetooth està desactivat, activeu-lo ;)</string>
<string name="overview_monitoring_active_label">Monitorització de dispositius</string>
<string name="overview_monitoring_active_description">Assegureu-vos que el dispositiu estigui a prop i actiu.</string>
<string name="overview_troubleshoot_suggestion_label">Connectat, però sense dades</string>
<string name="overview_troubleshoot_suggestion_description">El dispositiu està connectat, però el CAPod no rep dades en directe. El telèfon pot necessitar una opció de compatibilitat: el solucionador de problemes pot intentar trobar-ne una automàticament.</string>
<string name="overview_troubleshoot_suggestion_action">Executa el solucionador de problemes</string>
<string name="overview_unmatched_devices_label">Dispositius no coincidents</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositiu sense perfil coincident</item>
@@ -248,8 +260,8 @@
<string name="anc_mode_transparency">Transparència</string>
<string name="anc_mode_adaptive">Adaptatiu</string>
<string name="conversation_awareness_label">Consciència de conversa</string>
<string name="settings_conversation_action_label">Quan comences a parlar</string>
<string name="settings_conversation_action_nothing_label">No facis res</string>
<string name="settings_conversation_action_label">Quan comenceu a parlar</string>
<string name="settings_conversation_action_nothing_label">No fer res</string>
<string name="settings_conversation_action_lower_volume_label">Baixa el volum</string>
<string name="settings_conversation_action_pause_label">Posa en pausa el reproductor</string>
<string name="settings_conversation_volume_reduction_label">Reducció del volum</string>
@@ -288,7 +300,7 @@
<string name="profiles_delete_action">Elimina</string>
<string name="profiles_basic_info_title">Informació del dispositiu</string>
<string name="profiles_basic_info_description">Configureu el nom del dispositiu, el model i l\'emparellament Bluetooth opcional.</string>
<string name="profiles_signal_quality_title">Qualitat de senyal mínima</string>
<string name="profiles_signal_quality_title">Qualitat mínima del senyal</string>
<string name="profiles_signal_quality_description">Només es detecten dispositius amb una intensitat de senyal superior a aquest llindar. Els valors més baixos augmenten el rang de detecció, però poden causar falsos positius. No configureu aquest valor massa alt: la recepció Bluetooth generalment és deficient i varia segons la distància i els obstacles.</string>
<string name="profiles_identitykey_label">Clau d\'identitat</string>
<string name="profilessettings_maindevice_identitykey_description">La clau de resolució d\'identitat (IRK) del dispositiu ajuda al CAPod a identificar-lo entre els dispositius propers.</string>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detecció del son</string>
<string name="reaction_sleep_notification_title">Pausat per la detecció del son</string>
<string name="reaction_sleep_notification_text">%1$s ha informat que us heu adormit, de manera que la vostra música s\'ha posat en pausa. Podeu desactivar-ho a la configuració del dispositiu.</string>
<string name="reaction_charged_channel_label">Notificació de càrrega completa</string>
<string name="reaction_charged_notification_title">Càrrega completada</string>
<string name="reaction_charged_notification_text_full">%1$s està totalment carregat.</string>
<string name="reaction_charged_notification_text_partial">%1$s s\'ha carregat fins al %2$d%%.</string>
<string name="device_settings_rename_label">Canvia el nom</string>
<string name="device_settings_rename_hint">Nom del dispositiu</string>
<string name="device_settings_rename_confirm">Canvia el nom</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Zobrazit vyskakovací okno při připojení</string>
<string name="settings_popup_connected_description">Zobrazit vyskakovací okno při prvním připojení zařízení.</string>
<string name="settings_popup_info_not_in_app">Vyskakovací okna jsou zobrazována pouze tehdy, když nejste v aplikaci.</string>
<string name="settings_charged_notification_label">Oznámení o nabití</string>
<string name="settings_charged_notification_description">Zobrazit oznámení, jakmile vše, co se nabíjí, dosáhne cílové úrovně nabití.</string>
<string name="settings_charged_threshold_label">Cílová úroveň nabití</string>
<string name="settings_charged_scope_label">Sledované baterie</string>
<string name="settings_charged_scope_pods_label">Pouze sluchátka</string>
<string name="settings_charged_scope_case_label">Pouze pouzdro</string>
<string name="settings_charged_scope_both_label">Sluchátka a pouzdro</string>
<string name="device_settings_experimental_title">Experimentální funkce</string>
<string name="device_settings_experimental_description">Tato funkce ještě nebyla testována na všech zařízeních. Pokud něco nefunguje správně, nahlaste problém s logem ladění.</string>
<string name="device_settings_experimental_action">Otevřít sledovač problémů</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Ladění</string>
<string name="settings_general_label">Nastavení</string>
<string name="settings_general_description">Obecná vylepšení, která ovlivňují celou aplikaci.</string>
<string name="settings_overview_hide_unmatched_label">Skrýt nepřiřazená zařízení</string>
<string name="settings_overview_hide_unmatched_description">V přehledu nezobrazovat blízká zařízení, která neodpovídají žádnému z vašich profilů, např. AirPods jiných lidí.</string>
<string name="settings_acknowledgements_label">Poděkování</string>
<string name="settings_debug_autoreports_label">Automatické hlášení chyb</string>
<string name="settings_debug_autoreports_description">Automatické hlášení chyb např. podrobnosti o pádech aplikace.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth je vypnuto, zapněte jej ;)</string>
<string name="overview_monitoring_active_label">Monitorování zařízení</string>
<string name="overview_monitoring_active_description">Ujistěte se, že je vaše zařízení v dosahu a aktivní.</string>
<string name="overview_troubleshoot_suggestion_label">Připojeno, ale žádná data</string>
<string name="overview_troubleshoot_suggestion_description">Zařízení je připojeno, ale CAPod od něj nepřijímá žádná živá data. Váš telefon může potřebovat možnost kompatibility — řešení problémů ji může zkusit najít automaticky.</string>
<string name="overview_troubleshoot_suggestion_action">Spustit řešení problémů</string>
<string name="overview_unmatched_devices_label">Nepřiřazená zařízení</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d zařízení bez odpovídajícího profilu</item>
@@ -500,6 +512,10 @@
<string name="reaction_sleep_channel_label">Detekce spánku</string>
<string name="reaction_sleep_notification_title">Pozastaveno detekcí spánku</string>
<string name="reaction_sleep_notification_text">%1$s oznámil, že jste usnuli, takže vaše hudba byla pozastavena. Toto můžete vypnout v nastavení zařízení.</string>
<string name="reaction_charged_channel_label">Oznámení o nabití</string>
<string name="reaction_charged_notification_title">Nabíjení dokončeno</string>
<string name="reaction_charged_notification_text_full">%1$s je plně nabito.</string>
<string name="reaction_charged_notification_text_partial">%1$s nabito na %2$d%%.</string>
<string name="device_settings_rename_label">Přejmenovat</string>
<string name="device_settings_rename_hint">Název zařízení</string>
<string name="device_settings_rename_confirm">Přejmenovat</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Vis forbindelses-pop op</string>
<string name="settings_popup_connected_description">Vis en pop op, når enheden tilsluttes for første gang.</string>
<string name="settings_popup_info_not_in_app">Pop-ups vises kun, når du ikke er i appen.</string>
<string name="settings_charged_notification_label">Opladt notifikation</string>
<string name="settings_charged_notification_description">Vis en notifikation, når alt der oplades når det ønskede opladningsniveau.</string>
<string name="settings_charged_threshold_label">Målopladningsniveau</string>
<string name="settings_charged_scope_label">Overvågede batterier</string>
<string name="settings_charged_scope_pods_label">Kun pods</string>
<string name="settings_charged_scope_case_label">Kun etui</string>
<string name="settings_charged_scope_both_label">Pods og etui</string>
<string name="device_settings_experimental_title">Eksperimentel funktion</string>
<string name="device_settings_experimental_description">Denne funktion er endnu ikke testet på alle enheder. Hvis noget ikke fungerer korrekt, bedes du åbne en sag med en fejlretningslog.</string>
<string name="device_settings_experimental_action">Åbn fejlsporer</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Fejlfinding</string>
<string name="settings_general_label">Indstillinger</string>
<string name="settings_general_description">Generelle justeringer, der påvirker hele appen.</string>
<string name="settings_overview_hide_unmatched_label">Skjul ikke-matchende enheder</string>
<string name="settings_overview_hide_unmatched_description">Vis ikke nærliggende enheder, der ikke matcher nogen af dine profiler i overblikkket, f.eks. andres AirPods.</string>
<string name="settings_acknowledgements_label">Anerkendelser</string>
<string name="settings_debug_autoreports_label">Automatiske fejlrapporter</string>
<string name="settings_debug_autoreports_description">Rapporterer automatisk problemer, f.eks. detaljer om et app-nedbrud, så jeg kan finde ud af, hvordan jeg løser det.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth er deaktiveret, aktivér det ;)</string>
<string name="overview_monitoring_active_label">Overvåger for enheder</string>
<string name="overview_monitoring_active_description">Sørg for, at din enhed er i nærheden og aktiv.</string>
<string name="overview_troubleshoot_suggestion_label">Forbundet, men ingen data</string>
<string name="overview_troubleshoot_suggestion_description">Din enhed er forbundet, men CAPod modtager ikke live data fra den. Din telefon har måske brug for en kompatibilitetsindstilling — fejlfinderen kan prøve at finde en automatisk.</string>
<string name="overview_troubleshoot_suggestion_action">Kør fejlfinder</string>
<string name="overview_unmatched_devices_label">Uparrede enheder</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d enhed uden matchende profil</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Søvnregistrering</string>
<string name="reaction_sleep_notification_title">Sat på pause af søvnregistrering</string>
<string name="reaction_sleep_notification_text">%1$s registrerede, at du faldt i søvn, så din musik blev sat på pause. Du kan deaktivere dette i enhedsindstillingerne.</string>
<string name="reaction_charged_channel_label">Opladt notifikation</string>
<string name="reaction_charged_notification_title">Opladning færdig</string>
<string name="reaction_charged_notification_text_full">%1$s er fuldt opladet.</string>
<string name="reaction_charged_notification_text_partial">%1$s er blevet opladet til %2$d%%.</string>
<string name="device_settings_rename_label">Omdøb</string>
<string name="device_settings_rename_hint">Enhedsnavn</string>
<string name="device_settings_rename_confirm">Omdøb</string>
+17 -1
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Verbindungs-Popup anzeigen</string>
<string name="settings_popup_connected_description">Zeigt ein Popup an, wenn das Gerät zum ersten Mal eine Verbindung herstellt.</string>
<string name="settings_popup_info_not_in_app">Popups werden nur angezeigt, wenn du nicht in der App bist.</string>
<string name="settings_charged_notification_label">Aufgeladen-Benachrichtigung</string>
<string name="settings_charged_notification_description">Zeigt eine Benachrichtigung an, sobald alles, was geladen wird, den Ziel-Ladestand erreicht.</string>
<string name="settings_charged_threshold_label">Ziel-Ladestand</string>
<string name="settings_charged_scope_label">Überwachte Akkus</string>
<string name="settings_charged_scope_pods_label">Nur Pods</string>
<string name="settings_charged_scope_case_label">Nur Case</string>
<string name="settings_charged_scope_both_label">Pods und Case</string>
<string name="device_settings_experimental_title">Experimentelle Funktion</string>
<string name="device_settings_experimental_description">Diese Funktion wurde noch nicht auf allen Geräten getestet. Wenn etwas nicht korrekt funktioniert, öffne bitte ein Issue mit einem Debug-Log.</string>
<string name="device_settings_experimental_action">Issue-Tracker öffnen</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Einstellungen</string>
<string name="settings_general_description">Allgemeine Optimierungen, die die gesamte App betreffen.</string>
<string name="settings_overview_hide_unmatched_label">Nicht zugeordnete Geräte ausblenden</string>
<string name="settings_overview_hide_unmatched_description">Geräte in der Nähe, die keinem deiner Profile entsprechen, werden in der Übersicht nicht angezeigt, z. B. AirPods anderer Personen.</string>
<string name="settings_acknowledgements_label">Danksagungen</string>
<string name="settings_debug_autoreports_label">Automatische Fehlerberichte</string>
<string name="settings_debug_autoreports_description">Meldet Probleme automatisch, z.B. Details zu einem App-Absturz, damit ich herausfinden kann, wie ich ihn beheben kann.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ist deaktiviert, aktiviere es ;)</string>
<string name="overview_monitoring_active_label">Überwachung für Geräte</string>
<string name="overview_monitoring_active_description">Stelle sicher, dass dein Gerät in der Nähe ist und aktiv ist.</string>
<string name="overview_troubleshoot_suggestion_label">Verbunden, aber keine Daten</string>
<string name="overview_troubleshoot_suggestion_description">Dein Gerät ist verbunden, aber CAPod empfängt keine Live-Daten davon. Dein Telefon benötigt möglicherweise eine Kompatibilitätsoption die Fehlerbehebung kann versuchen, automatisch eine zu finden.</string>
<string name="overview_troubleshoot_suggestion_action">Fehlerbehebung starten</string>
<string name="overview_unmatched_devices_label">Nicht zugeordnete Geräte</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d Gerät ohne passendes Profil</item>
@@ -468,7 +480,7 @@
<!-- New device settings -->
<string name="device_settings_category_general_label">Allgemein</string>
<string name="device_settings_microphone_mode_label">Mikrofon</string>
<string name="device_settings_microphone_mode_description">Welches Ohrstöpsel als Mikrofon verwendet wird</string>
<string name="device_settings_microphone_mode_description">Welcher Ohrstöpsel als Mikrofon verwendet wird</string>
<string name="device_settings_microphone_mode_auto">Automatisch</string>
<string name="device_settings_microphone_mode_right">Rechts</string>
<string name="device_settings_microphone_mode_left">Links</string>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Schlaferkennung</string>
<string name="reaction_sleep_notification_title">Pausiert durch Schlafmodus-Erkennung</string>
<string name="reaction_sleep_notification_text">%1$s hat erkannt, dass du eingeschlafen bist, daher wurde deine Musik pausiert. Du kannst dies in den Geräteeinstellungen deaktivieren.</string>
<string name="reaction_charged_channel_label">Aufgeladen-Benachrichtigung</string>
<string name="reaction_charged_notification_title">Laden abgeschlossen</string>
<string name="reaction_charged_notification_text_full">%1$s ist vollständig geladen.</string>
<string name="reaction_charged_notification_text_partial">%1$s wurde auf %2$d%% geladen.</string>
<string name="device_settings_rename_label">Umbenennen</string>
<string name="device_settings_rename_hint">Gerätename</string>
<string name="device_settings_rename_confirm">Umbenennen</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Εμφάνιση αναδυόμενου παραθύρου σύνδεσης</string>
<string name="settings_popup_connected_description">Εμφάνιση αναδυόμενου παραθύρου όταν η συσκευή συνδέεται για πρώτη φορά.</string>
<string name="settings_popup_info_not_in_app">Τα αναδυόμενα παράθυρα εμφανίζονται μόνο όταν δεν βρίσκεστε στην εφαρμογή.</string>
<string name="settings_charged_notification_label">Ειδοποίηση φόρτισης</string>
<string name="settings_charged_notification_description">Εμφάνιση ειδοποίησης μόλις όλα τα στοιχεία που φορτίζουν φτάσουν στο επιθυμητό επίπεδο φόρτισης.</string>
<string name="settings_charged_threshold_label">Επιθυμητό επίπεδο φόρτισης</string>
<string name="settings_charged_scope_label">Παρακολουθούμενες μπαταρίες</string>
<string name="settings_charged_scope_pods_label">Μόνο ακουστικά</string>
<string name="settings_charged_scope_case_label">Μόνο θήκη</string>
<string name="settings_charged_scope_both_label">Ακουστικά και θήκη</string>
<string name="device_settings_experimental_title">Πειραματική λειτουργία</string>
<string name="device_settings_experimental_description">Αυτή η λειτουργία δεν έχει δοκιμαστεί ακόμα σε όλες τις συσκευές. Αν κάτι δεν λειτουργεί σωστά, παρακαλώ ανοίξτε ένα ζήτημα με ένα αρχείο καταγραφής εντοπισμού σφαλμάτων.</string>
<string name="device_settings_experimental_action">Άνοιγμα Παρακολούθησης Ζητημάτων</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Αποσφαλμάτωση</string>
<string name="settings_general_label">Ρυθμίσεις</string>
<string name="settings_general_description">Γενικές τροποποιήσεις που επηρεάζουν ολόκληρη την εφαρμογή.</string>
<string name="settings_overview_hide_unmatched_label">Απόκρυψη μη αντιστοιχισμένων συσκευών</string>
<string name="settings_overview_hide_unmatched_description">Να μην εμφανίζονται κοντινές συσκευές που δεν αντιστοιχούν σε κανένα από τα προφίλ σου στην επισκόπηση, π.χ. τα AirPods άλλων ανθρώπων.</string>
<string name="settings_acknowledgements_label">Ευχαριστίες</string>
<string name="settings_debug_autoreports_label">Αυτόματες αναφορές σφαλμάτων</string>
<string name="settings_debug_autoreports_description">Αναφέρει αυτόματα προβλήματα, π.χ. λεπτομέρειες σχετικά με μια κατάρρευση της εφαρμογής, ώστε να μπορώ να καταλάβω πώς να το διορθώσω.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Το Bluetooth είναι απενεργοποιημένο, ενεργοποιήστε το ;)</string>
<string name="overview_monitoring_active_label">Παρακολούθηση συσκευών</string>
<string name="overview_monitoring_active_description">Βεβαιωθείτε ότι η συσκευή σας είναι κοντά και ενεργή.</string>
<string name="overview_troubleshoot_suggestion_label">Συνδέθηκε, αλλά χωρίς δεδομένα</string>
<string name="overview_troubleshoot_suggestion_description">Η συσκευή σου είναι συνδεδεμένη, αλλά το CAPod δεν λαμβάνει ζωντανά δεδομένα από αυτήν. Το τηλέφωνό σου μπορεί να χρειαστεί μια επιλογή συμβατότητας — ο εντοπισμός προβλημάτων μπορεί να προσπαθήσει να βρει μία αυτόματα.</string>
<string name="overview_troubleshoot_suggestion_action">Εκτέλεση εντοπισμού προβλημάτων</string>
<string name="overview_unmatched_devices_label">Μη αντιστοιχισμένες συσκευές</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d συσκευή χωρίς αντίστοιχο προφίλ</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Ανίχνευση Ύπνου</string>
<string name="reaction_sleep_notification_title">Σε παύση από την Ανίχνευση Ύπνου</string>
<string name="reaction_sleep_notification_text">%1$s ανέφερε ότι αποκοιμηθήκατε, οπότε η μουσική σας τέθηκε σε παύση. Μπορείτε να το απενεργοποιήσετε στις ρυθμίσεις συσκευής.</string>
<string name="reaction_charged_channel_label">Ειδοποίηση φόρτισης</string>
<string name="reaction_charged_notification_title">Η φόρτιση ολοκληρώθηκε</string>
<string name="reaction_charged_notification_text_full">Το %1$s έχει φορτιστεί πλήρως.</string>
<string name="reaction_charged_notification_text_partial">Το %1$s έχει φορτιστεί στο %2$d%%.</string>
<string name="device_settings_rename_label">Μετονομασία</string>
<string name="device_settings_rename_hint">Όνομα συσκευής</string>
<string name="device_settings_rename_confirm">Μετονομασία</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostrar pop-up de conexión</string>
<string name="settings_popup_connected_description">Mostrar un pop-up cuando el dispositivo se conecta por primera vez.</string>
<string name="settings_popup_info_not_in_app">Los popups solo se muestran cuando no estás en la app.</string>
<string name="settings_charged_notification_label">Notificación de carga completa</string>
<string name="settings_charged_notification_description">Muestra una notificación cuando todo lo que se está cargando alcanza el nivel de carga objetivo.</string>
<string name="settings_charged_threshold_label">Nivel de carga objetivo</string>
<string name="settings_charged_scope_label">Baterías monitoreadas</string>
<string name="settings_charged_scope_pods_label">Solo pods</string>
<string name="settings_charged_scope_case_label">Solo estuche</string>
<string name="settings_charged_scope_both_label">Pods y estuche</string>
<string name="device_settings_experimental_title">Función experimental</string>
<string name="device_settings_experimental_description">Esta función aún no se ha probado en todos los dispositivos. Si algo no funciona correctamente, por favor abrí un problema con un registro de depuración.</string>
<string name="device_settings_experimental_action">Abrir seguimiento de problemas</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuración</string>
<string name="settings_general_label">Ajustes</string>
<string name="settings_general_description">Ajustes generales que afectan a toda la app.</string>
<string name="settings_overview_hide_unmatched_label">Ocultar dispositivos no emparejados</string>
<string name="settings_overview_hide_unmatched_description">No mostrar en el resumen los dispositivos cercanos que no coincidan con ninguno de tus perfiles, p. ej., los AirPods de otras personas.</string>
<string name="settings_acknowledgements_label">Agradecimientos</string>
<string name="settings_debug_autoreports_label">Reportes automáticos de errores</string>
<string name="settings_debug_autoreports_description">Reporta problemas automáticamente, ej. detalles sobre un cierre inesperado de la app para que pueda averiguar cómo solucionarlo.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">El Bluetooth está desactivado, actívalo ;)</string>
<string name="overview_monitoring_active_label">Monitoreo de dispositivos</string>
<string name="overview_monitoring_active_description">Asegúrate de que tu dispositivo esté cerca y activo.</string>
<string name="overview_troubleshoot_suggestion_label">Conectado, pero sin datos</string>
<string name="overview_troubleshoot_suggestion_description">Tu dispositivo está conectado, pero CAPod no está recibiendo datos en tiempo real. Tu teléfono puede necesitar una opción de compatibilidad: el solucionador de problemas puede intentar encontrar una automáticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Ejecutar solucionador de problemas</string>
<string name="overview_unmatched_devices_label">Dispositivos no emparejados</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo sin perfil coincidente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detección de sueño</string>
<string name="reaction_sleep_notification_title">Pausado por Detección de sueño</string>
<string name="reaction_sleep_notification_text">%1$s informó que te quedaste dormido, por lo que tu música fue pausada. Podés desactivar esto en la configuración del dispositivo.</string>
<string name="reaction_charged_channel_label">Notificación de carga completa</string>
<string name="reaction_charged_notification_title">Carga completa</string>
<string name="reaction_charged_notification_text_full">%1$s está completamente cargado.</string>
<string name="reaction_charged_notification_text_partial">%1$s se ha cargado al %2$d%%.</string>
<string name="device_settings_rename_label">Renombrar</string>
<string name="device_settings_rename_hint">Nombre del dispositivo</string>
<string name="device_settings_rename_confirm">Renombrar</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostrar pop-up de conexión</string>
<string name="settings_popup_connected_description">Mostrar un pop-up cuando el dispositivo se conecta por primera vez.</string>
<string name="settings_popup_info_not_in_app">Las ventanas emergentes solo se muestran cuando no estás en la aplicación.</string>
<string name="settings_charged_notification_label">Notificación de carga completa</string>
<string name="settings_charged_notification_description">Muestra una notificación cuando todo lo que se está cargando alcanza el nivel de carga objetivo.</string>
<string name="settings_charged_threshold_label">Nivel de carga objetivo</string>
<string name="settings_charged_scope_label">Baterías monitoreadas</string>
<string name="settings_charged_scope_pods_label">Solo audífonos</string>
<string name="settings_charged_scope_case_label">Solo estuche</string>
<string name="settings_charged_scope_both_label">Audífonos y estuche</string>
<string name="device_settings_experimental_title">Función experimental</string>
<string name="device_settings_experimental_description">Esta función aún no ha sido probada en todos los dispositivos. Si algo no funciona correctamente, por favor abre un problema con un registro de depuración.</string>
<string name="device_settings_experimental_action">Abrir rastreador de problemas</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuración</string>
<string name="settings_general_label">Ajustes</string>
<string name="settings_general_description">Ajustes generales que afectan a toda la aplicación.</string>
<string name="settings_overview_hide_unmatched_label">Ocultar dispositivos no emparejados</string>
<string name="settings_overview_hide_unmatched_description">No mostrar dispositivos cercanos que no coincidan con ninguno de tus perfiles en el resumen, p. ej. los AirPods de otras personas.</string>
<string name="settings_acknowledgements_label">Agradecimientos</string>
<string name="settings_debug_autoreports_label">Reportes automáticos de errores</string>
<string name="settings_debug_autoreports_description">Reporta problemas automáticamente, ej. detalles sobre un cierre inesperado de la aplicación para que pueda averiguar cómo solucionarlo.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">El Bluetooth está desactivado, actívalo ;)</string>
<string name="overview_monitoring_active_label">Monitoreo de dispositivos</string>
<string name="overview_monitoring_active_description">Asegúrate de que tu dispositivo esté cerca y activo.</string>
<string name="overview_troubleshoot_suggestion_label">Conectado, pero sin datos</string>
<string name="overview_troubleshoot_suggestion_description">Tu dispositivo está conectado, pero CAPod no está recibiendo datos en tiempo real. Es posible que tu teléfono necesite una opción de compatibilidad — el solucionador de problemas puede intentar encontrar una automáticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Ejecutar solucionador de problemas</string>
<string name="overview_unmatched_devices_label">Dispositivos no emparejados</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo sin perfil coincidente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detección de sueño</string>
<string name="reaction_sleep_notification_title">Pausado por detección de sueño</string>
<string name="reaction_sleep_notification_text">%1$s detectó que te quedaste dormido, por lo que tu música fue pausada. Puedes desactivar esto en la configuración del dispositivo.</string>
<string name="reaction_charged_channel_label">Notificación de carga completa</string>
<string name="reaction_charged_notification_title">Carga completada</string>
<string name="reaction_charged_notification_text_full">%1$s está completamente cargado.</string>
<string name="reaction_charged_notification_text_partial">%1$s se ha cargado al %2$d%%.</string>
<string name="device_settings_rename_label">Renombrar</string>
<string name="device_settings_rename_hint">Nombre del dispositivo</string>
<string name="device_settings_rename_confirm">Renombrar</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostrar ventana emergente de conexión</string>
<string name="settings_popup_connected_description">Mostrar una ventana emergente cuando el dispositivo se conecta por primera vez.</string>
<string name="settings_popup_info_not_in_app">Los popups solo se muestran cuando no estás en la aplicación.</string>
<string name="settings_charged_notification_label">Notificación de carga completa</string>
<string name="settings_charged_notification_description">Mostrar una notificación cuando todo lo que se está cargando alcance el nivel de carga objetivo.</string>
<string name="settings_charged_threshold_label">Nivel de carga objetivo</string>
<string name="settings_charged_scope_label">Baterías supervisadas</string>
<string name="settings_charged_scope_pods_label">Solo auriculares</string>
<string name="settings_charged_scope_case_label">Solo funda</string>
<string name="settings_charged_scope_both_label">Auriculares y funda</string>
<string name="device_settings_experimental_title">Función experimental</string>
<string name="device_settings_experimental_description">Esta función aún no se ha probado en todos los dispositivos. Si algo no funciona correctamente, por favor abre una incidencia con un registro de depuración.</string>
<string name="device_settings_experimental_action">Abrir rastreador de incidencias</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuración</string>
<string name="settings_general_label">Ajustes</string>
<string name="settings_general_description">Ajustes generales que afectan a toda la aplicación.</string>
<string name="settings_overview_hide_unmatched_label">Ocultar dispositivos no reconocidos</string>
<string name="settings_overview_hide_unmatched_description">No mostrar en el resumen los dispositivos cercanos que no coincidan con ninguno de tus perfiles, p. ej. los AirPods de otras personas.</string>
<string name="settings_acknowledgements_label">Agradecimientos</string>
<string name="settings_debug_autoreports_label">Informes de error automáticos</string>
<string name="settings_debug_autoreports_description">Informa automáticamente de los problemas, p. ej., detalles sobre un fallo de la aplicación para que pueda averiguar cómo solucionarlo.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">El Bluetooth está desactivado, actívalo ;)</string>
<string name="overview_monitoring_active_label">Monitoreo de dispositivos</string>
<string name="overview_monitoring_active_description">Asegúrate de que tu dispositivo esté cerca y activo.</string>
<string name="overview_troubleshoot_suggestion_label">Conectado, pero sin datos</string>
<string name="overview_troubleshoot_suggestion_description">Tu dispositivo está conectado, pero CAPod no está recibiendo datos en directo. Es posible que tu teléfono necesite una opción de compatibilidad: el solucionador de problemas puede intentar encontrar una automáticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Ejecutar solucionador de problemas</string>
<string name="overview_unmatched_devices_label">Dispositivos no emparejados</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo sin perfil coincidente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detección de sueño</string>
<string name="reaction_sleep_notification_title">Pausado por detección de sueño</string>
<string name="reaction_sleep_notification_text">%1$s informó que te quedaste dormido, por lo que tu música fue pausada. Puedes desactivar esto en la configuración del dispositivo.</string>
<string name="reaction_charged_channel_label">Notificación de carga completa</string>
<string name="reaction_charged_notification_title">Carga completada</string>
<string name="reaction_charged_notification_text_full">%1$s está completamente cargado.</string>
<string name="reaction_charged_notification_text_partial">%1$s se ha cargado al %2$d%%.</string>
<string name="device_settings_rename_label">Renombrar</string>
<string name="device_settings_rename_hint">Nombre del dispositivo</string>
<string name="device_settings_rename_confirm">Renombrar</string>
+24 -8
View File
@@ -47,9 +47,9 @@
<string name="settings_autopause_label">Automaatne peatamine</string>
<string name="settings_autopause_description">Seadme kõrvast eemaldamisel peata esitamine.</string>
<string name="settings_autopplay_label">Automaatne esitamine</string>
<string name="settings_autoplay_description">Jätka muusika esitust, kui kõrvaklapid jälle seljas, kuid ainult siis, kui Auto-paus selle peatas. Pausid, mille tegid ise (telefon, AirPodsi vars, uni), jäävad pausi peale.</string>
<string name="settings_start_music_on_wear_label">Käivita muusika kandmisel</string>
<string name="settings_start_music_on_wear_description">Proovib alati mängida muusikat, kui paned kõrvaklapid pähe, isegi pärast käsitsi pausi.</string>
<string name="settings_autoplay_description">Jätka muusika kuulamist, kui kannad taas kõrvaklappe, kuid ainult siis, kui isekäivitunud paus selle peatas. Isepausimise (telefon, AirPodsi vars, uni) puhul jääb paus kestma.</string>
<string name="settings_start_music_on_wear_label">Esita muusikat kõrva panemisel</string>
<string name="settings_start_music_on_wear_description">Proovib alati esitada muusikat, kui paned kõrvaklapid pähe, isegi pärast enda käivitatud pausi.</string>
<string name="settings_eardetection_info_label">Kõrva tuvastamisest</string>
<string name="settings_eardetection_info_description">Kui tuvastatakse vaid üks klapp, siis seda põhjustab Apple\'i piirang. Tuvastatakse vaid peamine klapp (kasutatakse mikrofonina). Seadista Apple\'i seadmetes: Seaded (Settings) → Bluetooth → AirPods (AirPodid) → Mikrofon (Microphone).</string>
<string name="settings_signal_minimum_label">Väikseim signaali kvaliteet</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Näita ühenduse hüpikakent</string>
<string name="settings_popup_connected_description">Näita seadme esmaühendumisel hüpikakent.</string>
<string name="settings_popup_info_not_in_app">Hüpikaknad kuvatakse ainult siis, kui sa pole rakenduses.</string>
<string name="settings_charged_notification_label">Laetud teatis</string>
<string name="settings_charged_notification_description">Kuva teatis, kui kõik laadimise all olevad seadmed jõuavad sihitud laetuse tasemele.</string>
<string name="settings_charged_threshold_label">Sihitud laetuse tase</string>
<string name="settings_charged_scope_label">Jälgitavad akud</string>
<string name="settings_charged_scope_pods_label">Ainult kõrvaklapid</string>
<string name="settings_charged_scope_case_label">Ainult ümbris</string>
<string name="settings_charged_scope_both_label">Kõrvaklapid ja ümbris</string>
<string name="device_settings_experimental_title">Katsetamisel</string>
<string name="device_settings_experimental_description">Seda pole kõigil seadmetel veel katsetatud. Kui midagi ei toimi õigesti, avage probleem koos silumislogi failiga.</string>
<string name="device_settings_experimental_action">Ava probleemide jälgija</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Silumine</string>
<string name="settings_general_label">Seaded</string>
<string name="settings_general_description">Kogu rakendust mõjutavad üldseaded.</string>
<string name="settings_overview_hide_unmatched_label">Peida mittevastavad seadmed</string>
<string name="settings_overview_hide_unmatched_description">Ära näita ülevaates lähedalasuvaid seadmeid, mis ei vasta ühelegi sinu profiilile, nt teiste inimeste AirPods.</string>
<string name="settings_acknowledgements_label">Tunnustused</string>
<string name="settings_debug_autoreports_label">Automaatsed veateated</string>
<string name="settings_debug_autoreports_description">Teavitab vigadest ise, nt andmed rakenduse hangumise kohta, et saaksin mõista, kuidas olukorda lahendada.</string>
@@ -127,13 +136,13 @@
<string name="anc_widget_config_aap_required_hint">See vidin nõuab otsest ühendust (AAP) teie seadmega. Enne selle vidina kasutamist veenduge, et teie seade on rakenduses seotud ja ühendatud.</string>
<string name="anc_widget_no_anc_support_label">See seade ei toeta mürakontrolli</string>
<string name="anc_widget_aap_not_connected_label">Ühendus puudub</string>
<string name="anc_widget_aap_not_connected_nearby_description">Lähedal, kuid ei ole ühendatud</string>
<string name="anc_widget_aap_not_connected_nearby_description">Lähedal, kuid pole ühendatud</string>
<string name="anc_widget_aap_not_connected_not_nearby_description">Pole lähedal</string>
<string name="anc_widget_aap_connecting_label">Ühendamine…</string>
<string name="tile_anc_label">Mürakontroll</string>
<string name="tile_anc_subtitle_permission_required">Luba nõutud</string>
<string name="tile_anc_subtitle_permission_required">Vaja on luba</string>
<string name="tile_anc_subtitle_no_device">Puudub seade</string>
<string name="tile_anc_subtitle_no_anc_support">Mürakontroll puudub</string>
<string name="tile_anc_subtitle_no_anc_support">Puudub mürakontroll</string>
<string name="tile_anc_subtitle_bluetooth_off">Bluetooth väljas</string>
<string name="widget_config_screen_title">Vidina seadistus</string>
<string name="widget_configuration_title">Vali seade</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth on keelatud, lubage see ;)</string>
<string name="overview_monitoring_active_label">Seadmete jälgimine</string>
<string name="overview_monitoring_active_description">Veenduge, et seade oleks läheduses ja kasutusel.</string>
<string name="overview_troubleshoot_suggestion_label">Ühendatud, kuid andmeid pole</string>
<string name="overview_troubleshoot_suggestion_description">Seade on ühendatud, kuid CAPod ei saa sellelt otseandmeid. Telefon vajab tõenäoliselt ühilduvuse valikut — trikijär kontrollib, kas suudab selle automaatselt leida.</string>
<string name="overview_troubleshoot_suggestion_action">Käivita trikijär</string>
<string name="overview_unmatched_devices_label">Omavahel sobimatud seadmed</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d seade ei kattu profiiliga</item>
@@ -250,7 +262,7 @@
<string name="conversation_awareness_label">Vestluse tuvastamine</string>
<string name="settings_conversation_action_label">Kui alustad rääkimist</string>
<string name="settings_conversation_action_nothing_label">Ära tee midagi</string>
<string name="settings_conversation_action_lower_volume_label">Alanda helitugevust</string>
<string name="settings_conversation_action_lower_volume_label">Vähenda helitugevust</string>
<string name="settings_conversation_action_pause_label">Peata meedia</string>
<string name="settings_conversation_volume_reduction_label">Helitugevuse vähendamine</string>
<string name="signal_badge_ble_cd">BLE skannimine aktiivne</string>
@@ -468,7 +480,7 @@
<!-- New device settings -->
<string name="device_settings_category_general_label">Üldine</string>
<string name="device_settings_microphone_mode_label">Mikrofon</string>
<string name="device_settings_microphone_mode_description">Millist kõrvaklappi kasutatakse mikrofonina</string>
<string name="device_settings_microphone_mode_description">Kumba kõrvaklappi kasutatakse mikrofonina</string>
<string name="device_settings_microphone_mode_auto">Automaatne</string>
<string name="device_settings_microphone_mode_right">Parem</string>
<string name="device_settings_microphone_mode_left">Vasak</string>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Une tuvastamine</string>
<string name="reaction_sleep_notification_title">Uinumise tõttu peatatud</string>
<string name="reaction_sleep_notification_text">%1$s teatas, et uinusite, seega muusika vaikis. Saate selle seadme seadetes keelata.</string>
<string name="reaction_charged_channel_label">Laetud teatis</string>
<string name="reaction_charged_notification_title">Laadimine lõpetatud</string>
<string name="reaction_charged_notification_text_full">%1$s on täielikult laetud.</string>
<string name="reaction_charged_notification_text_partial">%1$s on laetud %2$d%%-ni.</string>
<string name="device_settings_rename_label">Nimeta ümber</string>
<string name="device_settings_rename_hint">Seadme nimi</string>
<string name="device_settings_rename_confirm">Nimeta ümber</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Erakutsi konexioaren pop-up-a</string>
<string name="settings_popup_connected_description">Erakutsi pop-up bat gailua lehen aldiz konektatzen denean.</string>
<string name="settings_popup_info_not_in_app">Leiho gainerakorrak soilik erakusten dira aplikazioan ez zaudenerako.</string>
<string name="settings_charged_notification_label">Kargatutako jakinarazpena</string>
<string name="settings_charged_notification_description">Erakutsi jakinarazpen bat kargatzen ari den guztia helburuko karga-maila lortzen duenean.</string>
<string name="settings_charged_threshold_label">Helburuko karga-maila</string>
<string name="settings_charged_scope_label">Monitorizatutako bateriak</string>
<string name="settings_charged_scope_pods_label">Podak soilik</string>
<string name="settings_charged_scope_case_label">Kaxa soilik</string>
<string name="settings_charged_scope_both_label">Podak eta kaxa</string>
<string name="device_settings_experimental_title">Funtzio esperimentala</string>
<string name="device_settings_experimental_description">Funtzio hau oraindik ez da gailu guztietan probatu. Zerbait ondo funtzionatzen ez badu, mesedez ireki arazo bat arazketa-erregistroarekin.</string>
<string name="device_settings_experimental_action">Ireki arazo-jarraipena</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Arazketa</string>
<string name="settings_general_label">Ezarpenak</string>
<string name="settings_general_description">Aplikazio osoari eragiten dioten doikuntza orokorrak.</string>
<string name="settings_overview_hide_unmatched_label">Ezkutatu bat ez datozen gailuak</string>
<string name="settings_overview_hide_unmatched_description">Ez erakutsi ikuspegiaren inguruan dauden eta zure profilekin bat ez datozen gailuak, esaterako, beste pertsonen AirPods-ak.</string>
<string name="settings_acknowledgements_label">Eskertzak</string>
<string name="settings_debug_autoreports_label">Erroreen txosten automatikoak</string>
<string name="settings_debug_autoreports_description">Automatikoki arazoak salatzen ditu, adib. aplikazioaren kraskaduraren xehetasunak, konpontzen jakin dezadan.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth-a desgaituta dago, gaitu ezazu ;)</string>
<string name="overview_monitoring_active_label">Gailuen jarraipena</string>
<string name="overview_monitoring_active_description">Ziurtatu zure gailua gertuan eta aktibo dagoela.</string>
<string name="overview_troubleshoot_suggestion_label">Konektatuta, baina daturik ez</string>
<string name="overview_troubleshoot_suggestion_description">Zure gailua konektatuta dago, baina CAPod-ek ez du zuzeneko daturik jasotzen. Baliteke zure telefonoak bateragarritasun-aukera bat behar izatea — arazo-konpontzaileak automatikoki bila dezake.</string>
<string name="overview_troubleshoot_suggestion_action">Exekutatu arazo-konpontzailea</string>
<string name="overview_unmatched_devices_label">Bat ez datozen gailuak</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d gailu bat datorren profilik gabe</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Lo Detekzioa</string>
<string name="reaction_sleep_notification_title">Lo Detekzioak Pausatuta</string>
<string name="reaction_sleep_notification_text">%1$s-ek jakinarazi du lo geratu zarela, eta musikak pausatu egin zen. Gailu-ezarpenetan desgaitu dezakezu.</string>
<string name="reaction_charged_channel_label">Kargatutako jakinarazpena</string>
<string name="reaction_charged_notification_title">Karga osatu da</string>
<string name="reaction_charged_notification_text_full">%1$s guztiz kargatuta dago.</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%%-era kargatu da.</string>
<string name="device_settings_rename_label">Berrizendatu</string>
<string name="device_settings_rename_hint">Gailuaren izena</string>
<string name="device_settings_rename_confirm">Berrizendatu</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">نمایش پاپ‌آپ اتصال</string>
<string name="settings_popup_connected_description">هنگام اتصال دستگاه برای اولین بار، یک پاپ‌آپ نشان داده شود.</string>
<string name="settings_popup_info_not_in_app">پنجره‌های بازشو فقط زمانی نشان داده می‌شوند که در برنامه نباشید.</string>
<string name="settings_charged_notification_label">اعلان شارژ کامل</string>
<string name="settings_charged_notification_description">پس از اینکه همه چیزهایی که در حال شارژ هستند به سطح شارژ هدف رسیدند، یک اعلان نمایش داده می‌شود.</string>
<string name="settings_charged_threshold_label">سطح شارژ هدف</string>
<string name="settings_charged_scope_label">باتری‌های تحت نظارت</string>
<string name="settings_charged_scope_pods_label">فقط پادها</string>
<string name="settings_charged_scope_case_label">فقط کیس</string>
<string name="settings_charged_scope_both_label">پادها و کیس</string>
<string name="device_settings_experimental_title">ویژگی آزمایشی</string>
<string name="device_settings_experimental_description">این ویژگی هنوز روی همه دستگاه‌ها آزمایش نشده است. اگر چیزی درست کار نمی‌کند، لطفاً یک گزارش خطا با لاگ دیباگ باز کنید.</string>
<string name="device_settings_experimental_action">باز کردن ردیاب مشکلات</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">اشکال‌زدایی</string>
<string name="settings_general_label">تنظیمات</string>
<string name="settings_general_description">تنظیمات کلی که بر کل برنامه تأثیر می‌گذارند.</string>
<string name="settings_overview_hide_unmatched_label">پنهان کردن دستگاه‌های نامتناسب</string>
<string name="settings_overview_hide_unmatched_description">دستگاه‌های نزدیکی که با هیچ‌کدام از پروفایل‌های شما تطابق ندارند در نمای کلی نمایش داده نمی‌شوند، مثلاً AirPods دیگران.</string>
<string name="settings_acknowledgements_label">قدردانی‌ها</string>
<string name="settings_debug_autoreports_label">گزارش‌های خطای خودکار</string>
<string name="settings_debug_autoreports_description">مشکلات را به‌طور خودکار گزارش می‌دهد، مثلاً جزئیات مربوط به خرابی برنامه تا بتوانم نحوه رفع آن را بفهمم.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">بلوتوث غیرفعال است، آن را فعال کنید ;)</string>
<string name="overview_monitoring_active_label">نظارت بر دستگاه‌ها</string>
<string name="overview_monitoring_active_description">مطمئن شوید دستگاه شما نزدیک و فعال است.</string>
<string name="overview_troubleshoot_suggestion_label">متصل است، اما داده‌ای وجود ندارد</string>
<string name="overview_troubleshoot_suggestion_description">دستگاه شما متصل است، اما CAPod هیچ داده زنده‌ای از آن دریافت نمی‌کند. ممکن است تلفن شما به یک گزینه سازگاری نیاز داشته باشد — عیب‌یاب می‌تواند به‌طور خودکار تلاش کند آن را پیدا کند.</string>
<string name="overview_troubleshoot_suggestion_action">اجرای عیب‌یاب</string>
<string name="overview_unmatched_devices_label">دستگاه‌های بدون تطابق</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d دستگاه بدون پروفایل منطبق</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">تشخیص خواب</string>
<string name="reaction_sleep_notification_title">توسط تشخیص خواب متوقف شد</string>
<string name="reaction_sleep_notification_text">%1$s گزارش داد که به خواب رفتید، بنابراین موسیقی شما متوقف شد. می‌توانید این را در تنظیمات دستگاه غیرفعال کنید.</string>
<string name="reaction_charged_channel_label">اعلان شارژ کامل</string>
<string name="reaction_charged_notification_title">شارژ کامل شد</string>
<string name="reaction_charged_notification_text_full">%1$s کاملاً شارژ شده است.</string>
<string name="reaction_charged_notification_text_partial">%1$s تا %2$d%% شارژ شده است.</string>
<string name="device_settings_rename_label">تغییر نام</string>
<string name="device_settings_rename_hint">نام دستگاه</string>
<string name="device_settings_rename_confirm">تغییر نام</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Näytä yhteyden ponnahdusikkuna</string>
<string name="settings_popup_connected_description">Näytä ponnahdusikkuna, kun laite yhdistetään ensimmäisen kerran.</string>
<string name="settings_popup_info_not_in_app">Ponnahdusikkunat näytetään vain, kun et ole sovelluksessa.</string>
<string name="settings_charged_notification_label">Latausilmoitus</string>
<string name="settings_charged_notification_description">Näytä ilmoitus, kun kaikki ladattavat laitteet saavuttavat tavoitelataustason.</string>
<string name="settings_charged_threshold_label">Tavoitelataustaso</string>
<string name="settings_charged_scope_label">Seurattavat akut</string>
<string name="settings_charged_scope_pods_label">Vain nappikuulokkeet</string>
<string name="settings_charged_scope_case_label">Vain kotelo</string>
<string name="settings_charged_scope_both_label">Nappikuulokkeet ja kotelo</string>
<string name="device_settings_experimental_title">Kokeellinen ominaisuus</string>
<string name="device_settings_experimental_description">Tätä ominaisuutta ei ole vielä testattu kaikilla laitteilla. Jos jokin ei toimi oikein, avaa ongelmaraportti virheenkorjauslokilla.</string>
<string name="device_settings_experimental_action">Avaa ongelmaseuranta</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Virheenjäljitys</string>
<string name="settings_general_label">Asetukset</string>
<string name="settings_general_description">Yleiset säädöt, jotka vaikuttavat koko sovellukseen.</string>
<string name="settings_overview_hide_unmatched_label">Piilota yhteensopimattomat laitteet</string>
<string name="settings_overview_hide_unmatched_description">Älä näytä lähistöllä olevia laitteita, jotka eivät vastaa mitään profiileistasi yleiskatsauksessa, esim. muiden ihmisten AirPodseja.</string>
<string name="settings_acknowledgements_label">Kiitokset</string>
<string name="settings_debug_autoreports_label">Automaattiset virheraportit</string>
<string name="settings_debug_autoreports_description">Raportoi ongelmat automaattisesti, esim. tiedot sovelluksen kaatumisesta, jotta voin selvittää, miten se korjataan.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth on pois käytöstä, ota se käyttöön ;)</string>
<string name="overview_monitoring_active_label">Etsitään laitteita</string>
<string name="overview_monitoring_active_description">Varmista, että laitteesi on lähellä ja aktiivinen.</string>
<string name="overview_troubleshoot_suggestion_label">Yhdistetty, mutta ei dataa</string>
<string name="overview_troubleshoot_suggestion_description">Laitteesi on yhdistetty, mutta CAPod ei vastaanota siitä reaaliaikaista dataa. Puhelimesi saattaa tarvita yhteensopivuusasetuksen — vianmääritys voi yrittää löytää sellaisen automaattisesti.</string>
<string name="overview_troubleshoot_suggestion_action">Käynnistä vianmääritys</string>
<string name="overview_unmatched_devices_label">Vastaavuudetta olevat laitteet</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d laite ilman vastaavaa profiilia</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Unitunnistus</string>
<string name="reaction_sleep_notification_title">Unitunnistus keskeytti toiston</string>
<string name="reaction_sleep_notification_text">%1$s havaitsi sinun nukahtaneen, joten musiikkisi keskeytettiin. Voit poistaa tämän käytöstä laiteasetuksista.</string>
<string name="reaction_charged_channel_label">Latausilmoitus</string>
<string name="reaction_charged_notification_title">Lataus valmis</string>
<string name="reaction_charged_notification_text_full">%1$s on täyteen ladattu.</string>
<string name="reaction_charged_notification_text_partial">%1$s on ladattu %2$d%%:iin.</string>
<string name="device_settings_rename_label">Nimeä uudelleen</string>
<string name="device_settings_rename_hint">Laitteen nimi</string>
<string name="device_settings_rename_confirm">Nimeä uudelleen</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Ipakita ang connection popup</string>
<string name="settings_popup_connected_description">Magpakita ng popup kapag unang kumonekta ang device.</string>
<string name="settings_popup_info_not_in_app">Ang mga popup ay ipinapakita lamang kapag wala ka sa app.</string>
<string name="settings_charged_notification_label">Notipikasyon ng pagkakarga</string>
<string name="settings_charged_notification_description">Magpakita ng notipikasyon kapag ang lahat ng nagcha-charge ay umabot na sa target na antas ng karga.</string>
<string name="settings_charged_threshold_label">Target na antas ng karga</string>
<string name="settings_charged_scope_label">Mga sinusubaybaygang baterya</string>
<string name="settings_charged_scope_pods_label">Mga pod lamang</string>
<string name="settings_charged_scope_case_label">Case lamang</string>
<string name="settings_charged_scope_both_label">Mga pod at case</string>
<string name="device_settings_experimental_title">Pang-eksperimentong tampok</string>
<string name="device_settings_experimental_description">Ang tampok na ito ay hindi pa nasubok sa lahat ng device. Kung may hindi gumagana nang tama, mangyaring magbukas ng isyu na may debug log.</string>
<string name="device_settings_experimental_action">Buksan ang Issue Tracker</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Mga Setting</string>
<string name="settings_general_description">Mga pangkalahatang pag-aayos na nakakaapekto sa buong app.</string>
<string name="settings_overview_hide_unmatched_label">Itago ang mga hindi tugmang device</string>
<string name="settings_overview_hide_unmatched_description">Huwag ipakita ang mga kalapit na device na hindi tugma sa alinman sa iyong mga profile sa pangkalahatang-tanaw, hal. ang mga AirPods ng ibang tao.</string>
<string name="settings_acknowledgements_label">Mga Pasasalamat</string>
<string name="settings_debug_autoreports_label">Mga awtomatikong ulat ng bug</string>
<string name="settings_debug_autoreports_description">Awtomatikong nag-uulat ng mga isyu, hal. mga detalye sa isang pag-crash ng app para malaman ko kung paano ito ayusin.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Naka-disable ang Bluetooth, i-enable ito ;)</string>
<string name="overview_monitoring_active_label">Nagmo-monitor ng mga device</string>
<string name="overview_monitoring_active_description">Siguraduhing malapit at aktibo ang iyong device.</string>
<string name="overview_troubleshoot_suggestion_label">Nakakonekta, ngunit walang data</string>
<string name="overview_troubleshoot_suggestion_description">Nakakonekta ang iyong device, ngunit hindi nakakatanggap ng live data ang CAPod mula rito. Maaaring kailanganin ng iyong telepono ng opsyon sa compatibility — maaaring subukang hanapin ito nang awtomatiko ng troubleshooter.</string>
<string name="overview_troubleshoot_suggestion_action">Patakbuhin ang troubleshooter</string>
<string name="overview_unmatched_devices_label">Mga hindi nakatugmang device</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d device na walang katugmang profile</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Pagtuklas ng Pagtulog</string>
<string name="reaction_sleep_notification_title">Naka-pause ng Pagtuklas ng Pagtulog</string>
<string name="reaction_sleep_notification_text">Naiulat ng %1$s na nakatulog ka, kaya na-pause ang iyong musika. Maaari mong i-disable ito sa mga setting ng device.</string>
<string name="reaction_charged_channel_label">Notipikasyon ng Pagkakarga</string>
<string name="reaction_charged_notification_title">Kumpleto na ang pag-charge</string>
<string name="reaction_charged_notification_text_full">Ganap na na-charge ang %1$s.</string>
<string name="reaction_charged_notification_text_partial">Na-charge na ang %1$s sa %2$d%%.</string>
<string name="device_settings_rename_label">Palitan ang Pangalan</string>
<string name="device_settings_rename_hint">Pangalan ng device</string>
<string name="device_settings_rename_confirm">Palitan ang Pangalan</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Afficher une fenêtre de connection</string>
<string name="settings_popup_connected_description">Afficher une fenêtre contextuelle quand lappareil se connecte pour la première fois.</string>
<string name="settings_popup_info_not_in_app">Les popups ne sont affichées que lorsque vous n\'êtes pas dans l\'application.</string>
<string name="settings_charged_notification_label">Notification de charge complète</string>
<string name="settings_charged_notification_description">Afficher une notification une fois que tout ce qui est en charge atteint le niveau de charge cible.</string>
<string name="settings_charged_threshold_label">Niveau de charge cible</string>
<string name="settings_charged_scope_label">Batteries surveillées</string>
<string name="settings_charged_scope_pods_label">Écouteurs uniquement</string>
<string name="settings_charged_scope_case_label">Boîtier uniquement</string>
<string name="settings_charged_scope_both_label">Écouteurs et boîtier</string>
<string name="device_settings_experimental_title">Fonctionnalité expérimentale</string>
<string name="device_settings_experimental_description">Cette fonctionnalité n\'a pas encore été testée sur tous les appareils. Si quelque chose ne fonctionne pas correctement, veuillez ouvrir un ticket avec un journal de débogage.</string>
<string name="device_settings_experimental_action">Ouvrir le suivi des problèmes</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Débogage</string>
<string name="settings_general_label">Paramètres</string>
<string name="settings_general_description">Réglage généraux qui affectent l\'appli entière.</string>
<string name="settings_overview_hide_unmatched_label">Masquer les appareils sans correspondance</string>
<string name="settings_overview_hide_unmatched_description">Ne pas afficher dans laperçu les appareils à proximité qui ne correspondent à aucun de vos profils, p. ex. les AirPods dautres personnes.</string>
<string name="settings_acknowledgements_label">Remerciements</string>
<string name="settings_debug_autoreports_label">Relevés de bogue automatiques</string>
<string name="settings_debug_autoreports_description">Signale automatiquement les problèmes, p. ex., les détails dun plantage de lappli, afin que je puisse essayer de les corriger.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth est désactivé, activez-le ;)</string>
<string name="overview_monitoring_active_label">Surveillance des appareils</string>
<string name="overview_monitoring_active_description">Assurez-vous que votre appareil est proche et actif.</string>
<string name="overview_troubleshoot_suggestion_label">Connecté, mais aucune donnée</string>
<string name="overview_troubleshoot_suggestion_description">Votre appareil est connecté, mais CAPod ne reçoit aucune donnée en direct de sa part. Votre téléphone a peut-être besoin dune option de compatibilité — le dépannage peut essayer den trouver une automatiquement.</string>
<string name="overview_troubleshoot_suggestion_action">Lancer le dépannage</string>
<string name="overview_unmatched_devices_label">Appareils sans correspondance</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d appareil sans profil correspondant</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Détection du sommeil</string>
<string name="reaction_sleep_notification_title">Mis en pause par la détection du sommeil</string>
<string name="reaction_sleep_notification_text">%1$s a détecté que vous vous êtes endormi, votre musique a donc été mise en pause. Vous pouvez désactiver cela dans les paramètres de l\'appareil.</string>
<string name="reaction_charged_channel_label">Notification de charge</string>
<string name="reaction_charged_notification_title">Charge terminée</string>
<string name="reaction_charged_notification_text_full">%1$s est complètement chargé.</string>
<string name="reaction_charged_notification_text_partial">%1$s a été chargé à %2$d%%.</string>
<string name="device_settings_rename_label">Renommer</string>
<string name="device_settings_rename_hint">Nom de lappareil</string>
<string name="device_settings_rename_confirm">Renommer</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostrar ventá emerxente de conexión</string>
<string name="settings_popup_connected_description">Mostrar unha ventá emerxente cando o dispositivo se conecta por primeira vez.</string>
<string name="settings_popup_info_not_in_app">As ventás emerxentes só se mostran cando non estás na aplicación.</string>
<string name="settings_charged_notification_label">Notificación de carga completa</string>
<string name="settings_charged_notification_description">Mostra unha notificación cando todo o que está cargando alcanza o nivel de carga obxectivo.</string>
<string name="settings_charged_threshold_label">Nivel de carga obxectivo</string>
<string name="settings_charged_scope_label">Baterías monitorizadas</string>
<string name="settings_charged_scope_pods_label">Só os auriculares</string>
<string name="settings_charged_scope_case_label">Só o estoxo</string>
<string name="settings_charged_scope_both_label">Auriculares e estoxo</string>
<string name="device_settings_experimental_title">Función experimental</string>
<string name="device_settings_experimental_description">Esta función aínda non foi probada en todos os dispositivos. Se algo non funciona correctamente, abre un problema co rexistro de depuración.</string>
<string name="device_settings_experimental_action">Abrir o rastreador de problemas</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuración</string>
<string name="settings_general_label">Configuración</string>
<string name="settings_general_description">Axustes xerais que afectan a toda a aplicación.</string>
<string name="settings_overview_hide_unmatched_label">Ocultar dispositivos non coincidentes</string>
<string name="settings_overview_hide_unmatched_description">Non mostrar dispositivos próximos que non coincidan con ningún dos teus perfís na vista xeral, p. ex. os AirPods doutras persoas.</string>
<string name="settings_acknowledgements_label">Agradecementos</string>
<string name="settings_debug_autoreports_label">Informes de erros automáticos</string>
<string name="settings_debug_autoreports_description">Informa automaticamente de problemas, p. ex., detalles sobre un fallo da aplicación para que poida descubrir como solucionalo.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">O Bluetooth está desactivado, actívao ;)</string>
<string name="overview_monitoring_active_label">Supervisando dispositivos</string>
<string name="overview_monitoring_active_description">Asegúrate de que o teu dispositivo estea preto e activo.</string>
<string name="overview_troubleshoot_suggestion_label">Conectado, pero sen datos</string>
<string name="overview_troubleshoot_suggestion_description">O teu dispositivo está conectado, pero CAPod non está a recibir datos en tempo real del. O teu teléfono pode necesitar unha opción de compatibilidade — o solucionador de problemas pode tentar atopala automaticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Executar o solucionador de problemas</string>
<string name="overview_unmatched_devices_label">Dispositivos sen perfil coincidente</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo sen perfil coincidente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detección de sono</string>
<string name="reaction_sleep_notification_title">Pausado pola detección de sono</string>
<string name="reaction_sleep_notification_text">%1$s detectou que te durmiches, polo que a túa música foi pausada. Podes desactivar isto na configuración do dispositivo.</string>
<string name="reaction_charged_channel_label">Notificación de carga</string>
<string name="reaction_charged_notification_title">Carga completa</string>
<string name="reaction_charged_notification_text_full">%1$s está completamente cargado.</string>
<string name="reaction_charged_notification_text_partial">%1$s foi cargado ata o %2$d%%.</string>
<string name="device_settings_rename_label">Renomear</string>
<string name="device_settings_rename_hint">Nome do dispositivo</string>
<string name="device_settings_rename_confirm">Renomear</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">कनेक्शन पॉपअप दिखाएं</string>
<string name="settings_popup_connected_description">डिवाइस पहली बार कनेक्ट होने पर एक पॉपअप दिखाएं।</string>
<string name="settings_popup_info_not_in_app">पॉपअप केवल तब दिखाए जाते हैं जब आप ऐप में नहीं होते।</string>
<string name="settings_charged_notification_label">चार्ज सूचना</string>
<string name="settings_charged_notification_description">एक बार जब चार्ज हो रही हर चीज़ लक्ष्य चार्ज स्तर तक पहुँच जाए, तब एक सूचना दिखाएँ।</string>
<string name="settings_charged_threshold_label">लक्ष्य चार्ज स्तर</string>
<string name="settings_charged_scope_label">निगरानी की जा रही बैटरियाँ</string>
<string name="settings_charged_scope_pods_label">केवल पॉड्स</string>
<string name="settings_charged_scope_case_label">केवल केस</string>
<string name="settings_charged_scope_both_label">पॉड्स और केस</string>
<string name="device_settings_experimental_title">प्रयोगात्मक फ़ीचर</string>
<string name="device_settings_experimental_description">इस फ़ीचर को अभी सभी डिवाइस पर नहीं परखा गया है। यदि कुछ सही तरह से काम नहीं कर रहा, तो कृपया डीबग लॉग के साथ एक समस्या खोलें।</string>
<string name="device_settings_experimental_action">इश्यू ट्रैकर खोलें</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">डीबग</string>
<string name="settings_general_label">सेटिंग्स</string>
<string name="settings_general_description">सामान्य समायोजन जो पूरे ऐप को प्रभावित करते हैं।</string>
<string name="settings_overview_hide_unmatched_label">बेमेल डिवाइस छुपाएँ</string>
<string name="settings_overview_hide_unmatched_description">ओवरव्यू में उन नज़दीकी डिवाइस न दिखाएँ जो आपकी किसी प्रोफ़ाइल से मेल नहीं खाते, जैसे दूसरों के AirPods।</string>
<string name="settings_acknowledgements_label">स्वीकृतियाँ</string>
<string name="settings_debug_autoreports_label">स्वचालित बग रिपोर्ट</string>
<string name="settings_debug_autoreports_description">समस्याओं की स्वचालित रूप से रिपोर्ट करता है, जैसे ऐप क्रैश पर विवरण ताकि मैं यह पता लगा सकूं कि इसे कैसे ठीक किया जाए।</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth अक्षम है, इसे सक्षम करें ;)</string>
<string name="overview_monitoring_active_label">डिवाइसों की निगरानी हो रही है</string>
<string name="overview_monitoring_active_description">सुनिश्चित करें कि आपका डिवाइस पास में और सक्रिय है।</string>
<string name="overview_troubleshoot_suggestion_label">कनेक्टेड, लेकिन कोई डेटा नहीं</string>
<string name="overview_troubleshoot_suggestion_description">आपका डिवाइस कनेक्टेड है, लेकिन CAPod उससे कोई लाइव डेटा प्राप्त नहीं कर रहा। आपके फ़ोन को एक संगतता विकल्प की ज़रूरत हो सकती है — समस्या निवारक इसे स्वचालित रूप से खोजने की कोशिश कर सकता है।</string>
<string name="overview_troubleshoot_suggestion_action">समस्या निवारक चलाएँ</string>
<string name="overview_unmatched_devices_label">बेमेल डिवाइस</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d डिवाइस बिना मेल खाते प्रोफ़ाइल के</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">नींद का पता लगाना</string>
<string name="reaction_sleep_notification_title">नींद का पता लगाने से रोका गया</string>
<string name="reaction_sleep_notification_text">%1$s ने बताया कि आप सो गए, इसलिए आपका संगीत रोक दिया गया। आप इसे डिवाइस सेटिंग्स में बंद कर सकते हैं।</string>
<string name="reaction_charged_channel_label">चार्ज सूचना</string>
<string name="reaction_charged_notification_title">चार्जिंग पूर्ण</string>
<string name="reaction_charged_notification_text_full">%1$s पूरी तरह चार्ज हो गया है।</string>
<string name="reaction_charged_notification_text_partial">%1$s को %2$d%% तक चार्ज किया जा चुका है।</string>
<string name="device_settings_rename_label">नाम बदलें</string>
<string name="device_settings_rename_hint">डिवाइस का नाम</string>
<string name="device_settings_rename_confirm">नाम बदलें</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Prikaži skočni prozor veze</string>
<string name="settings_popup_connected_description">Prikaži skočni prozor kada se uređaj prvi put poveže.</string>
<string name="settings_popup_info_not_in_app">Skočni prozori prikazuju se samo kada niste u aplikaciji.</string>
<string name="settings_charged_notification_label">Obavijest o napunjenosti</string>
<string name="settings_charged_notification_description">Prikaži obavijest kada sve što se puni dostigne ciljanu razinu napunjenosti.</string>
<string name="settings_charged_threshold_label">Ciljana razina napunjenosti</string>
<string name="settings_charged_scope_label">Praćene baterije</string>
<string name="settings_charged_scope_pods_label">Samo slušalice</string>
<string name="settings_charged_scope_case_label">Samo kutija</string>
<string name="settings_charged_scope_both_label">Slušalice i kutija</string>
<string name="device_settings_experimental_title">Eksperimentalna značajka</string>
<string name="device_settings_experimental_description">Ova značajka još nije testirana na svim uređajima. Ako nešto ne radi ispravno, molimo otvorite prijavu s debug zapisnikom.</string>
<string name="device_settings_experimental_action">Otvori praćenje problema</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Ispravljanje pogrešaka</string>
<string name="settings_general_label">Postavke</string>
<string name="settings_general_description">Opće prilagodbe koje utječu na cijelu aplikaciju.</string>
<string name="settings_overview_hide_unmatched_label">Sakrij neprepoznate uređaje</string>
<string name="settings_overview_hide_unmatched_description">Ne prikazuj obližnje uređaje koji ne odgovaraju nijednom od tvojih profila u pregledu, npr. AirPods-e drugih osoba.</string>
<string name="settings_acknowledgements_label">Zahvale</string>
<string name="settings_debug_autoreports_label">Automatska izvješća o pogreškama</string>
<string name="settings_debug_autoreports_description">Automatski prijavljuje probleme, npr. detalje o rušenju aplikacije kako bih mogao shvatiti kako to popraviti.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth je onemogućen, omogućite ga ;)</string>
<string name="overview_monitoring_active_label">Praćenje uređaja</string>
<string name="overview_monitoring_active_description">Provjerite je li vaš uređaj u blizini i aktivan.</string>
<string name="overview_troubleshoot_suggestion_label">Spojeno, ali nema podataka</string>
<string name="overview_troubleshoot_suggestion_description">Tvoj uređaj je spojen, ali CAPod ne prima žive podatke od njega. Tvoj telefon možda treba opciju kompatibilnosti — alat za rješavanje problema može pokušati pronaći jednu automatski.</string>
<string name="overview_troubleshoot_suggestion_action">Pokreni rješavanje problema</string>
<string name="overview_unmatched_devices_label">Nepodudarni uređaji</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d uređaj bez odgovarajućeg profila</item>
@@ -495,6 +507,10 @@
<string name="reaction_sleep_channel_label">Otkrivanje spavanja</string>
<string name="reaction_sleep_notification_title">Pauzirano otkrivanjem spavanja</string>
<string name="reaction_sleep_notification_text">%1$s je prijavio da ste zaspali, pa je vaša glazba pauzirana. Možete to onemogućiti u postavkama uređaja.</string>
<string name="reaction_charged_channel_label">Obavijest o napunjenosti</string>
<string name="reaction_charged_notification_title">Punjenje završeno</string>
<string name="reaction_charged_notification_text_full">%1$s je potpuno napunjen.</string>
<string name="reaction_charged_notification_text_partial">%1$s je napunjen na %2$d%%.</string>
<string name="device_settings_rename_label">Preimenuj</string>
<string name="device_settings_rename_hint">Naziv uređaja</string>
<string name="device_settings_rename_confirm">Preimenuj</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Előugró ablak csatlakozáskor</string>
<string name="settings_popup_connected_description">Előugró ablak megjelenítése, amikor az eszköz először csatlakozik.</string>
<string name="settings_popup_info_not_in_app">Az előugró ablakok csak akkor jelennek meg, ha nem tartózkodik az alkalmazásban.</string>
<string name="settings_charged_notification_label">Feltöltési értesítés</string>
<string name="settings_charged_notification_description">Értesítés küldése, ha minden töltés alatt lévő eszköz eléri a céltöltési szintet.</string>
<string name="settings_charged_threshold_label">Céltöltési szint</string>
<string name="settings_charged_scope_label">Figyelt akkumulátorok</string>
<string name="settings_charged_scope_pods_label">Csak fülhallgatók</string>
<string name="settings_charged_scope_case_label">Csak tok</string>
<string name="settings_charged_scope_both_label">Fülhallgatók és tok</string>
<string name="device_settings_experimental_title">Kísérleti funkció</string>
<string name="device_settings_experimental_description">Ezt a funkciót még nem tesztelték minden eszközön. Ha valami nem működik megfelelően, kérjük, nyiss egy hibajegyet hibakeresési naplóval.</string>
<string name="device_settings_experimental_action">Hibajegykövetős megnyitása</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Hibakeresés</string>
<string name="settings_general_label">Beállítások</string>
<string name="settings_general_description">Általános módosítások, amelyek az egész alkalmazást érintik.</string>
<string name="settings_overview_hide_unmatched_label">Párosítatlan eszközök elrejtése</string>
<string name="settings_overview_hide_unmatched_description">Ne jelenjenek meg az áttekintőben azok a közeli eszközök, amelyek nem egyeznek egy profilodhoz sem, pl. mások AirPodjai.</string>
<string name="settings_acknowledgements_label">Köszönetnyilvánítás</string>
<string name="settings_debug_autoreports_label">Automatikus hibajelentések</string>
<string name="settings_debug_autoreports_description">Automatikusan jelenti a problémákat, például részleteket az alkalmazás összeomlásáról, hogy kitaláljam, hogyan javíthatom ki.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">A Bluetooth le van tiltva, engedélyezze ;)</string>
<string name="overview_monitoring_active_label">Eszközök figyelése</string>
<string name="overview_monitoring_active_description">Győződjön meg róla, hogy az eszköze a közelben van és aktív.</string>
<string name="overview_troubleshoot_suggestion_label">Csatlakoztatva, de nincs adat</string>
<string name="overview_troubleshoot_suggestion_description">Az eszköz csatlakoztatva van, de a CAPod nem kap élő adatot tőle. Előfordulhat, hogy a telefonodnak kompatibilitási beállításra van szüksége a hibaelőárító automatikusan megpróbálhat egyet találni.</string>
<string name="overview_troubleshoot_suggestion_action">Hibaelőárító futtatása</string>
<string name="overview_unmatched_devices_label">Nem párosított eszközök</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d eszköz párosított profil nélkül</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Alvásérzékelés</string>
<string name="reaction_sleep_notification_title">Az alvásérzékelés által szüneteltetve</string>
<string name="reaction_sleep_notification_text">%1$s jelezte, hogy elaludtál, ezért a zene szünetelt. Ezt a készülék beállításaiban kapcsolhatod ki.</string>
<string name="reaction_charged_channel_label">Feltöltési értesítés</string>
<string name="reaction_charged_notification_title">Töltés kész</string>
<string name="reaction_charged_notification_text_full">%1$s teljesen feltöltődött.</string>
<string name="reaction_charged_notification_text_partial">%1$s feltöltődött %2$d%%-ra.</string>
<string name="device_settings_rename_label">Átnevézés</string>
<string name="device_settings_rename_hint">Eszköz neve</string>
<string name="device_settings_rename_confirm">Átnevézés</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Ցուցադրել միացման բացվող պատուհանը</string>
<string name="settings_popup_connected_description">Ցուցադրել բացվող պատուհան, երբ սարքն առաջին անգամ է միանում։</string>
<string name="settings_popup_info_not_in_app">Ելնող պատուհանները ցուցադրվում են միայն այն ժամանակ, երբ դուք հավելվածում չեք:</string>
<string name="settings_charged_notification_label">Լիցքավորման ծանուցում</string>
<string name="settings_charged_notification_description">Ծանուցում ցուցադրել, երբ լիցքավորվող բոլոր սարքերը հասնեն թիրախային լիցքի մակարդակին:</string>
<string name="settings_charged_threshold_label">Թիրախային լիցքի մակարդակ</string>
<string name="settings_charged_scope_label">Վերահսկվող մարտկոցներ</string>
<string name="settings_charged_scope_pods_label">Միայն pods-երը</string>
<string name="settings_charged_scope_case_label">Միայն պատյանը</string>
<string name="settings_charged_scope_both_label">Pods-երն ու պատյանը</string>
<string name="device_settings_experimental_title">Փորձնական հատկություն</string>
<string name="device_settings_experimental_description">Այս հատկությունը դեռ չի փորձարկվել բոլոր սարքերում: Եթե ինչ-որ բան ճիշտ չի աշխատում, խնդրում ենք բացել հարց՝ կազմաբերման մատյանով:</string>
<string name="device_settings_experimental_action">Բացել հարցերի հետևիչը</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Կարգաբանություն</string>
<string name="settings_general_label">Կարգավորումներ</string>
<string name="settings_general_description">Ընդհանուր կարգավորումներ, որոնք ազդում են ամբողջ հավելվածի վրա։</string>
<string name="settings_overview_hide_unmatched_label">Թաքցնել անհամապատասխան սարքերը</string>
<string name="settings_overview_hide_unmatched_description">Չցուցադրել մոտակա սարքերը, որոնք չեն համընկնում ձեր պրոֆիլներից որևէ մեկի հետ, օրինակ՝ ուրիշի AirPods-ները:</string>
<string name="settings_acknowledgements_label">Շնորհակալագրեր</string>
<string name="settings_debug_autoreports_label">Սխալների ավտոմատ հաշվետվություններ</string>
<string name="settings_debug_autoreports_description">Ավտոմատ կերպով հաղորդում է խնդիրների մասին, օրինակ՝ հավելվածի խափանման մանրամասները, որպեսզի կարողանամ պարզել, թե ինչպես այն շտկել։</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth-ը անջատված է, միացրեք այն ;)</string>
<string name="overview_monitoring_active_label">Սարքերի մոնիթորինգ</string>
<string name="overview_monitoring_active_description">Համոզվեք, որ ձեր սարքը մոտակայքում է և ակտիվ է։</string>
<string name="overview_troubleshoot_suggestion_label">Միացված է, բայց տվյալներ չկան</string>
<string name="overview_troubleshoot_suggestion_description">Ձեր սարքը միացված է, սակայն CAPod-ը կենդանի տվյալներ չի ստանում դրանից: Ձեր հեռախոսը կարող է կոմպատիբիլության տարբերակի կարիք ունենալ — խնդիրների լուծիչը կարող է ավտոմատ կերպով գտնել համապատասխանը:</string>
<string name="overview_troubleshoot_suggestion_action">Գործարկել խնդիրների լուծիչը</string>
<string name="overview_unmatched_devices_label">Չհամապատասխանող սարքեր</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d սարք՝ առանց համապատասխան պրոֆիլի</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Քնի հայտնաբերում</string>
<string name="reaction_sleep_notification_title">Դադարեցված Քնի հայտնաբերման կողմից</string>
<string name="reaction_sleep_notification_text">%1$s-ը հայտնել է, որ դուք քնեցիք, ուստի ձեր երաժշտությունը դադարեցվեց։ Դուք կարող եք անջատել սա սարքի կարգավորումներում։</string>
<string name="reaction_charged_channel_label">Լիցքավորման ծանուցում</string>
<string name="reaction_charged_notification_title">Լիցքավորումն ավարտված է</string>
<string name="reaction_charged_notification_text_full">%1$s-ն ամբողջությամբ լիցքավորված է:</string>
<string name="reaction_charged_notification_text_partial">%1$s-ն լիցքավորվել է %2$d%%-ի:</string>
<string name="device_settings_rename_label">Փոխել անունը</string>
<string name="device_settings_rename_hint">Սառքի անուն</string>
<string name="device_settings_rename_confirm">Փոխել անունը</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Tampilkan pop-up koneksi</string>
<string name="settings_popup_connected_description">Tampilkan pop-up saat perangkat pertama kali terhubung.</string>
<string name="settings_popup_info_not_in_app">Popup hanya ditampilkan saat Anda tidak berada di aplikasi.</string>
<string name="settings_charged_notification_label">Pemberitahuan terisi</string>
<string name="settings_charged_notification_description">Tampilkan pemberitahuan setelah semua yang sedang diisi daya mencapai level pengisian target.</string>
<string name="settings_charged_threshold_label">Level pengisian target</string>
<string name="settings_charged_scope_label">Baterai yang dipantau</string>
<string name="settings_charged_scope_pods_label">Pod saja</string>
<string name="settings_charged_scope_case_label">Casing saja</string>
<string name="settings_charged_scope_both_label">Pod dan casing</string>
<string name="device_settings_experimental_title">Fitur eksperimental</string>
<string name="device_settings_experimental_description">Fitur ini belum diuji di semua perangkat. Jika ada yang tidak berfungsi dengan benar, silakan buka laporan masalah beserta log debug.</string>
<string name="device_settings_experimental_action">Buka Pelacak Masalah</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Pengaturan</string>
<string name="settings_general_description">Penyesuaian umum yang memengaruhi seluruh aplikasi.</string>
<string name="settings_overview_hide_unmatched_label">Sembunyikan perangkat yang tidak cocok</string>
<string name="settings_overview_hide_unmatched_description">Jangan tampilkan perangkat terdekat yang tidak cocok dengan profil mana pun di ringkasan, misalnya AirPods milik orang lain.</string>
<string name="settings_acknowledgements_label">Ucapan Terima Kasih</string>
<string name="settings_debug_autoreports_label">Laporan bug otomatis</string>
<string name="settings_debug_autoreports_description">Melaporkan masalah secara otomatis, mis. detail tentang kerusakan aplikasi sehingga saya dapat mencari tahu cara memperbaikinya.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth dinonaktifkan, aktifkan ;)</string>
<string name="overview_monitoring_active_label">Memantau perangkat</string>
<string name="overview_monitoring_active_description">Pastikan perangkat Anda berada di dekat dan aktif.</string>
<string name="overview_troubleshoot_suggestion_label">Terhubung, tetapi tidak ada data</string>
<string name="overview_troubleshoot_suggestion_description">Perangkat terhubung, tetapi CAPod tidak menerima data langsung darinya. Ponsel mungkin memerlukan opsi kompatibilitas — pemecah masalah dapat mencoba menemukannya secara otomatis.</string>
<string name="overview_troubleshoot_suggestion_action">Jalankan pemecah masalah</string>
<string name="overview_unmatched_devices_label">Perangkat tidak cocok</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">%d perangkat tanpa profil yang cocok</item>
@@ -485,6 +497,10 @@
<string name="reaction_sleep_channel_label">Deteksi Tidur</string>
<string name="reaction_sleep_notification_title">Dijeda oleh Deteksi Tidur</string>
<string name="reaction_sleep_notification_text">%1$s mendeteksi Anda tertidur, sehingga musik Anda dijeda. Anda dapat menonaktifkan ini di pengaturan perangkat.</string>
<string name="reaction_charged_channel_label">Pemberitahuan Terisi</string>
<string name="reaction_charged_notification_title">Pengisian selesai</string>
<string name="reaction_charged_notification_text_full">%1$s sudah terisi penuh.</string>
<string name="reaction_charged_notification_text_partial">%1$s telah diisi daya hingga %2$d%%.</string>
<string name="device_settings_rename_label">Ganti Nama</string>
<string name="device_settings_rename_hint">Nama perangkat</string>
<string name="device_settings_rename_confirm">Ganti Nama</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Sýna upplýsingaglugga tengingar</string>
<string name="settings_popup_connected_description">Sýna upplýsingaglugga þegar tækið tengist í fyrsta skipti.</string>
<string name="settings_popup_info_not_in_app">Sprettigluggar eru aðeins sýndir þegar þú ert ekki í forritinu.</string>
<string name="settings_charged_notification_label">Hlaðin tilkynning</string>
<string name="settings_charged_notification_description">Sýna tilkynningu þegar allt sem er að hlaðast nær markhlutfall hleðslu.</string>
<string name="settings_charged_threshold_label">Markhlutfall hleðslu</string>
<string name="settings_charged_scope_label">Fylgst með rafhlöðum</string>
<string name="settings_charged_scope_pods_label">Aðeins heyrnartæki</string>
<string name="settings_charged_scope_case_label">Aðeins hulstur</string>
<string name="settings_charged_scope_both_label">Heyrnartæki og hulstur</string>
<string name="device_settings_experimental_title">Tilraunaeiginleiki</string>
<string name="device_settings_experimental_description">Þessi eiginleiki hefur ekki verið prófaður á öllum tækjum enn. Ef eitthvað virkar ekki rétt skaltu opna málskrá með kembikladda.</string>
<string name="device_settings_experimental_action">Opna málaskráreftirlit</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Kembing</string>
<string name="settings_general_label">Stillingar</string>
<string name="settings_general_description">Almennar stillingar sem hafa áhrif á allt forritið.</string>
<string name="settings_overview_hide_unmatched_label">Fela ópassandi tæki</string>
<string name="settings_overview_hide_unmatched_description">Sýnir ekki nálæg tæki sem passa ekki við neitt af sniðunum þínum í yfirlitinu, t.d. AirPods annarra.</string>
<string name="settings_acknowledgements_label">Þakkir</string>
<string name="settings_debug_autoreports_label">Sjálfvirkar villuskýrslur</string>
<string name="settings_debug_autoreports_description">Tilkynnir sjálfkrafa um vandamál, t.d. upplýsingar um hrun forrits svo ég geti fundið út hvernig á að laga það.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth er óvirkt, virkjaðu það ;)</string>
<string name="overview_monitoring_active_label">Leitar að tækjum</string>
<string name="overview_monitoring_active_description">Gakktu úr skugga um að tækið þitt sé nálægt og virkt.</string>
<string name="overview_troubleshoot_suggestion_label">Tengt, en engar gögn</string>
<string name="overview_troubleshoot_suggestion_description">Tækið þitt er tengt, en CAPod er ekki að taka við lifandi gögnum frá því. Síminn þinn þarf kannski samhæfnismöguleika — villuleitin getur reynt að finna hann sjálfkrafa.</string>
<string name="overview_troubleshoot_suggestion_action">Keyra villuleit</string>
<string name="overview_unmatched_devices_label">Ópöruð tæki</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d tæki án samsvarandi sniðs</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Svefngreining</string>
<string name="reaction_sleep_notification_title">Gert hlé af svefngreiningu</string>
<string name="reaction_sleep_notification_text">%1$s greindi að þú sefur, þannig var tónlistin sett í hlé. Þú getur slökkt á þessu í tækjastillingum.</string>
<string name="reaction_charged_channel_label">Hlaðin tilkynning</string>
<string name="reaction_charged_notification_title">Hleðslu lokið</string>
<string name="reaction_charged_notification_text_full">%1$s er fullhlaðið.</string>
<string name="reaction_charged_notification_text_partial">%1$s hefur verið hlaðið í %2$d%%.</string>
<string name="device_settings_rename_label">Endurskíra</string>
<string name="device_settings_rename_hint">Nafn tækis</string>
<string name="device_settings_rename_confirm">Endurskíra</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostra pop-up connessione</string>
<string name="settings_popup_connected_description">Mostra un pop-up quando il dispositivo si connette per la prima volta.</string>
<string name="settings_popup_info_not_in_app">I popup vengono mostrati solo quando non sei nell\'app.</string>
<string name="settings_charged_notification_label">Notifica di ricarica completata</string>
<string name="settings_charged_notification_description">Mostra una notifica quando tutto ciò che è in carica raggiunge il livello di carica target.</string>
<string name="settings_charged_threshold_label">Livello di carica target</string>
<string name="settings_charged_scope_label">Batterie monitorate</string>
<string name="settings_charged_scope_pods_label">Solo auricolari</string>
<string name="settings_charged_scope_case_label">Solo custodia</string>
<string name="settings_charged_scope_both_label">Auricolari e custodia</string>
<string name="device_settings_experimental_title">Funzione sperimentale</string>
<string name="device_settings_experimental_description">Questa funzione non è stata ancora testata su tutti i dispositivi. Se qualcosa non funziona correttamente, apri una segnalazione con un log di debug.</string>
<string name="device_settings_experimental_action">Apri il tracker dei problemi</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Impostazioni</string>
<string name="settings_general_description">Modifiche generali che interessano l\'intera app.</string>
<string name="settings_overview_hide_unmatched_label">Nascondi dispositivi non abbinati</string>
<string name="settings_overview_hide_unmatched_description">Non mostrare nella panoramica i dispositivi nelle vicinanze che non corrispondono a nessuno dei tuoi profili, ad es. gli AirPods di altre persone.</string>
<string name="settings_acknowledgements_label">Riconoscimenti</string>
<string name="settings_debug_autoreports_label">Segnalazioni automatiche di bug</string>
<string name="settings_debug_autoreports_description">Segnala automaticamente i problemi, ad es. dettagli su un arresto anomalo dell\'app in modo che io possa capire come risolverlo.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Il Bluetooth è disabilitato, abilitalo ;)</string>
<string name="overview_monitoring_active_label">Monitoraggio dispositivi in corso</string>
<string name="overview_monitoring_active_description">Assicurati che il tuo dispositivo sia vicino e attivo.</string>
<string name="overview_troubleshoot_suggestion_label">Connesso, ma nessun dato</string>
<string name="overview_troubleshoot_suggestion_description">Il tuo dispositivo è connesso, ma CAPod non riceve dati live da esso. Il tuo telefono potrebbe aver bisogno di un\'opzione di compatibilità — lo strumento di risoluzione problemi può provare a trovarne una automaticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Avvia risoluzione problemi</string>
<string name="overview_unmatched_devices_label">Dispositivi non corrispondenti</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo senza profilo corrispondente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Rilevamento del sonno</string>
<string name="reaction_sleep_notification_title">In pausa per Rilevamento del sonno</string>
<string name="reaction_sleep_notification_text">%1$s ha rilevato che ti sei addormentato/a, quindi la musica è stata messa in pausa. Puoi disabilitarlo nelle impostazioni del dispositivo.</string>
<string name="reaction_charged_channel_label">Notifica di ricarica</string>
<string name="reaction_charged_notification_title">Ricarica completata</string>
<string name="reaction_charged_notification_text_full">%1$s è completamente carico.</string>
<string name="reaction_charged_notification_text_partial">%1$s è stato caricato al %2$d%%.</string>
<string name="device_settings_rename_label">Rinomina</string>
<string name="device_settings_rename_hint">Nome dispositivo</string>
<string name="device_settings_rename_confirm">Rinomina</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">הצג חלון קופץ של חיבור</string>
<string name="settings_popup_connected_description">הצג חלון קופץ כאשר המכשיר מתחבר בפעם הראשונה.</string>
<string name="settings_popup_info_not_in_app">חלונות קופצים מוצגים רק כשאינך בתוך האפליקציה.</string>
<string name="settings_charged_notification_label">התראת טעינה מלאה</string>
<string name="settings_charged_notification_description">הצג התראה כאשר כל מה שנטען מגיע לרמת הטעינה הרצויה.</string>
<string name="settings_charged_threshold_label">רמת טעינה יעד</string>
<string name="settings_charged_scope_label">סוללות מנוטרות</string>
<string name="settings_charged_scope_pods_label">אוזניות בלבד</string>
<string name="settings_charged_scope_case_label">נרתיק בלבד</string>
<string name="settings_charged_scope_both_label">אוזניות ונרתיק</string>
<string name="device_settings_experimental_title">תכונה ניסיונית</string>
<string name="device_settings_experimental_description">תכונה זו טרם נבדקה על כל המכשירים. אם משהו אינו פועל כראוי, אנא פתח בקשת תמיכה עם יומן ניפוי שגיאות.</string>
<string name="device_settings_experimental_action">פתח מעקב בעיות</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">איתור באגים</string>
<string name="settings_general_label">הגדרות</string>
<string name="settings_general_description">שינויים כלליים שמשפיעים על האפליקציה כולה.</string>
<string name="settings_overview_hide_unmatched_label">הסתר מכשירים שאינם תואמים</string>
<string name="settings_overview_hide_unmatched_description">אל תציג מכשירים קרובים שאינם תואמים אף אחד מהפרופילים שלך בתצוגה הכללית, למשל AirPods של אנשים אחרים.</string>
<string name="settings_acknowledgements_label">תודות</string>
<string name="settings_debug_autoreports_label">דוחות באגים אוטומטיים</string>
<string name="settings_debug_autoreports_description">מדווח אוטומטית על בעיות, למשל, פרטים על קריסת אפליקציה כדי שאוכל להבין איך לתקן את זה.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth מושבת, הפעל אותו ;)</string>
<string name="overview_monitoring_active_label">מחפש מכשירים</string>
<string name="overview_monitoring_active_description">ודא שהמכשיר שלך בקרבת מקום ופעיל.</string>
<string name="overview_troubleshoot_suggestion_label">מחובר, אך אין נתונים</string>
<string name="overview_troubleshoot_suggestion_description">המכשיר שלך מחובר, אך CAPod אינו מקבל ממנו נתונים חיים. הטלפון שלך עשוי להזדקק לאפשרות תאימות — פותר הבעיות יכול לנסות למצוא אחת אוטומטית.</string>
<string name="overview_troubleshoot_suggestion_action">הפעל פותר בעיות</string>
<string name="overview_unmatched_devices_label">מכשירים ללא התאמה</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">מכשיר %d ללא פרופיל תואם</item>
@@ -500,6 +512,10 @@
<string name="reaction_sleep_channel_label">זיהוי שינה</string>
<string name="reaction_sleep_notification_title">הושהה על ידי זיהוי שינה</string>
<string name="reaction_sleep_notification_text">%1$s דיווח שנרדמת, לכן המוזיקה הושהתה. ניתן להשבית זאת בהגדרות המכשיר.</string>
<string name="reaction_charged_channel_label">התראת טעינה מלאה</string>
<string name="reaction_charged_notification_title">הטעינה הושלמה</string>
<string name="reaction_charged_notification_text_full">%1$s טעון במלואו.</string>
<string name="reaction_charged_notification_text_partial">%1$s נטען עד %2$d%%.</string>
<string name="device_settings_rename_label">שנה שם</string>
<string name="device_settings_rename_hint">שם המכשיר</string>
<string name="device_settings_rename_confirm">שנה שם</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">接続ポップアップを表示</string>
<string name="settings_popup_connected_description">デバイスが初めて接続されたときにポップアップを表示します。</string>
<string name="settings_popup_info_not_in_app">ポップアップはアプリを使用していない時のみ表示されます。</string>
<string name="settings_charged_notification_label">充電完了通知</string>
<string name="settings_charged_notification_description">充電中のすべてのデバイスが目標充電レベルに達したら通知を表示します。</string>
<string name="settings_charged_threshold_label">目標充電レベル</string>
<string name="settings_charged_scope_label">監視対象バッテリー</string>
<string name="settings_charged_scope_pods_label">ポッドのみ</string>
<string name="settings_charged_scope_case_label">ケースのみ</string>
<string name="settings_charged_scope_both_label">ポッドとケース</string>
<string name="device_settings_experimental_title">実験的機能</string>
<string name="device_settings_experimental_description">この機能はまだすべてのデバイスでテストされていません。正しく動作しない場合は、デバッグログを添えてイシューを開いてください。</string>
<string name="device_settings_experimental_action">イシュートラッカーを開く</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">デバッグ</string>
<string name="settings_general_label">設定</string>
<string name="settings_general_description">アプリ全体に影響する一般的な調整。</string>
<string name="settings_overview_hide_unmatched_label">一致しないデバイスを非表示</string>
<string name="settings_overview_hide_unmatched_description">プロフィールに一致しない近くのデバイス(他の人のAirPodsなど)を概要に表示しません。</string>
<string name="settings_acknowledgements_label">謝辞</string>
<string name="settings_debug_autoreports_label">自動バグレポート</string>
<string name="settings_debug_autoreports_description">アプリのクラッシュに関する詳細など、問題を自動的に報告して、修正方法を把握できるようにします。</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetoothが無効です。有効にしてください ;)</string>
<string name="overview_monitoring_active_label">デバイスを監視中</string>
<string name="overview_monitoring_active_description">デバイスが近くにあり、アクティブであることを確認してください。</string>
<string name="overview_troubleshoot_suggestion_label">接続済み、データなし</string>
<string name="overview_troubleshoot_suggestion_description">デバイスは接続されていますが、CAPodはライブデータを受信していません。互換性オプションが必要な場合があります—トラブルシューターが自動的に検索を試みます。</string>
<string name="overview_troubleshoot_suggestion_action">トラブルシューターを実行</string>
<string name="overview_unmatched_devices_label">一致しないデバイス</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">一致するプロファイルがないデバイス %d 台</item>
@@ -485,6 +497,10 @@
<string name="reaction_sleep_channel_label">睡眠検出</string>
<string name="reaction_sleep_notification_title">睡眠検出によって一時停止されました</string>
<string name="reaction_sleep_notification_text">%1$s が眠りについたことを検出したため、音楽が一時停止されました。デバイス設定で無効にできます。</string>
<string name="reaction_charged_channel_label">充電完了通知</string>
<string name="reaction_charged_notification_title">充電完了</string>
<string name="reaction_charged_notification_text_full">%1$sは満充電になりました。</string>
<string name="reaction_charged_notification_text_partial">%1$sが%2$d%%まで充電されました。</string>
<string name="device_settings_rename_label">名前を変更</string>
<string name="device_settings_rename_hint">デバイス名</string>
<string name="device_settings_rename_confirm">名前を変更</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">დაკავშირების ამომხტარი ფანჯრის ჩვენება</string>
<string name="settings_popup_connected_description">აჩვენეთ ამომხტარი ფანჯარა მოწყობილობის პირველად დაკავშირებისას.</string>
<string name="settings_popup_info_not_in_app">პოპ-აპები მხოლოდ მაშინ ჩანს, როცა არ ხართ აპლიკაციაში.</string>
<string name="settings_charged_notification_label">დატენვის შეტყობინება</string>
<string name="settings_charged_notification_description">გამოჩნდება შეტყობინება, როგორც კი დამტენი მოწყობილობა მიაღწევს სამიზნე დატენვის დონეს.</string>
<string name="settings_charged_threshold_label">სამიზნე დატენვის დონე</string>
<string name="settings_charged_scope_label">მონიტორინგს დაქვემდებარებული ელემენტები</string>
<string name="settings_charged_scope_pods_label">მხოლოდ ყურსასმენები</string>
<string name="settings_charged_scope_case_label">მხოლოდ კეისი</string>
<string name="settings_charged_scope_both_label">ყურსასმენები და კეისი</string>
<string name="device_settings_experimental_title">ექსპერიმენტული ფუნქცია</string>
<string name="device_settings_experimental_description">ეს ფუნქცია ჯერ ყველა მოწყობილობაზე გამოცდილი არ არის. თუ რამე სწორად არ მუშაობს, გთხოვთ გახსნათ ხარვეზი debug ლოგთან ერთად.</string>
<string name="device_settings_experimental_action">ხარვეზების ტრეკერის გახსნა</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">გამართვა</string>
<string name="settings_general_label">პარამეტრები</string>
<string name="settings_general_description">ზოგადი შესწორებები, რომლებიც გავლენას ახდენს მთელ აპლიკაციაზე.</string>
<string name="settings_overview_hide_unmatched_label">შეუსაბამო მოწყობილობების დამალვა</string>
<string name="settings_overview_hide_unmatched_description">არ აჩვენო მახლობლად მყოფი მოწყობილობები, რომლებიც არ ემთხვევა თქვენს პროფილებს მიმოხილვაში, მაგ. სხვა ადამიანების AirPods.</string>
<string name="settings_acknowledgements_label">მადლობები</string>
<string name="settings_debug_autoreports_label">შეცდომების ავტომატური ანგარიშები</string>
<string name="settings_debug_autoreports_description">ავტომატურად აცნობებს პრობლემების შესახებ, მაგ. აპლიკაციის ავარიის დეტალებს, რათა გავარკვიო, როგორ გამოვასწორო.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth გამორთულია, ჩართეთ ;)</string>
<string name="overview_monitoring_active_label">მოწყობილობების მონიტორინგი</string>
<string name="overview_monitoring_active_description">დარწმუნდით, რომ თქვენი მოწყობილობა ახლოსაა და აქტიურია.</string>
<string name="overview_troubleshoot_suggestion_label">დაკავშირებულია, მაგრამ მონაცემები არ არის</string>
<string name="overview_troubleshoot_suggestion_description">თქვენი მოწყობილობა დაკავშირებულია, მაგრამ CAPod არ იღებს მისგან ცოცხალ მონაცემებს. თქვენს ტელეფონს შეიძლება სჭირდებოდეს თავსებადობის პარამეტრი — პრობლემების გადამჭრელი შეძლებს ავტომატურად მოძებნოს.</string>
<string name="overview_troubleshoot_suggestion_action">პრობლემების გადამჭრელის გაშვება</string>
<string name="overview_unmatched_devices_label">შეუთავსებელი მოწყობილობები</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d მოწყობილობა შესაბამისი პროფილის გარეშეა</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">ძილის გამოვლენა</string>
<string name="reaction_sleep_notification_title">შეჩერებულია ძილის გამოვლენის მიერ</string>
<string name="reaction_sleep_notification_text">%1$s-მ დააფიქსირა, რომ ჩაეძინათ, ამიტომ მუსიკა შეჩერდა. ამის გათიშვა შეგიძლიათ მოწყობილობის პარამეტრებში.</string>
<string name="reaction_charged_channel_label">დატენვის შეტყობინება</string>
<string name="reaction_charged_notification_title">დატენვა დასრულდა</string>
<string name="reaction_charged_notification_text_full">%1$s სრულად დატენილია.</string>
<string name="reaction_charged_notification_text_partial">%1$s დაიტენა %2$d%%-მდე.</string>
<string name="device_settings_rename_label">გადარქმევა</string>
<string name="device_settings_rename_hint">მოწყობილობის სახელი</string>
<string name="device_settings_rename_confirm">გადარქმევა</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">បង្ហាញផ្ទាំងលោតការភ្ជាប់</string>
<string name="settings_popup_connected_description">បង្ហាញផ្ទាំងលោតនៅពេលឧបករណ៍ភ្ជាប់ជាលើកដំបូង។</string>
<string name="settings_popup_info_not_in_app">ការបង្ហាញលេចឡើងត្រូវបានបង្ហាញតែពេលអ្នកមិននៅក្នុងកម្មវិធីប៉ុណ្ណោះ។</string>
<string name="settings_charged_notification_label">ការជូនដំណឹងការសាកថ្ម</string>
<string name="settings_charged_notification_description">បង្ហាញការជូនដំណឹងនៅពេលដែលអ្វីៗទាំងអស់ដែលកំពុងសាកថ្មដល់កម្រិតសាកថ្មគោលដៅ។</string>
<string name="settings_charged_threshold_label">កម្រិតសាកថ្មគោលដៅ</string>
<string name="settings_charged_scope_label">ថ្មដែលកំពុងត្រូវបានត្រួតពិនិត្យ</string>
<string name="settings_charged_scope_pods_label">តែ Pods ប៉ុណ្ណោះ</string>
<string name="settings_charged_scope_case_label">តែ Case ប៉ុណ្ណោះ</string>
<string name="settings_charged_scope_both_label">Pods និង Case</string>
<string name="device_settings_experimental_title">មុខងារពិសោធន៍</string>
<string name="device_settings_experimental_description">មុខងារនេះមិនទាន់ត្រូវបានសាកល្បងនៅលើឧបករណ៍ទាំងអស់នៅឡើយទេ។ ប្រសិនបើអ្វីមួយមិនដំណើរការត្រឹមត្រូវ សូមបើកបញ្ហាជាមួយកំណត់ហេតុ debug។</string>
<string name="device_settings_experimental_action">បើក Issue Tracker</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">ការបំបាត់កំហុស</string>
<string name="settings_general_label">ការកំណត់</string>
<string name="settings_general_description">ការកែតម្រូវទូទៅដែលប៉ះពាល់ដល់កម្មវិធីទាំងមូល។</string>
<string name="settings_overview_hide_unmatched_label">លាក់ឧបករណ៍ដែលមិនត្រូវគ្នា</string>
<string name="settings_overview_hide_unmatched_description">មិនបង្ហាញឧបករណ៍នៅជិតដែលមិនត្រូវនឹងប្រវត្តិរូបណាមួយរបស់អ្នកនៅក្នុងទិដ្ឋភាពទូទៅ ឧ. AirPods របស់អ្នកដទៃ។</string>
<string name="settings_acknowledgements_label">ការទទួលស្គាល់</string>
<string name="settings_debug_autoreports_label">របាយការណ៍កំហុសដោយស្វ័យប្រវត្តិ</string>
<string name="settings_debug_autoreports_description">រាយការណ៍បញ្ហាដោយស្វ័យប្រវត្តិ ឧ. ព័ត៌មានលម្អិតអំពីការគាំងកម្មវិធី ដូច្នេះខ្ញុំអាចរកវិធីដោះស្រាយវាបាន។</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ត្រូវបានបិទ សូមបើកវា ;)</string>
<string name="overview_monitoring_active_label">កំពុងតាមដានឧបករណ៍</string>
<string name="overview_monitoring_active_description">សូមប្រាកដថាឧបករណ៍របស់អ្នកនៅជិត និងសកម្ម។</string>
<string name="overview_troubleshoot_suggestion_label">ភ្ជាប់ហើយ តែគ្មានទិន្នន័យ</string>
<string name="overview_troubleshoot_suggestion_description">ឧបករណ៍របស់អ្នកបានភ្ជាប់ ប៉ុន្តែ CAPod មិនទទួលបានទិន្នន័យផ្ទាល់ណាមួយពីវាទេ។ ទូរស័ព្ទរបស់អ្នកប្រហែលជាត្រូវការជម្រើសសម្រាប់ភាពឆបគ្នា — កម្មវិធីដោះស្រាយបញ្ហាអាចព្យាយាមស្វែងរកមួយដោយស្វ័យប្រវត្តិ។</string>
<string name="overview_troubleshoot_suggestion_action">ដំណើរការកម្មវិធីដោះស្រាយបញ្ហា</string>
<string name="overview_unmatched_devices_label">ឧបករណ៍ដែលមិនត្រូវគ្នា</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">ឧបករណ៍ %d គ្មានទម្រង់ត្រូវគ្នា</item>
@@ -485,6 +497,10 @@
<string name="reaction_sleep_channel_label">ការរកឃើញការគេង</string>
<string name="reaction_sleep_notification_title">ផ្អាកដោយការរកឃើញការគេង</string>
<string name="reaction_sleep_notification_text">%1$s រាយការណ៍ថាអ្នកគេងលក់ ដូច្នេះតន្ត្រីរបស់អ្នកត្រូវបានផ្អាក។ អ្នកអាចបិទមុខងារនេះបានក្នុងការកំណត់ឧបករណ៍។</string>
<string name="reaction_charged_channel_label">ការជូនដំណឹងការសាកថ្ម</string>
<string name="reaction_charged_notification_title">ការសាកថ្មបានបញ្ចប់</string>
<string name="reaction_charged_notification_text_full">%1$s បានសាកថ្មពេញហើយ។</string>
<string name="reaction_charged_notification_text_partial">%1$s បានសាកថ្មដល់ %2$d%%។</string>
<string name="device_settings_rename_label">ប្តូរៀម្អោះ</string>
<string name="device_settings_rename_hint">ៀម្អោះឧបករណ៍</string>
<string name="device_settings_rename_confirm">ប្តូរៀម្អោះ</string>
+19 -3
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Pop-upa girêdanê nîşan bide</string>
<string name="settings_popup_connected_description">Dema ku amûr cara yekem girêdide pop-upek nîşan bide.</string>
<string name="settings_popup_info_not_in_app">Pencereyên daqurtandinê tenê dema tu di serîlêdanê de nî nîn in tên nîşandan.</string>
<string name="settings_charged_notification_label">Agahdariya şarjbûnê</string>
<string name="settings_charged_notification_description">Gava ku her tiştê ku tê şarjkirin bigihîje asta şarjê ya armancê, agahdariyekê nîşan bide.</string>
<string name="settings_charged_threshold_label">Asta şarjê ya armancê</string>
<string name="settings_charged_scope_label">Bataryayên çavdêrîkirî</string>
<string name="settings_charged_scope_pods_label">Tenê pods</string>
<string name="settings_charged_scope_case_label">Tenê qutiyek</string>
<string name="settings_charged_scope_both_label">Pods û qutî</string>
<string name="device_settings_experimental_title">Taybetmendiya ezmûnî</string>
<string name="device_settings_experimental_description">Ev taybetmendî hê li ser hemî amûran nehatiye ceribandin. Eger tiştek rast nexebite, ji kerema xwe pirsgirêkek bi têkelbûnek debug vekin.</string>
<string name="device_settings_experimental_action">Şopînerê Pirsgirêkê Veke</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Mîheng</string>
<string name="settings_general_description">Guhertinên giştî yên ku bandorê li tevahiya sepanê dikin.</string>
<string name="settings_overview_hide_unmatched_label">Amûrên neçêkirî veşêre</string>
<string name="settings_overview_hide_unmatched_description">Amûrên nêzîk ên ku bi ti profilên te re li hev nakin di nêrîna giştî de nîşan nede, mînak AirPods-ên kesên din.</string>
<string name="settings_acknowledgements_label">Spasdarî</string>
<string name="settings_debug_autoreports_label">Raporên xeletiyan ên otomatîk</string>
<string name="settings_debug_autoreports_description">Pirsgirêkan bixweber rapor dike, mînak hûrguliyên li ser têkçûna sepanê da ku ez bikaribim fêhm bikim ka meriv çawa wê sererast bike.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth neçalak e, wê çalak bikin ;)</string>
<string name="overview_monitoring_active_label">Amûr tên şopandin</string>
<string name="overview_monitoring_active_description">Bawer bin ku amûra we nêzîk û çalak e.</string>
<string name="overview_troubleshoot_suggestion_label">Girêdayî, lê daneya tune</string>
<string name="overview_troubleshoot_suggestion_description">Amûra te girêdayî ye, lê CAPod daneya zindî ji wê nagire. Dibe ku telefona te vebijarkek lihevhatinê hewce bike — çareserkerê pirsgirîkan dikare bixweber yek bibîne.</string>
<string name="overview_troubleshoot_suggestion_action">Çareserkerê pirsgirîkan bixebitîne</string>
<string name="overview_unmatched_devices_label">Amûrên nehevgirtî</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d amûr bê profîla hevgirtî</item>
@@ -250,9 +262,9 @@
<string name="conversation_awareness_label">Hişyariya Sohbetê</string>
<string name="settings_conversation_action_label">Gava tu dest bi axaftinê dikî</string>
<string name="settings_conversation_action_nothing_label">Tiştek meke</string>
<string name="settings_conversation_action_lower_volume_label">Dengê kêm bike</string>
<string name="settings_conversation_action_lower_volume_label">Dengê xwarin</string>
<string name="settings_conversation_action_pause_label">Medyayê raweste</string>
<string name="settings_conversation_volume_reduction_label">Kêmkirina dengê</string>
<string name="settings_conversation_volume_reduction_label">Kêmkirina dengî</string>
<string name="signal_badge_ble_cd">Lêgerîna BLE çalak e</string>
<string name="signal_badge_key_irk_cd">Nasnameya piştrast kir</string>
<string name="signal_badge_key_encrypted_cd">Girêdana şîfrekirî</string>
@@ -468,7 +480,7 @@
<!-- New device settings -->
<string name="device_settings_category_general_label">Giştî</string>
<string name="device_settings_microphone_mode_label">Mîkrofon</string>
<string name="device_settings_microphone_mode_description">Kîjan guhêrk wekî mîkrofon tê bikaranîn</string>
<string name="device_settings_microphone_mode_description">Kîjan guhêrk wek mîkrofon tê bikar anîn</string>
<string name="device_settings_microphone_mode_auto">Xweber</string>
<string name="device_settings_microphone_mode_right">Rastê</string>
<string name="device_settings_microphone_mode_left">Çepê</string>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Tespîtkirina Xewê</string>
<string name="reaction_sleep_notification_title">Ji hêla Tespîtkirina Xewê ve hate rawestandin</string>
<string name="reaction_sleep_notification_text">%1$s ragihand ku hûn xew çûn, ji ber vê yekê muzîka we hate rawestandin. Hûn dikarin vê di mîhengên amûrê de neçalak bikin.</string>
<string name="reaction_charged_channel_label">Agahdariya şarjbûnê</string>
<string name="reaction_charged_notification_title">Şarjkirin temam bû</string>
<string name="reaction_charged_notification_text_full">%1$s bi tevahî şarj bûye.</string>
<string name="reaction_charged_notification_text_partial">%1$s heya %2$d%% şarj bûye.</string>
<string name="device_settings_rename_label">Navnivisîn</string>
<string name="device_settings_rename_hint">Navê cîhazê</string>
<string name="device_settings_rename_confirm">Navnivisîn</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">ಸಂಪರ್ಕ ಪಾಪ್‌ಅಪ್ ತೋರಿಸಿ</string>
<string name="settings_popup_connected_description">ಸಾಧನವು ಮೊದಲ ಬಾರಿಗೆ ಸಂಪರ್ಕಗೊಂಡಾಗ ಪಾಪ್‌ಅಪ್ ತೋರಿಸಿ.</string>
<string name="settings_popup_info_not_in_app">ನೀವು ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ ಇಲ್ಲದಿರುವಾಗ ಮಾತ್ರ ಪಾಪ್‌ಅಪ್‌ಗಳನ್ನು ತೋರಿಸಲಾಗುತ್ತದೆ.</string>
<string name="settings_charged_notification_label">ಚಾರ್ಜ್ ಅಧಿಸೂಚನೆ</string>
<string name="settings_charged_notification_description">ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವ ಎಲ್ಲವೂ ಗುರಿ ಚಾರ್ಜ್ ಮಟ್ಟವನ್ನು ತಲುಪಿದ ನಂತರ ಅಧಿಸೂಚನೆ ತೋರಿಸಿ.</string>
<string name="settings_charged_threshold_label">ಗುರಿ ಚಾರ್ಜ್ ಮಟ್ಟ</string>
<string name="settings_charged_scope_label">ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಲಾದ ಬ್ಯಾಟರಿಗಳು</string>
<string name="settings_charged_scope_pods_label">ಪಾಡ್‌ಗಳು ಮಾತ್ರ</string>
<string name="settings_charged_scope_case_label">ಕೇಸ್ ಮಾತ್ರ</string>
<string name="settings_charged_scope_both_label">ಪಾಡ್‌ಗಳು ಮತ್ತು ಕೇಸ್</string>
<string name="device_settings_experimental_title">ಪ್ರಯೋಗಾತ್ಮಕ ವೈಶಿಷ್ಟ್ಯ</string>
<string name="device_settings_experimental_description">ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಇನ್ನೂ ಎಲ್ಲಾ ಸಾಧನಗಳಲ್ಲಿ ಪರೀಕ್ಷಿಸಲಾಗಿಲ್ಲ. ಏನಾದರೂ ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡದಿದ್ದರೆ, ದಯವಿಟ್ಟು ಡಿಬಗ್ ಲಾಗ್‌ನೊಂದಿಗೆ ಸಮಸ್ಯೆ ತೆರೆಯಿರಿ.</string>
<string name="device_settings_experimental_action">ಸಮಸ್ಯೆ ಟ್ರ್ಯಾಕರ್ ತೆರೆಯಿರಿ</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">ಡೀಬಗ್</string>
<string name="settings_general_label">ಸೆಟ್ಟಿಂಗ್‌ಗಳು</string>
<string name="settings_general_description">ಇಡೀ ಅಪ್ಲಿಕೇಶನ್‌ನ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುವ ಸಾಮಾನ್ಯ ಹೊಂದಾಣಿಕೆಗಳು.</string>
<string name="settings_overview_hide_unmatched_label">ಹೊಂದಿಕೆಯಾಗದ ಸಾಧನಗಳನ್ನು ಮರೆಮಾಡಿ</string>
<string name="settings_overview_hide_unmatched_description">ನಿಮ್ಮ ಯಾವುದೇ ಪ್ರೊಫೈಲ್‌ಗಳಿಗೆ ಹೊಂದಿಕೆಯಾಗದ ಹತ್ತಿರದ ಸಾಧನಗಳನ್ನು ಅವಲೋಕನದಲ್ಲಿ ತೋರಿಸಬೇಡಿ, ಉದಾ. ಇತರ ಜನರ AirPods.</string>
<string name="settings_acknowledgements_label">ಕೃತಜ್ಞತೆಗಳು</string>
<string name="settings_debug_autoreports_label">ಸ್ವಯಂಚಾಲಿತ ಬಗ್ ವರದಿಗಳು</string>
<string name="settings_debug_autoreports_description">ಸಮಸ್ಯೆಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ವರದಿ ಮಾಡುತ್ತದೆ, ಉದಾ. ಅಪ್ಲಿಕೇಶನ್ ಕ್ರ್ಯಾಶ್ ಕುರಿತು ವಿವರಗಳು ಇದರಿಂದ ಅದನ್ನು ಹೇಗೆ ಸರಿಪಡಿಸುವುದು ಎಂದು ನಾನು ಕಂಡುಹಿಡಿಯಬಹುದು.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ನಿಷ್ಕ್ರಿಯವಾಗಿದೆ, ಅದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ ;)</string>
<string name="overview_monitoring_active_label">ಸಾಧನಗಳಿಗಾಗಿ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಲಾಗುತ್ತಿದೆ</string>
<string name="overview_monitoring_active_description">ನಿಮ್ಮ ಸಾಧನವು ಹತ್ತಿರದಲ್ಲಿದೆ ಮತ್ತು ಸಕ್ರಿಯವಾಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.</string>
<string name="overview_troubleshoot_suggestion_label">ಸಂಪರ್ಕಿಸಲಾಗಿದೆ, ಆದರೆ ಡೇಟಾ ಇಲ್ಲ</string>
<string name="overview_troubleshoot_suggestion_description">ನಿಮ್ಮ ಸಾಧನ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ, ಆದರೆ CAPod ಅದರಿಂದ ಯಾವುದೇ ಲೈವ್ ಡೇಟಾ ಸ್ವೀಕರಿಸುತ್ತಿಲ್ಲ. ನಿಮ್ಮ ಫೋನ್‌ಗೆ ಹೊಂದಾಣಿಕೆ ಆಯ್ಕೆಯ ಅಗತ್ಯವಿರಬಹುದು — ಸಮಸ್ಯೆ ನಿವಾರಕ ಒಂದನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಹುಡುಕಲು ಪ್ರಯತ್ನಿಸಬಹುದು.</string>
<string name="overview_troubleshoot_suggestion_action">ಸಮಸ್ಯೆ ನಿವಾರಕ ರನ್ ಮಾಡಿ</string>
<string name="overview_unmatched_devices_label">ಹೊಂದಿಕೆಯಾಗದ ಸಾಧನಗಳು</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">ಹೊಂದಿಕೆಯಾಗುವ ಪ್ರೊಫೈಲ್ ಇಲ್ಲದ %d ಸಾಧನ</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">ನಿದ್ರೆ ಪತ್ತೆ</string>
<string name="reaction_sleep_notification_title">ನಿದ್ರೆ ಪತ್ತೆಯಿಂದ ವಿರಾಮಗೊಂಡಿದೆ</string>
<string name="reaction_sleep_notification_text">%1$s ನೀವು ನಿದ್ರಿಸಿದಿರಿ ಎಂದು ತಿಳಿಸಿದೆ, ಆದ್ದರಿಂದ ನಿಮ್ಮ ಸಂಗೀತವನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ. ಸಾಧನ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಇದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು.</string>
<string name="reaction_charged_channel_label">ಚಾರ್ಜ್ ಅಧಿಸೂಚನೆ</string>
<string name="reaction_charged_notification_title">ಚಾರ್ಜಿಂಗ್ ಪೂರ್ಣಗೊಂಡಿದೆ</string>
<string name="reaction_charged_notification_text_full">%1$s ಸಂಪೂರ್ಣವಾಗಿ ಚಾರ್ಜ್ ಆಗಿದೆ.</string>
<string name="reaction_charged_notification_text_partial">%1$s ಅನ್ನು %2$d%% ವರೆಗೆ ಚಾರ್ಜ್ ಮಾಡಲಾಗಿದೆ.</string>
<string name="device_settings_rename_label">ಮರುಹೆಸರಿಸಿ</string>
<string name="device_settings_rename_hint">ಸಾಧನ ಹೆಸರು</string>
<string name="device_settings_rename_confirm">ಮರುಹೆಸರಿಸಿ</string>
+20 -4
View File
@@ -76,8 +76,15 @@
<string name="settings_popup_connected_label">연결 팝업 표시</string>
<string name="settings_popup_connected_description">기기가 처음 연결될 때 팝업을 표시합니다.</string>
<string name="settings_popup_info_not_in_app">팝업은 앱 내에 있지 않을 때만 표시됩니다.</string>
<string name="settings_charged_notification_label">충전 완료 알림</string>
<string name="settings_charged_notification_description">충전 중인 모든 항목이 목표 충전 수준에 도달하면 알림을 표시합니다.</string>
<string name="settings_charged_threshold_label">목표 충전 수준</string>
<string name="settings_charged_scope_label">모니터링할 배터리</string>
<string name="settings_charged_scope_pods_label">팟만</string>
<string name="settings_charged_scope_case_label">케이스만</string>
<string name="settings_charged_scope_both_label">팟과 케이스</string>
<string name="device_settings_experimental_title">실험적 기능</string>
<string name="device_settings_experimental_description">이 기능은 아직 모든 기기에서 테스트되지 않았습니다. 제대로 작동하지 않는 경우 디버그 로그와 함께 이슈를 열어주세요.</string>
<string name="device_settings_experimental_description">이 기능은 아직 모든 기기에서 테스트되지 않았습니다. 제대로 작동하지 않는 경우 디버그 로그와 함께 문제를 보고해 주세요.</string>
<string name="device_settings_experimental_action">이슈 트래커 열기</string>
<string name="notification_channel_device_status_label">기기 상태</string>
<string name="notification_channel_device_status_connected_label">연결된 기기</string>
@@ -100,7 +107,7 @@
<string name="settings_wiki_label">위키</string>
<string name="settings_wiki_description">FAQ &amp; 가이드</string>
<string name="issue_tracker_label">문제 추적기</string>
<string name="issue_tracker_description">버그 보고서 및 기능 요청을 위한 공개 문제 추적기(영어만 해당).</string>
<string name="issue_tracker_description">버그 보고서 및 기능 요청을 위한 공개 문제 추적기(영어 전용).</string>
<string name="discord_label">디스코드</string>
<string name="discord_description">이야기를 나누고 질문을 할 수 있는 곳.</string>
<string name="changelog_label">변경 로그</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">디버그</string>
<string name="settings_general_label">설정</string>
<string name="settings_general_description">앱 전체에 영향을 미치는 일반적인 조정.</string>
<string name="settings_overview_hide_unmatched_label">일치하지 않는 기기 숨기기</string>
<string name="settings_overview_hide_unmatched_description">개요에서 프로필과 일치하지 않는 주변 기기(예: 다른 사람의 AirPods)를 표시하지 않습니다.</string>
<string name="settings_acknowledgements_label">감사의 말</string>
<string name="settings_debug_autoreports_label">자동 버그 보고서</string>
<string name="settings_debug_autoreports_description">앱 충돌에 대한 세부 정보와 같이 문제를 자동으로 보고하여 해결 방법을 파악할 수 있도록 합니다.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">블루투스를 켜야 연결할 수 있어요 ;)</string>
<string name="overview_monitoring_active_label">기기 모니터링 중</string>
<string name="overview_monitoring_active_description">기기가 켜진 상태에서 가까이 위치해 있는지 확인해 주세요.</string>
<string name="overview_troubleshoot_suggestion_label">연결됨, 데이터 없음</string>
<string name="overview_troubleshoot_suggestion_description">기기가 연결되어 있지만 CAPod가 실시간 데이터를 수신하지 못하고 있습니다. 호환성 옵션이 필요할 수 있으며, 문제 해결사가 자동으로 찾아드릴 수 있습니다.</string>
<string name="overview_troubleshoot_suggestion_action">문제 해결사 실행</string>
<string name="overview_unmatched_devices_label">일치하지 않는 기기</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">%d프로필과 일치하지 않는 기기</item>
@@ -209,7 +221,7 @@
<string name="permission_access_fine_location_label">정밀 위치 접근</string>
<string name="permission_access_fine_location_description">CAPod는 BLE 정보를 받기 위해 정밀 위치 접근 권한을 사용합니다. 앱은 블루투스 헤드폰의 BLE 기술을 사용해 기기의 상태에 접근합니다. CAPod는 이 권한으로 사용자의 위치를 확인하지 않습니다.</string>
<string name="permission_background_location_label">백그라운드 위치 접근</string>
<string name="permission_background_location_description">CAPod는 팝업 기나 자동 연결과 같은 기능을 앱이 꺼져있는 상태에서도 사용할 수 있게 하기 위해 백그라운드 위치 접근 권한을 사용합니다. 백그라운드 위치 접근 권한은 백그라운드에서도 BLE 정보를 받을 수 있게 합니다. CAPod는 이 권한으로 사용자의 위치를 확인하지 않습니다.</string>
<string name="permission_background_location_description">CAPod는 팝업 띄우기나 자동 연결과 같은 기능을 앱이 꺼져있는 상태에서도 사용할 수 있게 하기 위해 백그라운드 위치 접근 권한을 사용합니다. 백그라운드 위치 접근 권한은 백그라운드에서도 BLE 정보를 받을 수 있게 합니다. CAPod는 이 권한으로 사용자의 위치를 확인하지 않습니다.</string>
<string name="permission_ignore_battery_optimizations_label">배터리 사용량 최적화 비활성화</string>
<string name="permission_ignore_battery_optimizations_description">배터리 사용량 최적화는 앱이 백그라운드에서 Bluetooth 신호를 지속적으로 받지 못하게 합니다.</string>
<string name="permission_required_title">다음과 같은 권한이 필요합니다:</string>
@@ -235,7 +247,7 @@
<string name="pods_connection_state_unknown_label">연결 상태 알 수 없음</string>
<string name="pods_unknown_raw_data_label">Raw data</string>
<string name="pods_unknown_label">알 수 없는 기기</string>
<string name="pods_unknown_contact_dev">알 수 없는 기기이 비슷한 형식으로 정보를 보내는 기기인 것 같습니다. 제게 알려주시면 앱에 해당 기기 지원을 추가해 드릴게요 :)</string>
<string name="pods_unknown_contact_dev">알 수 없는 기기이지만, 비슷한 형식으로 정보를 보내는 기기인 것 같습니다. 제게 알려주시면 앱에 해당 기기 지원을 추가해 드릴게요 :)</string>
<string name="pods_none_label_short">기기 없음</string>
<string name="pods_charging_label">충전 중</string>
<string name="pods_charging_optimized_label">최적화됨</string>
@@ -487,6 +499,10 @@
<string name="reaction_sleep_channel_label">수면 감지</string>
<string name="reaction_sleep_notification_title">수면 감지로 일시 정지됨</string>
<string name="reaction_sleep_notification_text">%1$s에서 잠든 것을 감지하여 음악이 일시 정지되었습니다. 기기 설정에서 이 기능을 비활성화할 수 있습니다.</string>
<string name="reaction_charged_channel_label">충전 완료 알림</string>
<string name="reaction_charged_notification_title">충전 완료</string>
<string name="reaction_charged_notification_text_full">%1$s이(가) 완전히 충전되었습니다.</string>
<string name="reaction_charged_notification_text_partial">%1$s이(가) %2$d%%까지 충전되었습니다.</string>
<string name="device_settings_rename_label">이름 바꾸기</string>
<string name="device_settings_rename_hint">기기 이름</string>
<string name="device_settings_rename_confirm">이름 바꾸기</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Туташуу калкыма терезесин көрсөтүү</string>
<string name="settings_popup_connected_description">Түзмөк биринчи жолу туташканда калкыма терезени көрсөтүү.</string>
<string name="settings_popup_info_not_in_app">Калкыма терезелер колдонмодо болбогондо гана көрсөтүлөт.</string>
<string name="settings_charged_notification_label">Заряддалды деген билдирүү</string>
<string name="settings_charged_notification_description">Заряддалып жаткандын баары белгиленген заряд деңгээлине жеткенде билдирүү жөнөтүлөт.</string>
<string name="settings_charged_threshold_label">Максаттуу заряд деңгээли</string>
<string name="settings_charged_scope_label">Көзөмөлдөнүүчү батареялар</string>
<string name="settings_charged_scope_pods_label">Гарнитурлар гана</string>
<string name="settings_charged_scope_case_label">Кап гана</string>
<string name="settings_charged_scope_both_label">Гарнитурлар жана кап</string>
<string name="device_settings_experimental_title">Эксперименталдык функция</string>
<string name="device_settings_experimental_description">Бул функция азырынча бардык түзмөктөрдө сыналган жок. Эгер бир нерсе туура иштебесе, отладка журналы менен маселе ачыңыз.</string>
<string name="device_settings_experimental_action">Маселе трекерин ачуу</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Мүчүлүштүктөрдү оңдоо</string>
<string name="settings_general_label">Орнотуулар</string>
<string name="settings_general_description">Бүткүл колдонмого таасир этүүчү жалпы оңдоолор.</string>
<string name="settings_overview_hide_unmatched_label">Дал келбеген түзмөктөрдү жашыруу</string>
<string name="settings_overview_hide_unmatched_description">Профилдериңиздин эч бирине дал келбеген жакын жердеги түзмөктөрдү, мисалы башка адамдардын AirPods\'ун, чолпондо көрсөтпөө.</string>
<string name="settings_acknowledgements_label">Ыраазычылыктар</string>
<string name="settings_debug_autoreports_label">Автоматтык ката отчеттору</string>
<string name="settings_debug_autoreports_description">Маселелерди автоматтык түрдө кабарлайт, мис., колдонмонун бузулушу жөнүндө маалымат, ошентип мен аны кантип оңдоону аныктай алам.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth өчүрүлгөн, аны күйгүзүңүз ;)</string>
<string name="overview_monitoring_active_label">Түзмөктөрдү издөөдө</string>
<string name="overview_monitoring_active_description">Түзмөгүңүз жакын жана активдүү экенин текшериңиз.</string>
<string name="overview_troubleshoot_suggestion_label">Туташтырылган, бирок маалымат жок</string>
<string name="overview_troubleshoot_suggestion_description">Түзмөгүңүз туташтырылган, бирок CAPod андан жандуу маалымат алып жаткан жок. Телефонуңузга шайкештик параметри керек болушу мүмкүн — кыйынчылыктарды аныктагыч аны автоматтык түрдө тапкыла кыла алат.</string>
<string name="overview_troubleshoot_suggestion_action">Кыйынчылыктарды аныктагычты иштетүү</string>
<string name="overview_unmatched_devices_label">Дал келбеген түзмөктөр</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d түзмөк профилсиз</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Уйку аныктоо</string>
<string name="reaction_sleep_notification_title">Уйку аныктоо аркылуу токтотулду</string>
<string name="reaction_sleep_notification_text">%1$s сиздин уктап калганыңызды аныктады, ошондуктан музыкаңыз токтотулду. Муну түзмөк жөндөөлөрүнөн өчүрсөңүз болот.</string>
<string name="reaction_charged_channel_label">Заряддалды деген билдирүү</string>
<string name="reaction_charged_notification_title">Заряддоо аяктады</string>
<string name="reaction_charged_notification_text_full">%1$s толук заряддалды.</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% заряддалды.</string>
<string name="device_settings_rename_label">Ат өзгөртүү</string>
<string name="device_settings_rename_hint">Түзмөк аты</string>
<string name="device_settings_rename_confirm">Ат өзгөртүү</string>
+19 -3
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">ສະແດງປັອບອັບການເຊື່ອມຕໍ່</string>
<string name="settings_popup_connected_description">ສະແດງປັອບອັບເມື່ອອຸປະກອນເຊື່ອມຕໍ່ຄັ້ງທຳອິດ.</string>
<string name="settings_popup_info_not_in_app">ປ໋ອບອັບຈະສະແດງໃຫ້ເຫັນສະເພາະເມື່ອທ່ານບໍ່ຢູ່ໃນແອັບ.</string>
<string name="settings_charged_notification_label">ການແຈ້ງເຕືອນຊາດໄຟ</string>
<string name="settings_charged_notification_description">ສະແດງການແຈ້ງເຕືອນເມື່ອທຸກສິ່ງທີ່ກໍາລັງສາກໄຟຮອດລະດັບທີ່ກໍານົດ.</string>
<string name="settings_charged_threshold_label">ລະດັບການສາກໄຟເປົ້າໝາຍ</string>
<string name="settings_charged_scope_label">ແບັດເຕີລີທີ່ຕິດຕາມ</string>
<string name="settings_charged_scope_pods_label">ສະເພາະ Pods</string>
<string name="settings_charged_scope_case_label">ສະເພາະກ່ອງ</string>
<string name="settings_charged_scope_both_label">Pods ແລະກ່ອງ</string>
<string name="device_settings_experimental_title">ຟີເຈີທົດລອງ</string>
<string name="device_settings_experimental_description">ຟີເຈີນີ້ຍັງບໍ່ໄດ້ຮັບການທົດສອບໃນທຸກອຸປະກອນ. ຖ້າມີບາງຢ່າງທີ່ບໍ່ເຮັດວຽກຢ່າງຖືກຕ້ອງ, ກະລຸນາເປີດ issue ພ້ອມ debug log.</string>
<string name="device_settings_experimental_action">ເປີດ Issue Tracker</string>
@@ -91,8 +98,8 @@
<string name="debug_debuglog_recording_progress">ກໍາລັງບັນທຶກບັນທຶກດີບັກ</string>
<string name="debug_debuglog_record_action">ບັນທຶກບັນທຶກດີບັກ</string>
<string name="debug_debuglog_stop_action">ຢຸດການບັນທຶກ</string>
<string name="debug_debuglog_sensitive_information_message">ໄຟລ໌ທີ່ສ້າງຂຶ້ນມີຂໍ້ມູນທີ່ລະອຽດອ່ອນ (ຕົວຢ່າງ: ລາຍລະອຽດອຸປະກອນ Bluetooth). ແບ່ງປັນມັນກັບຝ່າຍທີ່ເຊື່ອຖືໄດ້ເທົ່ານັ້ນ.</string>
<string name="settings_debuglog_explanation">ຄຸນສົມບັດນີ້ບັນທຶກທຸກຢ່າງທີ່ແອັບກລັງເຮັດໃສ່ໃນໄຟລ໌ທີ່ສາມາດແບ່ງປັນໄດ້. ໄຟລ໌ທີ່ສ້າງຂຶ້ນມີຂໍ້ມູນທີ່ລະອຽດອ່ອນ (ຕົວຢ່າງ: ລາຍລະອຽດອຸປະກອນ Bluetooth). ແບ່ງປັນມັນກັບຝ່າຍທີ່ເຊື່ອຖືໄດ້ເທົ່ານັ້ນ (ຕົວຢ່າງ: ຜູ້ພັດທະນາທີ່ກລັງແກ້ໄຂບັນຫາ).</string>
<string name="debug_debuglog_sensitive_information_message">ໄຟລ໌ທີ່ສ້າງຂຶ້ນມີຂໍ້ມູນທີ່ລະອຽດອ່ອນ (ເຊັ່ນ: ລາຍລະອຽດອຸປະກອນ Bluetooth). ແບ່ງປັນໃຫ້ສະເພາະຜູ້ທີ່ໄວ້ໃຈໄດ້ເທົ່ານັ້ນ.</string>
<string name="settings_debuglog_explanation">ຟີເຈີນີ້ບັນທຶກທຸກສິ່ງທີ່ແອັບກໍາລັງເຮັດໃສ່ໃນໄຟລ໌ທີ່ແບ່ງປັນໄດ້. ໄຟລ໌ທີ່ສ້າງຂຶ້ນມີຂໍ້ມູນທີ່ລະອຽດອ່ອນ (ເຊັ່ນ: ລາຍລະອຽດອຸປະກອນ Bluetooth). ແບ່ງປັນໃຫ້ສະເພາະຜູ້ທີ່ໄວ້ໃຈໄດ້ (ເຊັ່ນ: ນັກພັດທະນາທີ່ກໍາລັງແກ້ໄຂບັນຫາ) ເທົ່ານັ້ນ.</string>
<string name="settings_support_installid_label">ID ການຕິດຕັ້ງ</string>
<string name="settings_support_installid_desc">ບົດລາຍງານຂໍ້ຜິດພາດອັດຕະໂນມັດແມ່ນບໍ່ເປີດເຜີຍຊື່. ແບ່ງປັນ ID ຕິດຕັ້ງຂອງທ່ານຖ້າຜູ້ພັດທະນາຕ້ອງການຊອກຫາບົດລາຍງານຂໍ້ຜິດພາດຂອງທ່ານ.</string>
<string name="settings_support_label">ການຊ່ວຍເຫຼືອ</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">ດີບັກ</string>
<string name="settings_general_label">ການຕັ້ງຄ່າ</string>
<string name="settings_general_description">ການປັບແຕ່ງທົ່ວໄປທີ່ສົ່ງຜົນກະທົບຕໍ່ແອັບທັງໝົດ.</string>
<string name="settings_overview_hide_unmatched_label">຋່ອນອຸປະກອນທີ່ໄມ່ຕໍງກັນ</string>
<string name="settings_overview_hide_unmatched_description">ບໍ່ສະແດງອຸປະກອນໃກ້ທີ່ໄມ່ຕໍງກັບໂປຣໄຟລ໌ຂອງທ່ານໃນບັນທຶກປະກອບການ, ເຊັ່ນ: AirPods ຂອງຄນອື່ນ.</string>
<string name="settings_acknowledgements_label">ການຮັບຮູ້</string>
<string name="settings_debug_autoreports_label">ລາຍງານຂໍ້ບົກພ່ອງອັດຕະໂນມັດ</string>
<string name="settings_debug_autoreports_description">ລາຍງານບັນຫາໂດຍອັດຕະໂນມັດ, ຕົວຢ່າງ: ລາຍລະອຽດກ່ຽວກັບການຂັດຂ້ອງຂອງແອັບ ເພື່ອໃຫ້ຂ້ອຍສາມາດຫາວິທີແກ້ໄຂໄດ້.</string>
@@ -160,7 +169,7 @@
<string name="troubleshooter_title">ຕົວແກ້ໄຂບັນຫາ</string>
<string name="troubleshooter_summary">ກວດຫາ ແລະ ແກ້ໄຂບັນຫາການເຊື່ອມຕໍ່ Bluetooth.</string>
<string name="troubleshooter_ble_intro_title">ການອອກອາກາດ Bluetooth Low Energy</string>
<string name="troubleshooter_ble_intro_body1">AirPods (ແລະຫູຟັງທີ່ຄ້າຍຄືກັນ) ອອກອາກາດຂໍ້ມູນສະຖານະໂດຍໃຊ້ເທັກໂນໂລຢີ BLE ທີ່ເອີ້ນວ່າ \"ການໂຄສະນາ\" . ໂທລະສັບບາງລຸ້ນບໍ່ໄດ້ປະຕິບັດເທັກໂນໂລຢີນີ້ຢ່າງຖືກຕ້ອງ. CAPod ສາມາດພະຍາຍາມແກ້ໄຂບັນຫານີ້ໂດຍການລອງຕົວເລືອກຄວາມເຂົ້າກັນໄດ້ຕ່າງໆຈົນກວ່າຈະໄດ້ຮັບຂໍ້ມູນ. ເລີ່ມການຫຼິ້ນເພງໃນຫູຟັງຂອງທ່ານ ແລະວາງໄວ້ໃກ້ກັບໂທລະສັບຂອງທ່ານ, ຈາກນັ້ນເລີ່ມຂະບວນການ.</string>
<string name="troubleshooter_ble_intro_body1">AirPods (ແລະຫູຟັງທີ່ຄ້າຍຄືກັນ) ອອກອາກາດຂໍ້ມູນສະຖານະໂດຍໃຊ້ເທັກໂນໂລຢີ BLE ທີ່ເອີ້ນວ່າ \"ການໂຄສະນາ\". ໂທລະສັບບາງລຸ້ນບໍ່ໄດ້ປະຕິບັດເທັກໂນໂລຢີນີ້ຢ່າງຖືກຕ້ອງ. CAPod ສາມາດພະຍາຍາມແກ້ໄຂບັນຫານີ້ໂດຍການລອງຕົວເລືອກຄວາມເຂົ້າກັນໄດ້ຕ່າງໆຈົນກວ່າຈະໄດ້ຮັບຂໍ້ມູນ. ເລີ່ມການຫຼິ້ນເພງໃນຫູຟັງຂອງທ່ານ ແລະວາງໄວ້ໃກ້ກັບໂທລະສັບຂອງທ່ານ, ຈາກນັ້ນເລີ່ມຂະບວນການ.</string>
<string name="troubleshooter_ble_intro_start_action">ເລີ່ມການແກ້ໄຂບັນຫາ</string>
<string name="troubleshooter_ble_process_title">ກຳລັງແກ້ໄຂບັນຫາ</string>
<string name="troubleshooter_ble_process_subtile">ແຕ່ລະຂັ້ນຕອນໃຊ້ເວລາ 5-10 ວິນາທີ</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ຖືກປິດ, ເປີດມັນ ;)</string>
<string name="overview_monitoring_active_label">ກຳລັງຕິດຕາມອຸປະກອນ</string>
<string name="overview_monitoring_active_description">ໃຫ້ແນ່ໃຈວ່າອຸປະກອນຂອງທ່ານຢູ່ໃກ້ ແລະ ເຮັດວຽກຢູ່.</string>
<string name="overview_troubleshoot_suggestion_label">ເຊື່ອມຕໍ່ແລ້ວ, ຜູ້ໃດ້ຂໍ້ມູນ</string>
<string name="overview_troubleshoot_suggestion_description">ອຸປະກອນຂອງທ່ານເຊື່ອມຕໍ່ແລ້ວ, ຜູ້ໃດ້ CAPod ບໍ່ໄດ້ຮັບຂໍ້ມູນລິວໃດ້ຈາກມັນ. ໂທລະສັບຂອງທ່ານອາດຕ້ອງການຕົວເລືອກຄວາມເຂົ້າກັນໄດ້ — ຕົວແກ້ໄຂບັນຫາສາມາດພະຍາຍາມຫາຕົວເລືອກທີ່ເຫມາະສະຫມໂດຍອັດຕະໂນມັດ.</string>
<string name="overview_troubleshoot_suggestion_action">ແລ່ນຕົວແກ້ໄຂບັນຫາ</string>
<string name="overview_unmatched_devices_label">ອຸປະກອນທີ່ບໍ່ກົງກັນ</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">%d ອຸປະກອນທີ່ບໍ່ມີໂປຣໄຟລ໌ກົງກັນ</item>
@@ -485,6 +497,10 @@
<string name="reaction_sleep_channel_label">ການກວດຈັບການນອນ</string>
<string name="reaction_sleep_notification_title">ຢຸດຊົ່ວຄາວໂດຍການກວດຈັບການນອນ</string>
<string name="reaction_sleep_notification_text">%1$s ລາຍງານວ່າທ່ານຫຼັບໄປ, ດັ່ງນັ້ນດົນຕີຂອງທ່ານໄດ້ຖືກຢຸດຊົ່ວຄາວ. ທ່ານສາມາດປິດການໃຊ້ງານນີ້ໄດ້ໃນການຕັ້ງຄ່າອຸປະກອນ.</string>
<string name="reaction_charged_channel_label">ການແຈ້ງເຕືອນຊາດໄຟ</string>
<string name="reaction_charged_notification_title">ສາກໄຟສຳເນັດແລ້ວ</string>
<string name="reaction_charged_notification_text_full">%1$s ສາກໄຟເຕັມແລ້ວ.</string>
<string name="reaction_charged_notification_text_partial">%1$s ສາກໄຟໄດ້ຖຶງ %2$d%% ແລ້ວ.</string>
<string name="device_settings_rename_label">ເປລີ່ຊື່</string>
<string name="device_settings_rename_hint">ຊື່ອຸປະກອນ</string>
<string name="device_settings_rename_confirm">ເປລີ່ຊື່</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Rodyti prisijungimo iškylantįjį langą</string>
<string name="settings_popup_connected_description">Rodyti iškylantįjį langą, kai įrenginys prisijungia pirmą kartą.</string>
<string name="settings_popup_info_not_in_app">Iskylantieji langai rodomi tik tada, kai nesate programoje.</string>
<string name="settings_charged_notification_label">Įkrovimo pranešimas</string>
<string name="settings_charged_notification_description">Rodyti pranešimą, kai viskas, kas įkraunama, pasiekia tikslinį įkrovimo lygį.</string>
<string name="settings_charged_threshold_label">Tikslingas įkrovimo lygis</string>
<string name="settings_charged_scope_label">Stebimos baterijos</string>
<string name="settings_charged_scope_pods_label">Tik ausinukai</string>
<string name="settings_charged_scope_case_label">Tik dėklas</string>
<string name="settings_charged_scope_both_label">Ausinukai ir dėklas</string>
<string name="device_settings_experimental_title">Eksperimentinė funkcija</string>
<string name="device_settings_experimental_description">Ši funkcija dar neišbandyta visuose įrenginiuose. Jei kažkas neveikia tinkamai, atidarykite problemų sąrašą su derinimo žurnalu.</string>
<string name="device_settings_experimental_action">Atidaryti problemų sąrašą</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Derinimas</string>
<string name="settings_general_label">Nustatymai</string>
<string name="settings_general_description">Bendrieji pakeitimai, turintys įtakos visai programai.</string>
<string name="settings_overview_hide_unmatched_label">Slėpti neatitinkančius įrenginius</string>
<string name="settings_overview_hide_unmatched_description">Nerodykite netoliese esančių įrenginius, kurie neatitinka nė vieno jūsų profilio apžvalgoje, pvz. kitų žmonų AirPods.</string>
<string name="settings_acknowledgements_label">Padėkos</string>
<string name="settings_debug_autoreports_label">Automatinės klaidų ataskaitos</string>
<string name="settings_debug_autoreports_description">Automatiškai praneša apie problemas, pvz., išsamią informaciją apie programos strigtį, kad galėčiau išsiaiškinti, kaip ją ištaisyti.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">„Bluetooth\" išjungtas, įjunkite jį ;)</string>
<string name="overview_monitoring_active_label">Stebimi įrenginiai</string>
<string name="overview_monitoring_active_description">Įsitikinkite, kad jūsų įrenginys yra netoliese ir aktyvus.</string>
<string name="overview_troubleshoot_suggestion_label">Prisijungta, bet nėra duomenų</string>
<string name="overview_troubleshoot_suggestion_description">Jūsų įrenginys yra prisijungęs, tačiau CAPod negauna jokių tiesioginių duomenų iš jo. Jūsų telefonui gali reikėti suderinamumo parinkties — problemų sprendiklis gali bandyti ją rasti automatiškai.</string>
<string name="overview_troubleshoot_suggestion_action">Paleisti problemų sprendiklį</string>
<string name="overview_unmatched_devices_label">Nesutapę įrenginiai</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d įrenginys be atitinkamo profilio</item>
@@ -500,6 +512,10 @@
<string name="reaction_sleep_channel_label">Miego aptikimas</string>
<string name="reaction_sleep_notification_title">Pristabdyta miego aptikimo</string>
<string name="reaction_sleep_notification_text">%1$s pranešė, kad užmigote, todėl jūsų muzika buvo pristabdyta. Tai galite išjungti įrenginio nustatymuose.</string>
<string name="reaction_charged_channel_label">Įkrovimo pranešimas</string>
<string name="reaction_charged_notification_title">Įkrovimas baigtas</string>
<string name="reaction_charged_notification_text_full">%1$s viškai įkrautas.</string>
<string name="reaction_charged_notification_text_partial">%1$s įkrautas iki %2$d%%.</string>
<string name="device_settings_rename_label">Pervadinti</string>
<string name="device_settings_rename_hint">Įrenginio pavadinimas</string>
<string name="device_settings_rename_confirm">Pervadinti</string>
+35 -19
View File
@@ -1,34 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="general_share_action">Dalīties</string>
<string name="general_share_action">Kopīgot</string>
<string name="general_done_action">Gatavs</string>
<string name="general_cancel_action">Atcelt</string>
<string name="general_copy_action">Kopēt</string>
<string name="general_copy_action">Ievietot starpliktuvē</string>
<string name="general_thank_you_label">Paldies</string>
<string name="general_upgrade_action">Jaunināt</string>
<string name="common_feature_requires_pro_msg">Jauniniet, lai atbloķētu.</string>
<string name="common_upgrade_required_label">Nepieciešams jauninājums</string>
<string name="general_upgrade_action">Uzlabot</string>
<string name="common_feature_requires_pro_msg">Jāuzlabo, lai atslēgtu.</string>
<string name="common_upgrade_required_label">Nepieciešama uzlabošana</string>
<string name="general_donate_action">Ziedot</string>
<string name="general_check_action">Pārbaudīt</string>
<string name="general_close_action">Aizvērt</string>
<string name="general_edit_action">Rediģēt</string>
<string name="general_edit_action">Labot</string>
<string name="general_save_action">Saglabāt</string>
<string name="general_guide_action">Ceļvedis</string>
<string name="general_continue_action">Turpināt</string>
<string name="general_show_action">Rādīt</string>
<string name="general_hide_action">Paslēpt</string>
<string name="general_example_label">Piem.: %s</string>
<string name="upgrade_capod_label">Jaunināt CAPod</string>
<string name="upgrade_capod_description">Iegūstiet papildu funkcijas un atbalstiet izstrādātāju.</string>
<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_popups">Uznirstošs logs, atverot futrāli un savienojoties</string>
<string name="upgrade_capod_label">Uzlabot CAPod</string>
<string name="upgrade_capod_description">Iegūsti papildu iespējas un atbalsti izstrādātāju!</string>
<string name="upgrade_preamble">CAPod ir izstrādājis viens cilvēks. Uzlabošana atslēdz papildu iespējas un palīdz uzturēt lietotnes esamību.</string>
<string name="upgrade_benefit_themes">Izskata pielāgošana</string>
<string name="upgrade_benefit_autoplay">Automātiska atskaņošana un apturēšana</string>
<string name="upgrade_benefit_popups">Uznirstošs logs pēc futrāļa atvēršanas un savienošanās</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>
<string name="upgrade_benefit_device_controls">Ierīces vadīklēšana — troksnis, kātieni un vairāk</string>
<string name="upgrade_benefit_support">Atbalstiet izstrādātāju</string>
<string name="upgrade_benefit_disclaimer">Funkciju pieejamība atkarīga no jūsu ausţu un ierīces.</string>
<string name="upgrade_benefit_device_controls">Ierīces vadīklas — troksnis, kātieni un vairāk</string>
<string name="upgrade_benefit_support">Izstrādātāja atbalstīšana</string>
<string name="upgrade_benefit_disclaimer">Iespēju pieejamība atkarīga no austiņam un ierīces.</string>
<string name="upgrade_screen_options_description">Vienādas funkcijas, atšķirīgas cenas. Abonements ietver bezmaksas izmēģinājumu un var tikt atcelts jebkurā laikā.</string>
<string name="upgrade_screen_subscription_trial_action">Sākt bezmaksas izmēģinājumu</string>
<string name="upgrade_screen_subscription_action">Abonēt gadā</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Rādīt savienojuma uznirstošo logu</string>
<string name="settings_popup_connected_description">Rādīt uznirstošo logu, kad ierīce pirmo reizi izveido savienojumu.</string>
<string name="settings_popup_info_not_in_app">Uznirstošie logi tiek rādīti tikai tad, kad neatrodaties lietotnē.</string>
<string name="settings_charged_notification_label">Uzlādes paziņojums</string>
<string name="settings_charged_notification_description">Rādīt paziņojumu, kad viss, kas tiek uzlādēts, sasniedz mērķa uzlādes līmeni.</string>
<string name="settings_charged_threshold_label">Mērķa uzlādes līmenis</string>
<string name="settings_charged_scope_label">Uzraudzītās baterijas</string>
<string name="settings_charged_scope_pods_label">Tikai klausules</string>
<string name="settings_charged_scope_case_label">Tikai futrālis</string>
<string name="settings_charged_scope_both_label">Klausules un futrālis</string>
<string name="device_settings_experimental_title">Eksperimentāla funkcija</string>
<string name="device_settings_experimental_description">Šī funkcija vēl nav pārbaudīta visās ierīcēs. Ja kaut kas nedarbojas pareizi, lūdzu atveriet problēmziņojumu ar atkļūdošanas žurnālu.</string>
<string name="device_settings_experimental_action">Atvērt problēmu izsekotāju</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Atkļūdošana</string>
<string name="settings_general_label">Iestatījumi</string>
<string name="settings_general_description">Vispārīgi pielāgojumi, kas ietekmē visu lietotni.</string>
<string name="settings_overview_hide_unmatched_label">Slēpt neatbilstošās ierīces</string>
<string name="settings_overview_hide_unmatched_description">Nerādīt tuvumā esošās ierīces, kas neatbilst nevienam no jūsu profiliem pārskatā, piemēram, citu cilvēku AirPods.</string>
<string name="settings_acknowledgements_label">Pateicības</string>
<string name="settings_debug_autoreports_label">Automātiski kļūdu ziņojumi</string>
<string name="settings_debug_autoreports_description">Automātiski ziņo par problēmām, piem., informāciju par lietotnes avāriju, lai es varētu izdomāt, kā to labot.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ir atspējots, iespējojiet to ;)</string>
<string name="overview_monitoring_active_label">Ierīču uzraudzība</string>
<string name="overview_monitoring_active_description">Pārliecinieties, ka jūsu ierīce ir tuvumā un aktīva.</string>
<string name="overview_troubleshoot_suggestion_label">Savienots, bet nav datu</string>
<string name="overview_troubleshoot_suggestion_description">Jūsu ierīce ir savienota, taču CAPod nesaņem no tās nekādus tiešraides datus. Jūsu tālrunim, iespējams, nepieciešama saderības opcija — problēmu risinātājs var mēģināt to atrast automātiski.</string>
<string name="overview_troubleshoot_suggestion_action">Palaist problēmu risinātāju</string>
<string name="overview_unmatched_devices_label">Neatbilstošas ierīces</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="zero">%d ierīce bez atbilstoša profila</item>
@@ -433,14 +445,14 @@
<string name="device_settings_category_sound_label">Skaņa</string>
<string name="device_settings_category_controls_label">Vadīklēšana</string>
<string name="device_settings_nc_one_airpod_label">ANC ar vienu austiņu</string>
<string name="device_settings_nc_one_airpod_description">Saglabāt trokšņu slāpēšanu aktīvu ar tikai vienu AirPod</string>
<string name="device_settings_nc_one_airpod_description">Saglabāt trokšņu slāpēšanu aktīvu tikai ar vienu AirPod</string>
<string name="device_settings_personalized_volume_label">Personālizots skaļumā</string>
<string name="device_settings_personalized_volume_description">Pielāgo multivides skaļumu atbilstoši apkārtējai videi</string>
<string name="device_settings_personalized_volume_description">Pielāgot multivides skaļumu atbilstoši videi</string>
<string name="device_settings_conversation_awareness_description">Samazināt multivides skaļumu un troksni, kad kāds runā ar jums</string>
<string name="device_settings_tone_volume_label">Dziľľu skaļums</string>
<string name="device_settings_tone_volume_description">Apstiprinājuma skaņu un zvanāmāsignalājumu skaļums</string>
<string name="device_settings_adaptive_noise_label">Adaptīvais audīo troksnis</string>
<string name="device_settings_adaptive_noise_description">Cik daudz apkārtējās vides trokšņa tiek caurlaistu</string>
<string name="device_settings_adaptive_noise_description">Cik daudz vides trokšņu tiek ielaisti</string>
<string name="device_settings_adaptive_noise_requires_adaptive">Nepieciešama adaptīvā trokšņu kontrole</string>
<string name="device_settings_pending_info">Izmaiņas stājas spēkā, kad AirPods ir ausīs</string>
<string name="device_settings_press_speed_label">Nospiēšanas ātrums</string>
@@ -459,7 +471,7 @@
<string name="device_settings_volume_swipe_length_description">Lai novērstu nejaušas skaļuma izmaiņas, izvēlieties, cik ilgi gaidīt starp vilkšanas žestiem.</string>
<string name="device_settings_volume_swipe_length_default">Noklusējuma</string>
<string name="device_settings_volume_swipe_length_longer">Garāks</string>
<string name="device_settings_volume_swipe_length_longest">Visgarāks</string>
<string name="device_settings_volume_swipe_length_longest">Garākais</string>
<string name="device_settings_end_call_mute_mic_label">Zvanāmā vadība</string>
<string name="device_settings_end_call_mute_mic_description">Izvēlieties, kas notiek, nospiežot kātienu zvanāšanas laikā</string>
<string name="device_settings_end_call_mute_mic_option_a_title">Vienu reizi nospiežot, beidz zvanu</string>
@@ -495,6 +507,10 @@
<string name="reaction_sleep_channel_label">Miega noteikšana</string>
<string name="reaction_sleep_notification_title">Apturēts ar miega noteikšanu</string>
<string name="reaction_sleep_notification_text">%1$s ziņoja, ka jūs aizmigsāt, tāpēc mūzika tika pauzēta. To var atspējot ierīces iestatījumos.</string>
<string name="reaction_charged_channel_label">Uzlādes paziņojums</string>
<string name="reaction_charged_notification_title">Uzlāde pabeigta</string>
<string name="reaction_charged_notification_text_full">%1$s ir pilnībā uzlādēts.</string>
<string name="reaction_charged_notification_text_partial">%1$s ir uzlādēts līdz %2$d%%.</string>
<string name="device_settings_rename_label">Pārdēvēt</string>
<string name="device_settings_rename_hint">Ierīces nosaukums</string>
<string name="device_settings_rename_confirm">Pārdēvēt</string>
+17 -1
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Прикажи скокачки прозорец за поврзување</string>
<string name="settings_popup_connected_description">Прикажи скокачки прозорец кога уредот се поврзува за прв пат.</string>
<string name="settings_popup_info_not_in_app">Скокачките прозорци се прикажуваат само кога не сте во апликацијата.</string>
<string name="settings_charged_notification_label">Известување за наполнетост</string>
<string name="settings_charged_notification_description">Прикажи известување откако сè што се полни ќе го достигне целното ниво на полнење.</string>
<string name="settings_charged_threshold_label">Целно ниво на полнење</string>
<string name="settings_charged_scope_label">Следени батерии</string>
<string name="settings_charged_scope_pods_label">Само слушалки</string>
<string name="settings_charged_scope_case_label">Само куќиште</string>
<string name="settings_charged_scope_both_label">Слушалки и куќиште</string>
<string name="device_settings_experimental_title">Експериментална функција</string>
<string name="device_settings_experimental_description">Оваа функција сè уште не е тестирана на сите уреди. Ако нешто не работи правилно, ве молиме отворете проблем со дневник за дебагирање.</string>
<string name="device_settings_experimental_action">Отвори следач на проблеми</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Дијагностика</string>
<string name="settings_general_label">Поставки</string>
<string name="settings_general_description">Општи прилагодувања што влијаат на целата апликација.</string>
<string name="settings_overview_hide_unmatched_label">Скриј неподударни уреди</string>
<string name="settings_overview_hide_unmatched_description">Не прикажувај блиски уреди кои не се поклопуваат со ниеден профил во прегледот, на пр. AirPods на други луѓе.</string>
<string name="settings_acknowledgements_label">Благодарници</string>
<string name="settings_debug_autoreports_label">Автоматски извештаи за грешки</string>
<string name="settings_debug_autoreports_description">Автоматски пријавува проблеми, на пр. детали за пад на апликацијата за да можам да откријам како да го поправам.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth е оневозможен, овозможете го ;)</string>
<string name="overview_monitoring_active_label">Следење на уреди</string>
<string name="overview_monitoring_active_description">Уверете се дека вашиот уред е во близина и активен.</string>
<string name="overview_troubleshoot_suggestion_label">Поврзан, но нема податоци</string>
<string name="overview_troubleshoot_suggestion_description">Уредот е поврзан, но CAPod не прима живи податоци од него. Можеби на телефонот му треба опција за компатибилност — решавањето проблеми може автоматски да пронајде такава.</string>
<string name="overview_troubleshoot_suggestion_action">Стартувај решавање проблеми</string>
<string name="overview_unmatched_devices_label">Несовпаднати уреди</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d уред без совпаѓачки профил</item>
@@ -362,7 +374,7 @@
<string name="support_debuglog_failed_empty_log">Неуспешно: датотеката со дневник е празна</string>
<string name="support_debuglog_failed_missing_log">Неуспешно: датотеката со дневник недостасува</string>
<string name="support_debuglog_failed_corrupt_zip">Неуспешно: zip датотеката е оштетена</string>
<string name="support_debuglog_failed_zip_failed">Неуспешно: компресијата не успеа</string>
<string name="support_debuglog_failed_zip_failed">Неуспешно: компресирањето не успеа</string>
<!-- Contact form -->
<string name="support_contact_label">Контактирајте го развивачот</string>
<string name="support_contact_desc">Пополнете формулар за да му пратите е-пошта на развивачот.</string>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Детекција на спиење</string>
<string name="reaction_sleep_notification_title">Паузирано од Детекција на спиење</string>
<string name="reaction_sleep_notification_text">%1$s пријави дека заспавте, па вашата музика беше паузирана. Ова можете да го оневозможите во поставките за уредот.</string>
<string name="reaction_charged_channel_label">Известување за наполнетост</string>
<string name="reaction_charged_notification_title">Полнењето е завршено</string>
<string name="reaction_charged_notification_text_full">%1$s е целосно наполнет.</string>
<string name="reaction_charged_notification_text_partial">%1$s е наполнет до %2$d%%.</string>
<string name="device_settings_rename_label">Преименување</string>
<string name="device_settings_rename_hint">Име на уредот</string>
<string name="device_settings_rename_confirm">Преименување</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">കണക്ഷൻ പോപ്പ്അപ്പ് കാണിക്കുക</string>
<string name="settings_popup_connected_description">ഉപകരണം ആദ്യമായി കണക്റ്റുചെയ്യുമ്പോൾ ഒരു പോപ്പ്അപ്പ് കാണിക്കുക.</string>
<string name="settings_popup_info_not_in_app">നിങ്ങൾ ആപ്പിൽ ഇല്ലാത്തപ്പോൾ മാത്രം പോപ്പപ്പുകൾ കാണിക്കും.</string>
<string name="settings_charged_notification_label">ചാർജ്ജ് അറിയിപ്പ്</string>
<string name="settings_charged_notification_description">ചാർജ്ജ് ചെയ്യുന്ന എല്ലാം ലക്ഷ്യ ചാർജ്ജ് നിലയിലെത്തുമ്പോൾ ഒരു അറിയിപ്പ് കാണിക്കുക.</string>
<string name="settings_charged_threshold_label">ലക്ഷ്യ ചാർജ്ജ് നില</string>
<string name="settings_charged_scope_label">നിരീക്ഷിക്കുന്ന ബാറ്ററികൾ</string>
<string name="settings_charged_scope_pods_label">പോഡുകൾ മാത്രം</string>
<string name="settings_charged_scope_case_label">കേസ് മാത്രം</string>
<string name="settings_charged_scope_both_label">പോഡുകളും കേസും</string>
<string name="device_settings_experimental_title">പരീക്ഷണ സവിശേഷത</string>
<string name="device_settings_experimental_description">ഈ സവിശേഷത ഇതുവരെ എല്ലാ ഡിവൈസുകളിലും പരീക്ഷിച്ചിട്ടില്ല. എന്തെങ്കിലും ശരിയായി പ്രവർത്തിക്കുന്നില്ലെങ്കിൽ, ദയവായി ഒരു ഡീബഗ് ലോഗ് സഹിതം ഒരു ഇഷ്യൂ തുറക്കുക.</string>
<string name="device_settings_experimental_action">ഇഷ്യൂ ട്രാക്കർ തുറക്കുക</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">ഡീബഗ്</string>
<string name="settings_general_label">ക്രമീകരണങ്ങൾ</string>
<string name="settings_general_description">മുഴുവൻ ആപ്പിനെയും ബാധിക്കുന്ന പൊതുവായ മാറ്റങ്ങൾ.</string>
<string name="settings_overview_hide_unmatched_label">പൊരുത്തപ്പെടാത്ത ഉപകരണങ്ങൾ മറയ്ക്കുക</string>
<string name="settings_overview_hide_unmatched_description">നിങ്ങളുടെ ഒരു പ്രൊഫൈലുമായും പൊരുത്തപ്പെടാത്ത അടുത്തുള്ള ഉപകരണങ്ങൾ അവലോകനത്തിൽ കാണിക്കരുത്, ഉദാ. മറ്റുള്ളവരുടെ AirPods.</string>
<string name="settings_acknowledgements_label">അംഗീകാരങ്ങൾ</string>
<string name="settings_debug_autoreports_label">യാന്ത്രിക ബഗ് റിപ്പോർട്ടുകൾ</string>
<string name="settings_debug_autoreports_description">പ്രശ്നങ്ങൾ യാന്ത്രികമായി റിപ്പോർട്ട് ചെയ്യുന്നു, ഉദാ. ആപ്പ് ക്രാഷിനെക്കുറിച്ചുള്ള വിശദാംശങ്ങൾ, അതുവഴി എനിക്കത് എങ്ങനെ പരിഹരിക്കാമെന്ന് കണ്ടെത്താനാകും.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">ബ്ലൂടൂത്ത് പ്രവർത്തനരഹിതമാണ്, അത് പ്രവർത്തനക്ഷമമാക്കുക ;)</string>
<string name="overview_monitoring_active_label">ഉപകരണങ്ങൾ നിരീക്ഷിക്കുന്നു</string>
<string name="overview_monitoring_active_description">നിങ്ങളുടെ ഉപകരണം സമീപത്തും സജീവവുമാണെന്ന് ഉറപ്പാക്കുക.</string>
<string name="overview_troubleshoot_suggestion_label">കണക്‌റ്റ് ചെയ്‌തു, എന്നാൽ ഡേറ്റ ഇല്ല</string>
<string name="overview_troubleshoot_suggestion_description">നിങ്ങളുടെ ഉപകരണം കണക്‌റ്റ് ചെയ്‌തിരിക്കുന്നു, എന്നാൽ CAPod അതിൽ നിന്ന് തത്സമയ ഡേറ്റ സ്വീകരിക്കുന്നില്ല. നിങ്ങളുടെ ഫോണിന് ഒരു അനുയോജ്യതാ ഓപ്‌ഷൻ ആവശ്യമായി വന്നേക്കാം — ട്രബിൾഷൂട്ടറിന് ഒന്ന് സ്വയംചാലകമായി കണ്ടെത്താൻ ശ്രമിക്കാനാകും.</string>
<string name="overview_troubleshoot_suggestion_action">ട്രബിൾഷൂട്ടർ പ്രവർത്തിപ്പിക്കുക</string>
<string name="overview_unmatched_devices_label">പൊരുത്തമില്ലാത്ത ഉപകരണങ്ങൾ</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">പൊരുത്തമുള്ള പ്രൊഫൈൽ ഇല്ലാത്ത %d ഉപകരണം</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">ഉറക്ക കണ്ടെത്തൽ</string>
<string name="reaction_sleep_notification_title">ഉറക്ക കണ്ടെത്തൽ മൂലം താൽക്കാലികമായി നിർത്തി</string>
<string name="reaction_sleep_notification_text">%1$s നിങ്ങൾ ഉറങ്ങിപ്പോയതായി റിപ്പോർട്ട് ചെയ്തതിനാൽ സംഗീതം താൽക്കാലികമായി നിർത്തി. ഉപകരണ ക്രമീകരണങ്ങളിൽ ഇത് പ്രവർത്തനരഹിതമാക്കാം.</string>
<string name="reaction_charged_channel_label">ചാർജ്ജ് അറിയിപ്പ്</string>
<string name="reaction_charged_notification_title">ചാർജ്ജിംഗ് പൂർണ്ണമായി</string>
<string name="reaction_charged_notification_text_full">%1$s പൂർണ്ണമായും ചാർജ്ജ് ആയി.</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% ആയി ചാർജ്ജ് ചെയ്‌തു.</string>
<string name="device_settings_rename_label">പുനർനാമകരണം ചെയ്യുക</string>
<string name="device_settings_rename_hint">ഉപകരണ നാമം</string>
<string name="device_settings_rename_confirm">പുനർനാമകരണം ചെയ്യുക</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Холболтын попап цонхыг харуулах</string>
<string name="settings_popup_connected_description">Төхөөрөмж анх удаа холбогдоход попап цонхыг харуулна.</string>
<string name="settings_popup_info_not_in_app">Попап нь зөвхөн та аппликейшнд байхгүй үед харагдана.</string>
<string name="settings_charged_notification_label">Цэнэглэгдсэн мэдэгдэл</string>
<string name="settings_charged_notification_description">Цэнэглэгдэж байгаа бүх зүйл зорилтот цэнэглэлтийн түвшинд хүрмэгц мэдэгдэл илгээнэ.</string>
<string name="settings_charged_threshold_label">Зорилтот цэнэглэлтийн түвшин</string>
<string name="settings_charged_scope_label">Хяналттай батарейнууд</string>
<string name="settings_charged_scope_pods_label">Зөвхөн pods</string>
<string name="settings_charged_scope_case_label">Зөвхөн кейс</string>
<string name="settings_charged_scope_both_label">Pods болон кейс</string>
<string name="device_settings_experimental_title">Туршилтын онцлог</string>
<string name="device_settings_experimental_description">Энэ функцийг бүх төхөөрөмж дээр туршиж үзээгүй байна. Хэрэв ямар нэг зүйл буруу ажиллаж байвал debug лог хавсаргаж асуудал нээнэ үү.</string>
<string name="device_settings_experimental_action">Асуудлын жагсаалт нээх</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Дебаг</string>
<string name="settings_general_label">Тохиргоо</string>
<string name="settings_general_description">Апп-н бүх хэсэгт нөлөөлөх ерөнхий тохируулгууд.</string>
<string name="settings_overview_hide_unmatched_label">Тохирохгүй төхөөрөмжүүдийг нуух</string>
<string name="settings_overview_hide_unmatched_description">Таны профайлтай тохирохгүй ойрхон байгаа төхөөрөмжүүдийг, тухайлбал бусад хүмүүсийн AirPods-ийг тоймд харуулахгүй.</string>
<string name="settings_acknowledgements_label">Талархал</string>
<string name="settings_debug_autoreports_label">Автомат алдааны тайлан</string>
<string name="settings_debug_autoreports_description">Апп-н ослын дэлгэрэнгүй мэдээлэл гэх мэт асуудлуудыг автоматаар мэдээлдэг бөгөөд ингэснээр би түүнийг хэрхэн засахаа олж мэдэх боломжтой.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth идэвхгүй байна, идэвхжүүлнэ үү ;)</string>
<string name="overview_monitoring_active_label">Төхөөрөмжүүдийг хайж байна</string>
<string name="overview_monitoring_active_description">Таны төхөөрөмж ойролцоо, идэвхтэй байгаа эсэхийг шалгана уу.</string>
<string name="overview_troubleshoot_suggestion_label">Холбогдсон, гэхдээ өгөгдөл алга</string>
<string name="overview_troubleshoot_suggestion_description">Таны төхөөрөмж холбогдсон боловч CAPod түүнээс шууд өгөгдөл хүлээж авахгүй байна. Утас таны нийцтэй байдлын тохиргоо шаардаж болзошгүй — асуудал шийдвэрлэгч автоматаар нэгийг хайж олохыг оролдож чадна.</string>
<string name="overview_troubleshoot_suggestion_action">Асуудал шийдвэрлэгчийг ажиллуулах</string>
<string name="overview_unmatched_devices_label">Тохирохгүй төхөөрөмжүүд</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">Тохирох профайлгүй %d төхөөрөмж</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Нойрны мэдрэгч</string>
<string name="reaction_sleep_notification_title">Нойрны мэдрэгчээр түр зогссон</string>
<string name="reaction_sleep_notification_text">%1$s таныг унтаж байна гэж мэдээллэсэн тул хөгжим нь түр зогссон. Үүнийг төхөөрөмжийн тохиргооноос идэвхгүй болгож болно.</string>
<string name="reaction_charged_channel_label">Цэнэглэгдсэн мэдэгдэл</string>
<string name="reaction_charged_notification_title">Цэнэглэлт дууссан</string>
<string name="reaction_charged_notification_text_full">%1$s бүрэн цэнэглэгдсэн.</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% хүртэл цэнэглэгдсэн.</string>
<string name="device_settings_rename_label">Нэр өөрчлөх</string>
<string name="device_settings_rename_hint">Төхөөрөмжийн нэр</string>
<string name="device_settings_rename_confirm">Нэр өөрчлөх</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">कनेक्शन पॉपअप दर्शवा</string>
<string name="settings_popup_connected_description">डिव्हाइस पहिल्यांदा कनेक्ट झाल्यावर पॉपअप दर्शवा.</string>
<string name="settings_popup_info_not_in_app">पॉपअप केवळ तेव्हा दाखवले जातात जेव्हा तुम्ही अॅपमध्ये नसता.</string>
<string name="settings_charged_notification_label">चार्ज झाल्याची सूचना</string>
<string name="settings_charged_notification_description">चार्ज होणारी प्रत्येक गोष्ट लक्ष्य चार्ज पातळीवर पोहोचल्यावर एक सूचना दाखवा.</string>
<string name="settings_charged_threshold_label">लक्ष्य चार्ज पातळी</string>
<string name="settings_charged_scope_label">निरीक्षण केलेल्या बॅटऱ्या</string>
<string name="settings_charged_scope_pods_label">केवळ पॉड्स</string>
<string name="settings_charged_scope_case_label">केवळ केस</string>
<string name="settings_charged_scope_both_label">पॉड्स आणि केस</string>
<string name="device_settings_experimental_title">प्रयोगात्मक वैशिष्ट्य</string>
<string name="device_settings_experimental_description">हे वैशिष्ट्य अद्याप सर्व डिव्हाइसवर तपासले गेले नाही. जर काही योग्यरित्या काम करत नसेल, तर कृपया डीबग लॉगसह एक समस्या उघडा.</string>
<string name="device_settings_experimental_action">समस्या ट्रॅकर उघडा</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">डीबग</string>
<string name="settings_general_label">सेटिंग्ज</string>
<string name="settings_general_description">संपूर्ण अॅपवर परिणाम करणारे सामान्य बदल.</string>
<string name="settings_overview_hide_unmatched_label">न जुळणारी उपकरणे लपवा</string>
<string name="settings_overview_hide_unmatched_description">आढावा विभागात तुमच्या कोणत्याही प्रोफाइलशी न जुळणारी जवळची उपकरणे दाखवू नका, उदा. इतर लोकांचे AirPods.</string>
<string name="settings_acknowledgements_label">पोचपावती</string>
<string name="settings_debug_autoreports_label">स्वयंचलित बग अहवाल</string>
<string name="settings_debug_autoreports_description">समस्या स्वयंचलितपणे नोंदवते, उदा. अॅप क्रॅशबद्दल तपशील जेणेकरून मी ते कसे दुरुस्त करायचे हे शोधू शकेन.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">ब्लूटूथ अक्षम आहे, ते सक्षम करा ;)</string>
<string name="overview_monitoring_active_label">डिव्हाइसचे निरीक्षण सुरू आहे</string>
<string name="overview_monitoring_active_description">तुमचे डिव्हाइस जवळ आणि सक्रिय असल्याची खात्री करा.</string>
<string name="overview_troubleshoot_suggestion_label">जोडलेले, पण डेटा नाही</string>
<string name="overview_troubleshoot_suggestion_description">तुमचे उपकरण जोडलेले आहे, पण CAPod त्याच्याकडून कोणताही थेट डेटा प्राप्त करत नाही. तुमच्या फोनला एका सुसंगतता पर्यायाची आवश्यकता असू शकते — समस्या निवारक आपोआप एक शोधण्याचा प्रयत्न करू शकतो.</string>
<string name="overview_troubleshoot_suggestion_action">समस्या निवारक चालवा</string>
<string name="overview_unmatched_devices_label">न जुळणारे डिव्हाइस</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">जुळणारे प्रोफाइल नसलेले %d डिव्हाइस</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">झोप शोध</string>
<string name="reaction_sleep_notification_title">झोप शोधाने थांबवले</string>
<string name="reaction_sleep_notification_text">%1$s ने नोंदवले की तुम्ही झोपी गेलात, त्यामुळे तुमचे संगीत थांबवले गेले. तुम्ही डिव्हाइस सेटिंग्जमध्ये हे अक्षम करू शकता.</string>
<string name="reaction_charged_channel_label">चार्ज झाल्याची सूचना</string>
<string name="reaction_charged_notification_title">चार्जिंग पूर्ण</string>
<string name="reaction_charged_notification_text_full">%1$s पूर्णपणे चार्ज झाले आहे.</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% पर्यंत चार्ज झाले आहे.</string>
<string name="device_settings_rename_label">नाव बदला</string>
<string name="device_settings_rename_hint">डिव्हाइसचे नाव</string>
<string name="device_settings_rename_confirm">नाव बदला</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Tunjukkan pop timbul sambungan</string>
<string name="settings_popup_connected_description">Tunjukkan pop timbul apabila peranti disambungkan buat kali pertama.</string>
<string name="settings_popup_info_not_in_app">Pop timbul hanya ditunjukkan apabila anda tidak berada dalam aplikasi.</string>
<string name="settings_charged_notification_label">Pemberitahuan cas penuh</string>
<string name="settings_charged_notification_description">Tunjukkan pemberitahuan setelah semua yang sedang dicas mencapai tahap cas sasaran.</string>
<string name="settings_charged_threshold_label">Tahap cas sasaran</string>
<string name="settings_charged_scope_label">Bateri yang dipantau</string>
<string name="settings_charged_scope_pods_label">Pod sahaja</string>
<string name="settings_charged_scope_case_label">Kes sahaja</string>
<string name="settings_charged_scope_both_label">Pod dan kes</string>
<string name="device_settings_experimental_title">Ciri eksperimental</string>
<string name="device_settings_experimental_description">Ciri ini belum diuji pada semua peranti lagi. Jika sesuatu tidak berfungsi dengan betul, sila buka isu dengan log nyahpepijat.</string>
<string name="device_settings_experimental_action">Buka Penjejak Isu</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Tetapan</string>
<string name="settings_general_description">Penyesuaian umum yang mempengaruhi keseluruhan apl.</string>
<string name="settings_overview_hide_unmatched_label">Sembunyikan peranti yang tidak sepadan</string>
<string name="settings_overview_hide_unmatched_description">Jangan tunjukkan peranti berdekatan yang tidak sepadan dengan mana-mana profil anda dalam gambaran keseluruhan, cth. AirPods orang lain.</string>
<string name="settings_acknowledgements_label">Penghargaan</string>
<string name="settings_debug_autoreports_label">Laporan pepijat automatik</string>
<string name="settings_debug_autoreports_description">Melaporkan isu secara automatik, cth. butiran mengenai ranap apl supaya saya boleh memikirkan cara untuk membetulkannya.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth dilumpuhkan, dayakannya ;)</string>
<string name="overview_monitoring_active_label">Memantau peranti</string>
<string name="overview_monitoring_active_description">Pastikan peranti anda berdekatan dan aktif.</string>
<string name="overview_troubleshoot_suggestion_label">Disambungkan, tetapi tiada data</string>
<string name="overview_troubleshoot_suggestion_description">Peranti anda disambungkan, tetapi CAPod tidak menerima sebarang data langsung daripadanya. Telefon anda mungkin memerlukan pilihan keserasian — penyelesai masalah boleh cuba mencari satu secara automatik.</string>
<string name="overview_troubleshoot_suggestion_action">Jalankan penyelesai masalah</string>
<string name="overview_unmatched_devices_label">Peranti tidak sepadan</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">%d peranti tanpa profil yang sepadan</item>
@@ -485,6 +497,10 @@
<string name="reaction_sleep_channel_label">Pengesanan Tidur</string>
<string name="reaction_sleep_notification_title">Dijeda oleh Pengesanan Tidur</string>
<string name="reaction_sleep_notification_text">%1$s melaporkan anda tertidur, jadi muzik anda telah dijeda. Anda boleh melumpuhkan ini dalam tetapan peranti.</string>
<string name="reaction_charged_channel_label">Pemberitahuan Cas Penuh</string>
<string name="reaction_charged_notification_title">Pengecasan selesai</string>
<string name="reaction_charged_notification_text_full">%1$s telah dicas sepenuhnya.</string>
<string name="reaction_charged_notification_text_partial">%1$s telah dicas kepada %2$d%%.</string>
<string name="device_settings_rename_label">Namakan Semula</string>
<string name="device_settings_rename_hint">Nama peranti</string>
<string name="device_settings_rename_confirm">Namakan Semula</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">ချိတ်ဆက်မှုပြတင်းပေါက်ပြသရန်</string>
<string name="settings_popup_connected_description">စက်ပစ္စည်းပထမဆုံးချိတ်ဆက်သည့်အခါ ပြတင်းပေါက်တစ်ခုပြသပါ။</string>
<string name="settings_popup_info_not_in_app">သင် အပ်ငယ်ထဲ မရှိသောအခါတွင်သာ ပေါ့အပ်ဝင်းများ ပြသသည်။</string>
<string name="settings_charged_notification_label">အားသွင်းပြည့်သည့် အသိပေးချက်</string>
<string name="settings_charged_notification_description">အားသွင်းနေသည့် အရာများ သတ်မှတ်ထားသော အားသွင်းအဆင့်သို့ ရောက်သည်နှင့် အသိပေးချက်တစ်ခု ပြသပါမည်။</string>
<string name="settings_charged_threshold_label">သတ်မှတ်ထားသော အားသွင်းအဆင့်</string>
<string name="settings_charged_scope_label">စောင့်ကြည့်သော ဘက်ထရီများ</string>
<string name="settings_charged_scope_pods_label">Pods များသာ</string>
<string name="settings_charged_scope_case_label">အိတ်သာ</string>
<string name="settings_charged_scope_both_label">Pods နှင့် အိတ်</string>
<string name="device_settings_experimental_title">စမ်းသပ်ဆဲ လုပ်ဆောင်ချက်</string>
<string name="device_settings_experimental_description">ဤလုပ်ဆောင်ချက်ကို ကိရိယာအားလုံးတွင် မစစ်ဆေးရသေးပါ။ မှားယွင်းနေသည့် အရာတစ်ခုခုရှိပါက debug log ပါသော ပြဿနာတစ်ခု ဖွင့်ပေးပါ။</string>
<string name="device_settings_experimental_action">ပြဿနာ ခြေရာခံမှုကို ဖွင့်ရန်</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">ဆက်တင်များ</string>
<string name="settings_general_description">အက်ပ်တစ်ခုလုံးကို သက်ရောက်မှုရှိသော ယေဘုယျပြင်ဆင်မှုများ။</string>
<string name="settings_overview_hide_unmatched_label">မကိုက်ညီသော ကိရိယာများ ဝှက်ရန်</string>
<string name="settings_overview_hide_unmatched_description">သင့်ပရိုဖိုင်များနှင့် မကိုက်ညီသော အနီးနားရှိ ကိရိယာများကို မည်သည့်အကြောင်းကြောင့်မဆို ခြုံငုံသုံးသပ်ချက်တွင် မပြပါနှင့်၊ ဥပမာ အခြားသူများ၏ AirPods။</string>
<string name="settings_acknowledgements_label">ကျေးဇူးတင်လွှာ</string>
<string name="settings_debug_autoreports_label">အလိုအလြှောက်ချွတ်ယွင်းချက်အစီရင်ခံစာများ</string>
<string name="settings_debug_autoreports_description">ပြဿနာများကို အလိုအလြှောက်အစီရင်ခံပါသည်၊ ဥပမာ အက်ပ်ပျက်ကျမှုအကြောင်းအသေးစိတ်များ၊ သို့မှသာ ၎င်းကိုမည်သို့ဖြေရှင်းရမည်ကို ကျွန်ုပ်သိရှိနိုင်မည်ဖြစ်သည်။</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth ပိတ်ထားသည်၊ ဖွင့်ပါ ;)</string>
<string name="overview_monitoring_active_label">စက်ပစ္စည်းများကို စောင့်ကြည့်နေသည်</string>
<string name="overview_monitoring_active_description">သင့်စက်ပစ္စည်းသည် အနီးအနားတွင်ရှိပြီး အသုံးပြုနေကြောင်း သေချာပါစေ။</string>
<string name="overview_troubleshoot_suggestion_label">ချိတ်ဆက်ထားသည်၊ သို့သော် ဒေတာမရှိ</string>
<string name="overview_troubleshoot_suggestion_description">သင့်ကိရိယာ ချိတ်ဆက်ထားသော်လည်း CAPod မှ ၎င်းထံမှ တိုက်ရိုက်ဒေတာ မရရှိပါ။ သင့်ဖုန်းသည် တွဲဖက်သုံးနိုင်မှု ရွေးချယ်မှုတစ်ခု လိုအပ်နိုင်သည် — ပြဿနာဖြေရှင်းသူက အလိုအလျောက် ရှာဖွေကြည့်နိုင်သည်။</string>
<string name="overview_troubleshoot_suggestion_action">ပြဿနာဖြေရှင်းသူ စတင်ရန်</string>
<string name="overview_unmatched_devices_label">တိုက်ဆိုင်မှုမရှိသော စက်ပစ္စည်းများ</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="other">ကိုက်ညီသောပရိုဖိုင်မရှိသော စက်ပစ္စည်း %d ခု</item>
@@ -485,6 +497,10 @@
<string name="reaction_sleep_channel_label">အိပ်ငိုက်ခြင်း ထောက်လှမ်းခြင်း</string>
<string name="reaction_sleep_notification_title">အိပ်ငိုက်ခြင်း ထောက်လှမ်းခြင်းဖြင့် ခေတ္တရပ်ထားသည်</string>
<string name="reaction_sleep_notification_text">%1$s က သင်အိပ်ငိုက်သွားသည်ဟု သတင်းပို့သောကြောင့် သင့်သီချင်းကို ခေတ္တရပ်ထားသည်။ ဤဆက်တင်ကို စက်ပစ္စည်းဆက်တင်များတွင် ပိတ်နိုင်သည်။</string>
<string name="reaction_charged_channel_label">အားသွင်းပြည့်သည့် အသိပေးချက်</string>
<string name="reaction_charged_notification_title">အားသွင်းခြင်း ပြည့်စုံပြီ</string>
<string name="reaction_charged_notification_text_full">%1$s အားသွင်းပြည့်သွားပြီ။</string>
<string name="reaction_charged_notification_text_partial">%1$s ကို %2$d%% အထိ အားသွင်းပြီးပါပြီ။</string>
<string name="device_settings_rename_label">အမည်ပြောင်းပါ</string>
<string name="device_settings_rename_hint">ကိရိယာ အမည်</string>
<string name="device_settings_rename_confirm">အမည်ပြောင်းပါ</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Vis tilkoblings-popup</string>
<string name="settings_popup_connected_description">Vis en popup første gang enheten kobles til.</string>
<string name="settings_popup_info_not_in_app">Popup-vinduer vises bare når du ikke er i appen.</string>
<string name="settings_charged_notification_label">Ladet-varsling</string>
<string name="settings_charged_notification_description">Vis en varsling når alt som lader når ønsket ladenivå.</string>
<string name="settings_charged_threshold_label">Ønsket ladenivå</string>
<string name="settings_charged_scope_label">Overvåkede batterier</string>
<string name="settings_charged_scope_pods_label">Kun pods</string>
<string name="settings_charged_scope_case_label">Kun etui</string>
<string name="settings_charged_scope_both_label">Pods og etui</string>
<string name="device_settings_experimental_title">Eksperimentell funksjon</string>
<string name="device_settings_experimental_description">Denne funksjonen er ikke testet på alle enheter ennå. Hvis noe ikke fungerer som det skal, kan du åpne en sak med en feilsøkingslogg.</string>
<string name="device_settings_experimental_action">Åpne sporing av saker</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Feilsøking</string>
<string name="settings_general_label">Innstillinger</string>
<string name="settings_general_description">Generelle justeringer som påvirker hele appen.</string>
<string name="settings_overview_hide_unmatched_label">Skjul ikke-matchende enheter</string>
<string name="settings_overview_hide_unmatched_description">Ikke vis enheter i nærheten som ikke samsvarer med noen av profilene dine i oversikten, f.eks. andre personers AirPods.</string>
<string name="settings_acknowledgements_label">Anerkjennelser</string>
<string name="settings_debug_autoreports_label">Automatiske feilrapporter</string>
<string name="settings_debug_autoreports_description">Rapporterer problemer automatisk, f.eks. detaljer om en appkrasj slik at jeg kan finne ut hvordan jeg kan fikse det.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth er deaktivert, aktiver det ;)</string>
<string name="overview_monitoring_active_label">Overvåker etter enheter</string>
<string name="overview_monitoring_active_description">Sørg for at enheten din er i nærheten og aktiv.</string>
<string name="overview_troubleshoot_suggestion_label">Tilkoblet, men ingen data</string>
<string name="overview_troubleshoot_suggestion_description">Enheten din er tilkoblet, men CAPod mottar ikke live-data fra den. Telefonen din kan trenge et kompatibilitetsalternativ — feilsøkeren kan prøve å finne ett automatisk.</string>
<string name="overview_troubleshoot_suggestion_action">Kjør feilsøker</string>
<string name="overview_unmatched_devices_label">Ikke-matchede enheter</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d enhet uten matchende profil</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Søvnregistrering</string>
<string name="reaction_sleep_notification_title">Satt på pause av søvnregistrering</string>
<string name="reaction_sleep_notification_text">%1$s registrerte at du sovnet, så musikken ble satt på pause. Du kan deaktivere dette i enhetsinnstillingene.</string>
<string name="reaction_charged_channel_label">Ladet-varsling</string>
<string name="reaction_charged_notification_title">Lading fullført</string>
<string name="reaction_charged_notification_text_full">%1$s er fulladet.</string>
<string name="reaction_charged_notification_text_partial">%1$s er ladet til %2$d%%.</string>
<string name="device_settings_rename_label">Gi nytt navn</string>
<string name="device_settings_rename_hint">Enhetsnavn</string>
<string name="device_settings_rename_confirm">Gi nytt navn</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">कनेक्सन पपअप देखाउनुहोस्</string>
<string name="settings_popup_connected_description">उपकरण पहिलो पटक जडान हुँदा पपअप देखाउनुहोस्।</string>
<string name="settings_popup_info_not_in_app">पप-अपहरू केवल तब देखाइन्छन् जब तपाईं एप्लिकेसनमा हुनुहुन्न।</string>
<string name="settings_charged_notification_label">चार्ज सूचना</string>
<string name="settings_charged_notification_description">चार्ज हुने सबै कुरा लक्षित चार्ज स्तरमा पुगेपछि सूचना देखाउनुस्।</string>
<string name="settings_charged_threshold_label">लक्षित चार्ज स्तर</string>
<string name="settings_charged_scope_label">निगरानी गरिएका ब्याट्रीहरू</string>
<string name="settings_charged_scope_pods_label">पड्स मात्र</string>
<string name="settings_charged_scope_case_label">केस मात्र</string>
<string name="settings_charged_scope_both_label">पड्स र केस</string>
<string name="device_settings_experimental_title">प्रयोगात्मक सुविधा</string>
<string name="device_settings_experimental_description">यो सुविधा अझै सबै उपकरणहरूमा परीक्षण गरिएको छैन। यदि केही सही काम गरिरहेको छैन भने, कृपया डिबग लगसहित एउटा समस्या खोल्नुहोस्।</string>
<string name="device_settings_experimental_action">समस्या ट्र्याकर खोल्नुहोस्</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">डिबग</string>
<string name="settings_general_label">सेटिङहरू</string>
<string name="settings_general_description">सम्पूर्ण एपलाई असर गर्ने सामान्य ट्वीकहरू।</string>
<string name="settings_overview_hide_unmatched_label">नमिलेका यन्त्रहरू लुकाउनुस्</string>
<string name="settings_overview_hide_unmatched_description">अवलोकनमा तपाईंको कुनै पनि प्रोफाइलसँग नमिल्ने नजिकका यन्त्रहरू नदेखाउनुस्, जस्तै अरू मान्छेका AirPods।</string>
<string name="settings_acknowledgements_label">स्वीकृतिहरू</string>
<string name="settings_debug_autoreports_label">स्वचालित बग रिपोर्टहरू</string>
<string name="settings_debug_autoreports_description">समस्याहरू स्वचालित रूपमा रिपोर्ट गर्दछ, उदाहरणका लागि एप क्र्यास बारे विवरणहरू ताकि म यसलाई कसरी समाधान गर्ने भनेर पत्ता लगाउन सकूँ।</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth असक्षम छ, यसलाई सक्षम गर्नुहोस् ;)</string>
<string name="overview_monitoring_active_label">उपकरणहरू खोज्दै</string>
<string name="overview_monitoring_active_description">तपाईंको उपकरण नजिकै र सक्रिय छ भनी सुनिश्चित गर्नुहोस्।</string>
<string name="overview_troubleshoot_suggestion_label">जोडिएको छ, तर डेटा छैन</string>
<string name="overview_troubleshoot_suggestion_description">तपाईंको यन्त्र जोडिएको छ, तर CAPod ले यसबाट कुनै लाइभ डेटा प्राप्त गरिरहेको छैन। तपाईंको फोनलाई अनुकूलता विकल्पको आवश्यकता पर्न सक्छ — समस्या निवारकले स्वतः एउटा खोज्ने प्रयास गर्न सक्छ।</string>
<string name="overview_troubleshoot_suggestion_action">समस्या निवारक चलाउनुस्</string>
<string name="overview_unmatched_devices_label">मेल नखाएका उपकरणहरू</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">मेल खाने प्रोफाइल नभएको %d उपकरण</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">निद्रा पत्ता लगाउने</string>
<string name="reaction_sleep_notification_title">निद्रा पत्ता लगाउनेद्वारा रोकिएको</string>
<string name="reaction_sleep_notification_text">%1$s ले रिपोर्ट गर्यो कि तपाईं सुत्नुभयो, त्यसैले तपाईंको संगीत रोकिएको थियो। तपाईं यसलाई यन्त्र सेटिङहरूमा अक्षम गर्न सक्नुहुन्छ।</string>
<string name="reaction_charged_channel_label">चार्ज सूचना</string>
<string name="reaction_charged_notification_title">चार्ज पूरा भयो</string>
<string name="reaction_charged_notification_text_full">%1$s पूर्ण रूपमा चार्ज भएको छ।</string>
<string name="reaction_charged_notification_text_partial">%1$s %2$d%% सम्म चार्ज भएको छ।</string>
<string name="device_settings_rename_label">नाम बदल्नुहोस्</string>
<string name="device_settings_rename_hint">उपकरणको नाम</string>
<string name="device_settings_rename_confirm">नाम बदल्नुहोस्</string>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="notification_icon_tint">#EEEEEE</color>
</resources>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Verbindingspop-up weergeven</string>
<string name="settings_popup_connected_description">Toon een pop-up wanneer het apparaat voor de eerste keer verbinding maakt.</string>
<string name="settings_popup_info_not_in_app">Pop-ups worden alleen weergegeven wanneer je de app niet gebruikt.</string>
<string name="settings_charged_notification_label">Oplading voltooid-melding</string>
<string name="settings_charged_notification_description">Stuur een melding zodra alles wat aan het opladen is het doellaadniveau bereikt.</string>
<string name="settings_charged_threshold_label">Doellaadniveau</string>
<string name="settings_charged_scope_label">Bewaakte batterijen</string>
<string name="settings_charged_scope_pods_label">Alleen pods</string>
<string name="settings_charged_scope_case_label">Alleen case</string>
<string name="settings_charged_scope_both_label">Pods en case</string>
<string name="device_settings_experimental_title">Experimentele functie</string>
<string name="device_settings_experimental_description">Deze functie is nog niet op alle apparaten getest. Als er iets niet correct werkt, open dan een probleem met een foutopsporingslogboek.</string>
<string name="device_settings_experimental_action">Probleemtracker openen</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Foutopsporing</string>
<string name="settings_general_label">Instellingen</string>
<string name="settings_general_description">Algemene aanpassingen die de hele app beïnvloeden.</string>
<string name="settings_overview_hide_unmatched_label">Niet-overeenkomende apparaten verbergen</string>
<string name="settings_overview_hide_unmatched_description">Verberg apparaten in het overzicht die niet overeenkomen met je profielen, bijv. AirPods van anderen.</string>
<string name="settings_acknowledgements_label">Dankbetuigingen</string>
<string name="settings_debug_autoreports_label">Automatische bugrapporten</string>
<string name="settings_debug_autoreports_description">Rapporteert automatisch problemen, b.v. details over een app-crash, zodat ik kan uitzoeken hoe ik dit kan oplossen.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth is uitgeschakeld, schakel het in ;)</string>
<string name="overview_monitoring_active_label">Monitoring voor apparaten</string>
<string name="overview_monitoring_active_description">Zorg ervoor dat je apparaat in de buurt is en actief is.</string>
<string name="overview_troubleshoot_suggestion_label">Verbonden, maar geen gegevens</string>
<string name="overview_troubleshoot_suggestion_description">Je apparaat is verbonden, maar CAPod ontvangt geen live gegevens. Je telefoon heeft mogelijk een compatibiliteitsoptie nodig — de probleemoplosser kan er automatisch een zoeken.</string>
<string name="overview_troubleshoot_suggestion_action">Probleemoplosser starten</string>
<string name="overview_unmatched_devices_label">Niet overeenkomende apparaten</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d apparaat zonder overeenkomend profiel</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Slaapdetectie</string>
<string name="reaction_sleep_notification_title">Gepauzeerd door slaapdetectie</string>
<string name="reaction_sleep_notification_text">%1$s heeft gedetecteerd dat je in slaap bent gevallen, dus je muziek is gepauzeerd. Je kunt dit uitschakelen in de apparaatinstellingen.</string>
<string name="reaction_charged_channel_label">Oplading voltooid-melding</string>
<string name="reaction_charged_notification_title">Opladen voltooid</string>
<string name="reaction_charged_notification_text_full">%1$s is volledig opgeladen.</string>
<string name="reaction_charged_notification_text_partial">%1$s is opgeladen tot %2$d%%.</string>
<string name="device_settings_rename_label">Hernoemen</string>
<string name="device_settings_rename_hint">Apparaatnaam</string>
<string name="device_settings_rename_confirm">Hernoemen</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Wyświetl okienko połączenia</string>
<string name="settings_popup_connected_description">Wyświetla okienko, gdy urządzenie łączy się po raz pierwszy.</string>
<string name="settings_popup_info_not_in_app">Wyskakujące okienka są wyświetlane tylko wtedy, gdy nie jesteś w aplikacji.</string>
<string name="settings_charged_notification_label">Powiadomienie o naładowaniu</string>
<string name="settings_charged_notification_description">Wyślij powiadomienie, gdy wszystko, co jest ładowane, osiągnie docelowy poziom naładowania.</string>
<string name="settings_charged_threshold_label">Docelowy poziom naładowania</string>
<string name="settings_charged_scope_label">Monitorowane baterie</string>
<string name="settings_charged_scope_pods_label">Tylko słuchawki</string>
<string name="settings_charged_scope_case_label">Tylko etui</string>
<string name="settings_charged_scope_both_label">Słuchawki i etui</string>
<string name="device_settings_experimental_title">Funkcja eksperymentalna</string>
<string name="device_settings_experimental_description">Ta funkcja nie została jeszcze przetestowana na wszystkich urządzeniach. Jeśli coś nie działa poprawnie, otwórz zgłoszenie z dziennikiem debugowania.</string>
<string name="device_settings_experimental_action">Otwórz śledzenie problemów</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debuguj</string>
<string name="settings_general_label">Ustawienia</string>
<string name="settings_general_description">Ogólne opcje, które mają wpływ na całą aplikację.</string>
<string name="settings_overview_hide_unmatched_label">Ukryj niedopasowane urządzenia</string>
<string name="settings_overview_hide_unmatched_description">Nie pokazuj w przeglądzie pobliskich urządzeń, które nie pasują do żadnego z twoich profili, np. AirPods innych osób.</string>
<string name="settings_acknowledgements_label">Podziękowania</string>
<string name="settings_debug_autoreports_label">Automatyczne raportowanie błędów</string>
<string name="settings_debug_autoreports_description">Automatyczne raportowanie problemów, na przykład w przypadku awarii aplikacji, tak aby można było łatwo ją naprawić.</string>
@@ -195,6 +204,9 @@ K4r0lSz;</string>
<string name="overview_bluetooth_disabled_description">Bluetooth jest wyłączony, włącz go ;)</string>
<string name="overview_monitoring_active_label">Monitorowanie urządzeń</string>
<string name="overview_monitoring_active_description">Upewnij się, że urządzenie znajduje się w pobliżu i jest aktywne.</string>
<string name="overview_troubleshoot_suggestion_label">Połączono, ale brak danych</string>
<string name="overview_troubleshoot_suggestion_description">Twoje urządzenie jest połączone, ale CAPod nie odbiera żadnych danych na żywo. Twój telefon może potrzebować opcji zgodności — narzędzie do rozwiązywania problemów może spróbować znaleźć ją automatycznie.</string>
<string name="overview_troubleshoot_suggestion_action">Uruchom narzędzie do rozwiązywania problemów</string>
<string name="overview_unmatched_devices_label">Niedopasowane urządzenia</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d urządzenie bez pasującego profilu</item>
@@ -502,6 +514,10 @@ K4r0lSz;</string>
<string name="reaction_sleep_channel_label">Wykrywanie snu</string>
<string name="reaction_sleep_notification_title">Wstrzymano przez wykrywanie snu</string>
<string name="reaction_sleep_notification_text">%1$s wykrył, że zasnąłeś, więc muzyka została wstrzymana. Możesz to wyłączyć w ustawieniach urządzenia.</string>
<string name="reaction_charged_channel_label">Powiadomienie o naładowaniu</string>
<string name="reaction_charged_notification_title">Ładowanie zakończone</string>
<string name="reaction_charged_notification_text_full">%1$s jest w pełni naładowany.</string>
<string name="reaction_charged_notification_text_partial">%1$s został naładowany do %2$d%%.</string>
<string name="device_settings_rename_label">Zmień nazwę</string>
<string name="device_settings_rename_hint">Nazwa urządzenia</string>
<string name="device_settings_rename_confirm">Zmień nazwę</string>
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostrar pop-up de conexão</string>
<string name="settings_popup_connected_description">Mostrar um pop-up quando o dispositivo se conectar pela primeira vez.</string>
<string name="settings_popup_info_not_in_app">Os popups são exibidos somente quando você não está no aplicativo.</string>
<string name="settings_charged_notification_label">Notificação de carregamento concluído</string>
<string name="settings_charged_notification_description">Exibir uma notificação quando tudo que está carregando atingir o nível de carga alvo.</string>
<string name="settings_charged_threshold_label">Nível de carga alvo</string>
<string name="settings_charged_scope_label">Baterias monitoradas</string>
<string name="settings_charged_scope_pods_label">Apenas os pods</string>
<string name="settings_charged_scope_case_label">Apenas o estojo</string>
<string name="settings_charged_scope_both_label">Pods e estojo</string>
<string name="device_settings_experimental_title">Recurso experimental</string>
<string name="device_settings_experimental_description">Este recurso ainda não foi testado em todos os dispositivos. Se algo não estiver funcionando corretamente, abra um problema com um registro de depuração.</string>
<string name="device_settings_experimental_action">Abrir Rastreador de Problemas</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuração</string>
<string name="settings_general_label">Configurações</string>
<string name="settings_general_description">Ajustes gerais que afetam todo o aplicativo.</string>
<string name="settings_overview_hide_unmatched_label">Ocultar dispositivos sem correspondência</string>
<string name="settings_overview_hide_unmatched_description">Não exibir dispositivos próximos que não correspondam a nenhum dos seus perfis na visão geral, por ex., AirPods de outras pessoas.</string>
<string name="settings_acknowledgements_label">Agradecimentos</string>
<string name="settings_debug_autoreports_label">Relatórios automáticos de bugs</string>
<string name="settings_debug_autoreports_description">Relata problemas automaticamente, por exemplo. detalhes sobre uma falha de aplicativo para que eu possa descobrir como corrigi-lo.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">O Bluetooth está desativado, ative-o ;)</string>
<string name="overview_monitoring_active_label">Monitorando dispositivos</string>
<string name="overview_monitoring_active_description">Certifique-se de que seu dispositivo está próximo e ativo.</string>
<string name="overview_troubleshoot_suggestion_label">Conectado, mas sem dados</string>
<string name="overview_troubleshoot_suggestion_description">Seu dispositivo está conectado, mas o CAPod não está recebendo dados em tempo real dele. Seu telefone pode precisar de uma opção de compatibilidade — o solucionador de problemas pode tentar encontrar uma automaticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Executar solucionador de problemas</string>
<string name="overview_unmatched_devices_label">Dispositivos sem correspondência</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo sem perfil correspondente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detecção de Sono</string>
<string name="reaction_sleep_notification_title">Pausado pela Detecção de Sono</string>
<string name="reaction_sleep_notification_text">%1$s informou que você adormeceu, então sua música foi pausada. Você pode desativar isso nas configurações do dispositivo.</string>
<string name="reaction_charged_channel_label">Notificação de Carregamento Concluído</string>
<string name="reaction_charged_notification_title">Carregamento completo</string>
<string name="reaction_charged_notification_text_full">%1$s está totalmente carregado.</string>
<string name="reaction_charged_notification_text_partial">%1$s foi carregado a %2$d%%.</string>
<string name="device_settings_rename_label">Renomear</string>
<string name="device_settings_rename_hint">Nome do dispositivo</string>
<string name="device_settings_rename_confirm">Renomear</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mostrar pop-up de ligação</string>
<string name="settings_popup_connected_description">Mostrar um pop-up quando o dispositivo se liga pela primeira vez.</string>
<string name="settings_popup_info_not_in_app">Os popups só são mostrados quando não está na aplicação.</string>
<string name="settings_charged_notification_label">Notificação de carregamento completo</string>
<string name="settings_charged_notification_description">Mostrar uma notificação quando tudo o que está a carregar atingir o nível de carga pretendido.</string>
<string name="settings_charged_threshold_label">Nível de carga pretendido</string>
<string name="settings_charged_scope_label">Baterias monitorizadas</string>
<string name="settings_charged_scope_pods_label">Apenas os pods</string>
<string name="settings_charged_scope_case_label">Apenas o estojo</string>
<string name="settings_charged_scope_both_label">Pods e estojo</string>
<string name="device_settings_experimental_title">Funcionalidade experimental</string>
<string name="device_settings_experimental_description">Esta funcionalidade ainda não foi testada em todos os dispositivos. Se algo não estiver a funcionar corretamente, por favor abra um problema com um registo de depuração.</string>
<string name="device_settings_experimental_action">Abrir Rastreador de Problemas</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Depuração</string>
<string name="settings_general_label">Definições</string>
<string name="settings_general_description">Ajustes gerais que afetam toda a aplicação.</string>
<string name="settings_overview_hide_unmatched_label">Ocultar dispositivos sem correspondência</string>
<string name="settings_overview_hide_unmatched_description">Não mostrar na vista geral os dispositivos próximos que não correspondem a nenhum dos teus perfis, por ex. os AirPods de outras pessoas.</string>
<string name="settings_acknowledgements_label">Agradecimentos</string>
<string name="settings_debug_autoreports_label">Relatórios de erros automáticos</string>
<string name="settings_debug_autoreports_description">Relata problemas automaticamente, p. ex., detalhes sobre uma falha da aplicação para que eu possa descobrir como corrigi-la.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">O Bluetooth está desativado, ative-o ;)</string>
<string name="overview_monitoring_active_label">A monitorizar dispositivos</string>
<string name="overview_monitoring_active_description">Certifique-se de que o seu dispositivo está perto e ativo.</string>
<string name="overview_troubleshoot_suggestion_label">Ligado, mas sem dados</string>
<string name="overview_troubleshoot_suggestion_description">O teu dispositivo está ligado, mas o CAPod não está a receber dados em tempo real. O teu telefone pode precisar de uma opção de compatibilidade — o solucionador de problemas pode tentar encontrar uma automaticamente.</string>
<string name="overview_troubleshoot_suggestion_action">Executar solucionador de problemas</string>
<string name="overview_unmatched_devices_label">Dispositivos sem correspondência</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d dispositivo sem perfil correspondente</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Deteção de Sono</string>
<string name="reaction_sleep_notification_title">Pausado pela Deteção de Sono</string>
<string name="reaction_sleep_notification_text">%1$s detetou que adormeceu, por isso a sua música foi pausada. Pode desativar esta funcionalidade nas definições do dispositivo.</string>
<string name="reaction_charged_channel_label">Notificação de carregamento completo</string>
<string name="reaction_charged_notification_title">Carregamento concluído</string>
<string name="reaction_charged_notification_text_full">%1$s está totalmente carregado.</string>
<string name="reaction_charged_notification_text_partial">%1$s foi carregado até %2$d%%.</string>
<string name="device_settings_rename_label">Mudar nome</string>
<string name="device_settings_rename_hint">Nome do dispositivo</string>
<string name="device_settings_rename_confirm">Mudar nome</string>
+16
View File
@@ -76,6 +76,13 @@
<string name="settings_popup_connected_label">Mussar il popup da connexiun</string>
<string name="settings_popup_connected_description">Mussar in popup cura che l\'apparat sa connecta per l\'emprima giada.</string>
<string name="settings_popup_info_not_in_app">Fenestras da popup vegnan mo mussadas cura ch\'i na sei betg en l\'app.</string>
<string name="settings_charged_notification_label">Notificaziun da chargià</string>
<string name="settings_charged_notification_description">Mussa ina notificaziun cur che tut quai che vegn chargià ha cuntanschì il nivel da chargiader fixà.</string>
<string name="settings_charged_threshold_label">Nivel da chargiader da mira</string>
<string name="settings_charged_scope_label">Batteries surveglidas</string>
<string name="settings_charged_scope_pods_label">Sulettamain Pods</string>
<string name="settings_charged_scope_case_label">Sulettamain l\'etui</string>
<string name="settings_charged_scope_both_label">Pods ed etui</string>
<string name="device_settings_experimental_title">Funcziun experimentala</string>
<string name="device_settings_experimental_description">Questa funcziun n\'è anc betg vegnida testada sin tuts apparats. Sch\'insatge na funcziuna betg correctamain, vegnì plais avrir ina dumonda cun in protocol da debug.</string>
<string name="device_settings_experimental_action">Avrir il tractur da dumondas</string>
@@ -113,6 +120,8 @@
<string name="settings_category_debug_label">Debug</string>
<string name="settings_general_label">Configuraziuns</string>
<string name="settings_general_description">Adattaziuns generalas che concernan l\'entira app.</string>
<string name="settings_overview_hide_unmatched_label">Zuppentar apparats betg concordants</string>
<string name="settings_overview_hide_unmatched_description">Na mussa betg ils apparats visadaifer che na correspundan a nagin da tis profils en la survista, p.ex. ils AirPods d\'autras persunas.</string>
<string name="settings_acknowledgements_label">Remerciaments</string>
<string name="settings_debug_autoreports_label">Raports da bugs automatics</string>
<string name="settings_debug_autoreports_description">Raporta automaticamain problems, p.ex. detagls davart in crash da l\'app, uschia che jau poss chapir co reparar quai.</string>
@@ -193,6 +202,9 @@
<string name="overview_bluetooth_disabled_description">Bluetooth è deactivà, activai el ;)</string>
<string name="overview_monitoring_active_label">Surveglianza dad apparats</string>
<string name="overview_monitoring_active_description">Assicurai che Voss apparat è datiers ed activ.</string>
<string name="overview_troubleshoot_suggestion_label">Connectà, ma nagins datas</string>
<string name="overview_troubleshoot_suggestion_description">Tieu apparat è connectà, ma CAPod na retschaiva naginas datas en diretta. Tiu telefon sto eventualmain ina opziun da cumpatibilitad — il schliader da problems po emprovar da chattar ina automaticamain.</string>
<string name="overview_troubleshoot_suggestion_action">Aviar il schliader da problems</string>
<string name="overview_unmatched_devices_label">Apparats senza correspondenza</string>
<plurals name="overview_unmatched_devices_count">
<item quantity="one">%d apparat senza profil correspundent</item>
@@ -490,6 +502,10 @@
<string name="reaction_sleep_channel_label">Detecziun dal Somen</string>
<string name="reaction_sleep_notification_title">Stoppà da la Detecziun dal Somen</string>
<string name="reaction_sleep_notification_text">%1$s ha rapportà ch\'Vus avais endormì, uschia è Vossa musica vegnida stoppada. Vus pudais deactivar quai en las configurazions dal apparat.</string>
<string name="reaction_charged_channel_label">Notificaziun da chargiader</string>
<string name="reaction_charged_notification_title">Chargiader terminà</string>
<string name="reaction_charged_notification_text_full">%1$s è cumplettamain chargiada.</string>
<string name="reaction_charged_notification_text_partial">%1$s è vegnida chargiada fin %2$d%%.</string>
<string name="device_settings_rename_label">Renumerar</string>
<string name="device_settings_rename_hint">Num da l\'apparat</string>
<string name="device_settings_rename_confirm">Renumerar</string>

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