mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
647300fd3a | ||
|
|
3eaf99390e | ||
|
|
0ee7915e31 | ||
|
|
10c880a800 | ||
|
|
b1bf658ff3 | ||
|
|
77dc13d9ba | ||
|
|
21b6cfc013 | ||
|
|
5d953ee23e | ||
|
|
42f2f5bfee | ||
|
|
6708901394 | ||
|
|
788038beb7 | ||
|
|
18ac05ed80 | ||
|
|
02f68821d2 | ||
|
|
62886f00f1 | ||
|
|
f2eb45d00b | ||
|
|
2fca9097c2 | ||
|
|
051677e7dd | ||
|
|
fbcd595b45 | ||
|
|
aa38f58f62 | ||
|
|
a3b01a02ee | ||
|
|
8544983984 | ||
|
|
07a11799b1 | ||
|
|
65a7b1933a | ||
|
|
bbfb735124 | ||
|
|
7b474fb0e1 | ||
|
|
c6524d7cee | ||
|
|
148cdf5109 | ||
|
|
60a3039415 | ||
|
|
6f7b6e30c9 | ||
|
|
08c095eae4 | ||
|
|
9087be6282 | ||
|
|
d46fe35eab | ||
|
|
1afb77ee33 | ||
|
|
a9215fc11c | ||
|
|
d80a110280 | ||
|
|
fdfc7f44fb | ||
|
|
26fbfc08f7 | ||
|
|
89049ee3ab | ||
|
|
68f81f900b | ||
|
|
513bd891af | ||
|
|
37cd753ab8 | ||
|
|
34bf2311b4 | ||
|
|
a86093f617 | ||
|
|
71f66e6004 | ||
|
|
2d1ab85e01 | ||
|
|
f029eb9102 | ||
|
|
471837ab88 | ||
|
|
1e80d742cc | ||
|
|
16b6273938 | ||
|
|
3407370563 | ||
|
|
3cda73a36c | ||
|
|
b604c423ad | ||
|
|
0c8b121c2c |
@@ -4,7 +4,8 @@
|
||||
[](https://github.com/d4rken-org/capod/releases/latest)
|
||||
[](https://github.com/d4rken/capod/actions/workflows/code-checks.yml)
|
||||
[](https://crowdin.com/project/capod)
|
||||
[](https://github.com/d4rken-org/capod/releases/latest)
|
||||
[](https://github.com/d4rken-org/capod/edit/main/README.md#download)
|
||||
[](https://github.com/d4rken-org/capod/edit/main/README.md#download)
|
||||
|
||||
A companion app that adds support for AirPod specific features to Android:
|
||||
|
||||
@@ -25,12 +26,15 @@ Currently supported models:
|
||||
* AirPods 1. Generation
|
||||
* AirPods 2. Generation
|
||||
* AirPods 3. Generation
|
||||
* AirPods 4. Generation
|
||||
* AirPods 4. Generation with ANC
|
||||
* AirPods Pro 1. Generation
|
||||
* AirPods Pro 2. Generation
|
||||
* AirPods Pro 2. Generation (USB-C)
|
||||
* AirPods Max
|
||||
* Power Beats Pro
|
||||
* Power Beats 3
|
||||
* Power Beats 4
|
||||
* Beats Solo 3
|
||||
* Beats Studio 3
|
||||
* Beats X
|
||||
@@ -76,6 +80,8 @@ Currently supported models:
|
||||
Travis & Rye, Erik & Sipes, Brandon & Teplov, Sam. (2019). Handoff All Your Privacy – A Review of Apple’s Bluetooth
|
||||
Low Energy Continuity Protocol. Proceedings on Privacy Enhancing Technologies. 2019. 34-53. 10.2478/popets-2019-0057.
|
||||
* Celosia, Guillaume. (2020). Privacy Challenges in Wireless Communications of the Internet of Things.
|
||||
* The [MagicPods](https://github.com/steam3d/MagicPods-Windows) project. If you are looking for "CAPod for Windows",
|
||||
check it out.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -9,13 +9,19 @@ import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.*
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.DEBUG
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.notifications.PendingIntentCompat
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
@@ -132,12 +138,12 @@ class BleScanner @Inject constructor(
|
||||
ScannerMode.LOW_POWER -> {
|
||||
setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
|
||||
setMatchMode(ScanSettings.MATCH_MODE_STICKY)
|
||||
setNumOfMatches(ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT)
|
||||
setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
|
||||
}
|
||||
ScannerMode.BALANCED -> {
|
||||
setScanMode(ScanSettings.SCAN_MODE_BALANCED)
|
||||
setMatchMode(ScanSettings.MATCH_MODE_STICKY)
|
||||
setNumOfMatches(ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT)
|
||||
setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
|
||||
}
|
||||
ScannerMode.LOW_LATENCY -> {
|
||||
setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package eu.darken.capod.common.preferences
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
|
||||
class MaterialSwitchPreference(context: Context, attrs: AttributeSet?) :
|
||||
SwitchPreferenceCompat(context, attrs) {
|
||||
|
||||
init {
|
||||
// Use material switch
|
||||
widgetLayoutResource = eu.darken.capod.common.R.layout.preference_material_switch
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,14 @@ interface PodDevice {
|
||||
"AirPods (Gen 3)",
|
||||
R.drawable.devic_airpods_gen2_both,
|
||||
),
|
||||
@Json(name = "airpods.gen4") AIRPODS_GEN4(
|
||||
"AirPods (Gen 4)",
|
||||
R.drawable.devic_airpods_gen2_both,
|
||||
),
|
||||
@Json(name = "airpods.gen4.anc") AIRPODS_GEN4_ANC(
|
||||
"AirPods (Gen 4 ANC)",
|
||||
R.drawable.devic_airpods_gen2_both,
|
||||
),
|
||||
@Json(name = "airpods.pro") AIRPODS_PRO(
|
||||
"AirPods Pro",
|
||||
R.drawable.devic_airpods_pro2_both
|
||||
@@ -114,6 +122,9 @@ interface PodDevice {
|
||||
@Json(name = "beats.powerbeats.3") POWERBEATS_3(
|
||||
"Power Beats 3"
|
||||
),
|
||||
@Json(name = "beats.powerbeats.4") POWERBEATS_4(
|
||||
"Power Beats 4"
|
||||
),
|
||||
@Json(name = "beats.powerbeats.pro") POWERBEATS_PRO(
|
||||
"Power Beats Pro"
|
||||
),
|
||||
|
||||
@@ -5,9 +5,28 @@ import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.multibindings.IntoSet
|
||||
import eu.darken.capod.pods.core.apple.airpods.*
|
||||
import eu.darken.capod.pods.core.apple.beats.*
|
||||
import eu.darken.capod.pods.core.apple.misc.*
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen1
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen2
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen3
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen4
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsGen4Anc
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsMax
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro2
|
||||
import eu.darken.capod.pods.core.apple.airpods.AirPodsPro2Usbc
|
||||
import eu.darken.capod.pods.core.apple.beats.BeatsFitPro
|
||||
import eu.darken.capod.pods.core.apple.beats.BeatsFlex
|
||||
import eu.darken.capod.pods.core.apple.beats.BeatsSolo3
|
||||
import eu.darken.capod.pods.core.apple.beats.BeatsStudio3
|
||||
import eu.darken.capod.pods.core.apple.beats.BeatsX
|
||||
import eu.darken.capod.pods.core.apple.beats.PowerBeats3
|
||||
import eu.darken.capod.pods.core.apple.beats.PowerBeats4
|
||||
import eu.darken.capod.pods.core.apple.beats.PowerBeatsPro
|
||||
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen1
|
||||
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen2
|
||||
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsGen3
|
||||
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsPro
|
||||
import eu.darken.capod.pods.core.apple.misc.FakeAirPodsPro2
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
@@ -16,6 +35,8 @@ abstract class AppleFactoryModule {
|
||||
@Binds @IntoSet abstract fun airPodsGen1(factory: AirPodsGen1.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun airPodsGen2(factory: AirPodsGen2.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun airPodsGen3(factory: AirPodsGen3.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun airPodsGen4(factory: AirPodsGen4.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun airPodsGen4Anc(factory: AirPodsGen4Anc.Factory): ApplePodsFactory<out ApplePods>
|
||||
|
||||
@Binds @IntoSet abstract fun airPodsPro(factory: AirPodsPro.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun airPodsPro2(factory: AirPodsPro2.Factory): ApplePodsFactory<out ApplePods>
|
||||
@@ -27,6 +48,7 @@ abstract class AppleFactoryModule {
|
||||
@Binds @IntoSet abstract fun beatsStudio3(factory: BeatsStudio3.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun beatsX(factory: BeatsX.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun powerBeats3(factory: PowerBeats3.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun powerBeats4(factory: PowerBeats4.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun powerBeatsPro(factory: PowerBeatsPro.Factory): ApplePodsFactory<out ApplePods>
|
||||
@Binds @IntoSet abstract fun beatsFitPro(factory: BeatsFitPro.Factory): ApplePodsFactory<out ApplePods>
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.ApplePods
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
data class AirPodsGen4(
|
||||
override val identifier: PodDevice.Id = PodDevice.Id(),
|
||||
override val seenLastAt: Instant = Instant.now(),
|
||||
override val seenFirstAt: Instant = Instant.now(),
|
||||
override val seenCounter: Int = 1,
|
||||
override val scanResult: BleScanResult,
|
||||
override val proximityMessage: ProximityPairing.Message,
|
||||
override val reliability: Float = PodDevice.BASE_CONFIDENCE,
|
||||
private val rssiAverage: Int? = null,
|
||||
private val cachedBatteryPercentage: Float? = null,
|
||||
private val cachedCaseState: DualApplePods.LidState? = null
|
||||
) : DualApplePods, HasStateDetectionAirPods {
|
||||
|
||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN4
|
||||
|
||||
override val batteryCasePercent: Float?
|
||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||
|
||||
override val caseLidState: DualApplePods.LidState
|
||||
get() = cachedCaseState ?: super.caseLidState
|
||||
|
||||
override val rssi: Int
|
||||
get() = rssiAverage ?: super<DualApplePods>.rssi
|
||||
|
||||
class Factory @Inject constructor() : DualApplePodsFactory(TAG) {
|
||||
|
||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
|
||||
var basic = AirPodsGen4(scanResult = scanResult, proximityMessage = message)
|
||||
val result = searchHistory(basic)
|
||||
|
||||
if (result != null) basic = basic.copy(identifier = result.id)
|
||||
updateHistory(basic)
|
||||
|
||||
if (result == null) return basic
|
||||
|
||||
return basic.copy(
|
||||
identifier = result.id,
|
||||
seenFirstAt = result.seenFirstAt,
|
||||
seenLastAt = scanResult.receivedAt,
|
||||
seenCounter = result.seenCounter,
|
||||
reliability = result.reliability,
|
||||
cachedBatteryPercentage = result.getLatestCaseBattery(),
|
||||
rssiAverage = result.rssiSmoothed(basic.rssi),
|
||||
cachedCaseState = result.getLatestCaseLidState(basic)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEVICE_CODE = 0x1920.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Gen4")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.ApplePods
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import eu.darken.capod.pods.core.apple.DualApplePodsFactory
|
||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
data class AirPodsGen4Anc(
|
||||
override val identifier: PodDevice.Id = PodDevice.Id(),
|
||||
override val seenLastAt: Instant = Instant.now(),
|
||||
override val seenFirstAt: Instant = Instant.now(),
|
||||
override val seenCounter: Int = 1,
|
||||
override val scanResult: BleScanResult,
|
||||
override val proximityMessage: ProximityPairing.Message,
|
||||
override val reliability: Float = PodDevice.BASE_CONFIDENCE,
|
||||
private val rssiAverage: Int? = null,
|
||||
private val cachedBatteryPercentage: Float? = null,
|
||||
private val cachedCaseState: DualApplePods.LidState? = null
|
||||
) : DualApplePods, HasStateDetectionAirPods {
|
||||
|
||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_GEN4_ANC
|
||||
|
||||
override val batteryCasePercent: Float?
|
||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||
|
||||
override val caseLidState: DualApplePods.LidState
|
||||
get() = cachedCaseState ?: super.caseLidState
|
||||
|
||||
override val rssi: Int
|
||||
get() = rssiAverage ?: super<DualApplePods>.rssi
|
||||
|
||||
class Factory @Inject constructor() : DualApplePodsFactory(TAG) {
|
||||
|
||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
|
||||
var basic = AirPodsGen4Anc(scanResult = scanResult, proximityMessage = message)
|
||||
val result = searchHistory(basic)
|
||||
|
||||
if (result != null) basic = basic.copy(identifier = result.id)
|
||||
updateHistory(basic)
|
||||
|
||||
if (result == null) return basic
|
||||
|
||||
return basic.copy(
|
||||
identifier = result.id,
|
||||
seenFirstAt = result.seenFirstAt,
|
||||
seenLastAt = scanResult.receivedAt,
|
||||
seenCounter = result.seenCounter,
|
||||
reliability = result.reliability,
|
||||
cachedBatteryPercentage = result.getLatestCaseBattery(),
|
||||
rssiAverage = result.rssiSmoothed(basic.rssi),
|
||||
cachedCaseState = result.getLatestCaseLidState(basic)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEVICE_CODE = 0x1B20.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Gen4-ANC")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package eu.darken.capod.pods.core.apple.beats
|
||||
|
||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.ApplePods
|
||||
import eu.darken.capod.pods.core.apple.SingleApplePods
|
||||
import eu.darken.capod.pods.core.apple.SingleApplePodsFactory
|
||||
import eu.darken.capod.pods.core.apple.airpods.HasStateDetectionAirPods
|
||||
import eu.darken.capod.pods.core.apple.protocol.ProximityPairing
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
data class PowerBeats4(
|
||||
override val identifier: PodDevice.Id = PodDevice.Id(),
|
||||
override val seenLastAt: Instant = Instant.now(),
|
||||
override val seenFirstAt: Instant = Instant.now(),
|
||||
override val seenCounter: Int = 1,
|
||||
override val scanResult: BleScanResult,
|
||||
override val proximityMessage: ProximityPairing.Message,
|
||||
override val reliability: Float = PodDevice.BASE_CONFIDENCE,
|
||||
private val rssiAverage: Int? = null,
|
||||
) : SingleApplePods, HasStateDetectionAirPods {
|
||||
|
||||
override val model: PodDevice.Model = PodDevice.Model.POWERBEATS_4
|
||||
|
||||
override val rssi: Int
|
||||
get() = rssiAverage ?: super<SingleApplePods>.rssi
|
||||
|
||||
class Factory @Inject constructor() : SingleApplePodsFactory(TAG) {
|
||||
|
||||
override fun isResponsible(message: ProximityPairing.Message): Boolean = message.run {
|
||||
getModelInfo().full == DEVICE_CODE && length == ProximityPairing.PAIRING_MESSAGE_LENGTH
|
||||
}
|
||||
|
||||
override fun create(scanResult: BleScanResult, message: ProximityPairing.Message): ApplePods {
|
||||
var basic = PowerBeats4(scanResult = scanResult, proximityMessage = message)
|
||||
val result = searchHistory(basic)
|
||||
|
||||
if (result != null) basic = basic.copy(identifier = result.id)
|
||||
updateHistory(basic)
|
||||
|
||||
if (result == null) return basic
|
||||
|
||||
return basic.copy(
|
||||
identifier = result.id,
|
||||
seenFirstAt = result.seenFirstAt,
|
||||
seenLastAt = scanResult.receivedAt,
|
||||
seenCounter = result.seenCounter,
|
||||
reliability = result.reliability,
|
||||
rssiAverage = result.rssiSmoothed(basic.rssi),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEVICE_CODE = 0x0D20.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Beats", "PowerBeats", "4")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.materialswitch.MaterialSwitch xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/switchWidget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:clickable="false"
|
||||
android:focusable="false" />
|
||||
@@ -59,4 +59,5 @@
|
||||
<string name="last_seen_x">آخر ظهور: %s</string>
|
||||
<string name="first_seen_x">أول ظهور:%s</string>
|
||||
<string name="permission_post_notifications_label"></string>
|
||||
<string name="permission_post_notifications_description">"اسمح لـلتطبيق بإظهار الإشعارات المتعلقة بسماعات الأذن الخاصة بك، على سبيل المثال. حالتهم الحالية خلال الاتصال."</string>
|
||||
</resources>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="app_name">CAPod</string>
|
||||
<string name="app_name_pro">CAPod Pro</string>
|
||||
<string name="app_name_foss">CAPod FOSS</string>
|
||||
<string name="general_grant_permission_action">Conceder permiso</string>
|
||||
<string name="permission_bluetooth_connect_label">Conexión Bluetooth</string>
|
||||
<string name="permission_bluetooth_connect_description">Esta aplicacion requiere el permiso \"Conexión Bluetooth\" para interactuar con los dispositivos vinculados e iniciar las conexiones.</string>
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
<string name="settings_monitor_mode_always_label">Sempre</string>
|
||||
<string name="settings_reaction_autoconnect_whenseen_label">Quando rilevato</string>
|
||||
<string name="settings_reaction_autoconnect_caseopen_label">La custodia é aperta</string>
|
||||
<string name="settings_reaction_autoconnect_inear_label">Nell\'orecchio</string>
|
||||
<string name="pods_dual_left_label">Pod sinistro</string>
|
||||
<string name="pods_dual_right_label">Pod destro</string>
|
||||
<string name="settings_reaction_autoconnect_inear_label">Indossato</string>
|
||||
<string name="pods_dual_left_label">Pod SX</string>
|
||||
<string name="pods_dual_right_label">Pod DX</string>
|
||||
<string name="pods_case_label">Custodia</string>
|
||||
<string name="pods_case_status_open_label">Aperto</string>
|
||||
<string name="pods_case_status_closed_label">Chiuso</string>
|
||||
<string name="pods_connection_state_disconnected_label">Non connesso</string>
|
||||
<string name="pods_connection_state_idle_label">Connesso ad un device, ma inattivo</string>
|
||||
<string name="pods_connection_state_idle_label">Connesso al dispositivo, ma inattivo</string>
|
||||
<string name="pods_connection_state_music_label">In modalità musica</string>
|
||||
<string name="pods_connection_state_call_label">In modalità chiamata</string>
|
||||
<string name="pods_connection_state_ringing_label">Squilla</string>
|
||||
@@ -51,7 +51,7 @@
|
||||
<string name="pods_unknown_contact_dev">Questo è un dispositivo sconosciuto, ma sta utilizzando un formato di comunicazione noto. Aggiungiamo il supporto per questo dispositivo, contattami :)</string>
|
||||
<string name="pods_none_label_short">Nessun dispositivo</string>
|
||||
<string name="pods_charging_label">In ricarica</string>
|
||||
<string name="pods_inear_label">Nell\'orecchio</string>
|
||||
<string name="pods_inear_label">Indossato</string>
|
||||
<string name="pods_microphone_label">Microfono</string>
|
||||
<string name="pods_yours">Tuoi</string>
|
||||
<string name="headset_being_worn_label">Indossato</string>
|
||||
|
||||
@@ -1,2 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"></resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="app_name">CAPod</string>
|
||||
<string name="app_name_pro">CAPod Pro</string>
|
||||
<string name="app_name_foss">CAPod FOSS</string>
|
||||
<string name="general_value_not_available_label">N/A</string>
|
||||
<string name="general_error_label">Eroare</string>
|
||||
<string name="general_grant_permission_action">Acordați permisiuni</string>
|
||||
<string name="overview_nomaindevice_label">Niciun dispozitiv principal</string>
|
||||
<string name="overview_nomaindevice_description">Este puțin probabil ca toate dispozitivele detectate să fie ale tale. Porniți și conectați dispozitivul sau ajustați setările.</string>
|
||||
<string name="overview_bluetooth_disabled_label">Bluetooth este dezactivat</string>
|
||||
<string name="overview_bluetooth_disabled_description">Bluetooth este dezactivat, activați-l ;)</string>
|
||||
<string name="permission_bluetooth_connect_label">Conectare Bluetooth</string>
|
||||
<string name="permission_bluetooth_connect_description">Această aplicație necesită permisiunea „Conectare Bluetooth” pentru a interacționa cu dispozitivele asociate și a iniția conexiuni.</string>
|
||||
<string name="permission_bluetooth_scan_label">Scanare Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Permisiunea „Scanare Bluetooth” permite acestei aplicații să descopere și să primească date Bluetooth de la dispozitivele din apropiere, cum ar fi AirPod-urile dvs.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Această aplicație necesită permisiunea „Bluetooth” pentru a se conecta la dispozitive Bluetooth asociate.</string>
|
||||
<string name="permission_access_fine_location_label">Permiteți locație exactă</string>
|
||||
<string name="permission_access_fine_location_description">CAPod folosește permisiunea „locație exactă” pentru a primi date Bluetooth Energie Scăzută (BLE). Căștile dvs. folosesc tehnologia Bluetooth Energie Scăzută (BLE) pentru a-și transmite starea. Această aplicație NU va folosi date Bluetooth pentru a vă determina locația.</string>
|
||||
<string name="permission_background_location_label">Permiteți acces la locație în fundal</string>
|
||||
<string name="permission_background_location_description">CAPod folosește „accesul la locație în fundal” pentru a activa funcții precum „Afișare pop-up” și „Conectare Automată” în timp ce aplicația este închisă. Accesul la locație în fundal permite aplicației să primească date Bluetooth Energie Scăzută (BLE) în timp ce se află în fundal. Această aplicație NU va folosi date Bluetooth pentru a vă determina locația.</string>
|
||||
<string name="permission_ignore_battery_optimizations_label">Dezactivați optimizări ale bateriei</string>
|
||||
<string name="permission_ignore_battery_optimizations_description">Optimizările bateriei împiedică această aplicație să primească în mod fiabil date Bluetooth în timp ce aplicația este în fundal.</string>
|
||||
<string name="permission_required_title">Este necesară următoarea permisiune:</string>
|
||||
<string name="permission_system_alert_window_label">Fereastra de alertă de sistem</string>
|
||||
<string name="permission_system_alert_window_description">Permiteți CAPod să apară peste alte aplicații pentru a face posibilă funcția „Afișați pop-up”.</string>
|
||||
<string name="settings_scanner_mode_lowpower_label">Putere redusă</string>
|
||||
<string name="settings_scanner_mode_balanced_label">Echilibrat</string>
|
||||
<string name="settings_scanner_mode_lowlatency_label">Latență scăzută</string>
|
||||
<string name="settings_monitor_mode_manual_label">Când aplicația este deschisă</string>
|
||||
<string name="settings_monitor_mode_automatic_label">Când dispozitivul este conectat</string>
|
||||
<string name="settings_monitor_mode_always_label">Mereu</string>
|
||||
<string name="settings_reaction_autoconnect_whenseen_label">Când este detectat</string>
|
||||
<string name="settings_reaction_autoconnect_caseopen_label">Carcasa este deschisă</string>
|
||||
<string name="settings_reaction_autoconnect_inear_label">În ureche</string>
|
||||
<string name="pods_dual_left_label">Casca stângă</string>
|
||||
<string name="pods_dual_right_label">Casca dreaptă</string>
|
||||
<string name="pods_case_label">Carcasă</string>
|
||||
<string name="pods_case_status_open_label">Deschisă</string>
|
||||
<string name="pods_case_status_closed_label">Închisă</string>
|
||||
<string name="pods_connection_state_disconnected_label">Nu sunt conectate la un dispozitiv</string>
|
||||
<string name="pods_connection_state_idle_label">Conectate la un dispozitiv, dar inactiv</string>
|
||||
<string name="pods_connection_state_music_label">În modul muzică</string>
|
||||
<string name="pods_connection_state_call_label">În modul apel</string>
|
||||
<string name="pods_connection_state_ringing_label">Sună</string>
|
||||
<string name="pods_connection_state_hanging_up_label">Închidere</string>
|
||||
<string name="pods_connection_state_unknown_label">Starea conexiunii necunoscută</string>
|
||||
<string name="pods_unknown_raw_data_label">Date neprelucrate</string>
|
||||
<string name="pods_unknown_label">Dispozitiv necunoscut</string>
|
||||
<string name="pods_unknown_contact_dev">Acesta este un dispozitiv necunoscut, dar folosește un format de mesaj similar. Să adăugăm suport pentru el, contactează-mă :)</string>
|
||||
<string name="pods_none_label_short">Niciun dispozitiv</string>
|
||||
<string name="pods_charging_label">Se încarcă</string>
|
||||
<string name="pods_inear_label">În ureche</string>
|
||||
<string name="pods_microphone_label">Microfon</string>
|
||||
<string name="pods_yours">Ale tale</string>
|
||||
<string name="headset_being_worn_label">Fiind purtate</string>
|
||||
<string name="pods_case_unknown_state">Stare necunoscută</string>
|
||||
<string name="last_seen_x">Vazute ultima dată: %s</string>
|
||||
<string name="first_seen_x">Prima dată văzute: %s</string>
|
||||
<string name="permission_post_notifications_label">Arată notificări</string>
|
||||
<string name="permission_post_notifications_description">"Permiteți ca CAPod să afișeze notificări despre AirPod-urile dvs., de exemplu, starea lor actuală în timp ce sunt conectate."</string>
|
||||
</resources>
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
<string name="pods_microphone_label">Microphone</string>
|
||||
<string name="pods_yours">Yours</string>
|
||||
<string name="headset_being_worn_label">Being worn</string>
|
||||
<string name="headset_not_being_worn_label">Not being worn</string>
|
||||
<string name="pods_case_unknown_state">Unknown state</string>
|
||||
|
||||
<string name="last_seen_x">Last seen: %s</string>
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import eu.darken.capod.pods.core.apple.HasAppleColor
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AirPodsGen4AncTest : BaseAirPodsTest() {
|
||||
|
||||
@Test
|
||||
fun `AirPods Gen4 with ANC via log from #226`() = runTest {
|
||||
create<AirPodsGen4Anc>("07 19 01 1B 20 0B 9A 8F 10 00 04 43 DF EC 1D D3 F1 C3 F4 A1 9B 29 26 B9 E7 3A A0") {
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x1B20.toUShort()
|
||||
rawStatus shouldBe 0x0b.toUByte()
|
||||
rawPodsBattery shouldBe 0x9A.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x10.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
batteryLeftPodPercent shouldBe 0.9f
|
||||
batteryRightPodPercent shouldBe 1.0f
|
||||
|
||||
isCaseCharging shouldBe false
|
||||
isLeftPodCharging shouldBe false
|
||||
isRightPodCharging shouldBe false
|
||||
|
||||
isLeftPodInEar shouldBe true
|
||||
isRightPodInEar shouldBe true
|
||||
batteryCasePercent shouldBe null
|
||||
|
||||
caseLidState shouldBe DualApplePods.LidState.UNKNOWN
|
||||
|
||||
state shouldBe HasStateDetectionAirPods.ConnectionState.IDLE
|
||||
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name
|
||||
|
||||
model shouldBe PodDevice.Model.AIRPODS_GEN4_ANC
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.DualApplePods
|
||||
import eu.darken.capod.pods.core.apple.HasAppleColor
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AirPodsGen4Test : BaseAirPodsTest() {
|
||||
|
||||
@Test
|
||||
fun `AirPods Gen4 via log from #225`() = runTest {
|
||||
create<AirPodsGen4>("07 19 01 19 20 2B 33 8F 11 00 04 59 D4 57 20 0F 1C 13 38 B2 00 74 E9 DD 70 D7 A5") {
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x1920.toUShort()
|
||||
rawStatus shouldBe 0x2B.toUByte()
|
||||
rawPodsBattery shouldBe 0x33.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x11.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
batteryLeftPodPercent shouldBe 0.3f
|
||||
batteryRightPodPercent shouldBe 0.3f
|
||||
|
||||
isCaseCharging shouldBe false
|
||||
isLeftPodCharging shouldBe false
|
||||
isRightPodCharging shouldBe false
|
||||
|
||||
isLeftPodInEar shouldBe true
|
||||
isRightPodInEar shouldBe true
|
||||
batteryCasePercent shouldBe null
|
||||
|
||||
caseLidState shouldBe DualApplePods.LidState.UNKNOWN
|
||||
|
||||
state shouldBe HasStateDetectionAirPods.ConnectionState.IDLE
|
||||
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name
|
||||
|
||||
model shouldBe PodDevice.Model.AIRPODS_GEN4
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,4 +40,33 @@ class BeatsFitProTest : BaseAirPodsTest() {
|
||||
model shouldBe PodDevice.Model.BEATS_FIT_PRO
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extra rl test case`() = runTest {
|
||||
create<BeatsFitPro>("07 19 01 12 20 04 FA 92 54 11 24 CE B1 DF 9D 8D F5 E3 37 60 B1 23 8B 90 3B 63 3F") {
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x1220.toUShort()
|
||||
rawStatus shouldBe 0x04.toUByte()
|
||||
rawPodsBattery shouldBe 0xFA.toUByte()
|
||||
rawFlags shouldBe 0x9.toUShort()
|
||||
rawCaseBattery shouldBe 0x2.toUShort()
|
||||
rawCaseLidState shouldBe 0x54.toUByte()
|
||||
rawDeviceColor shouldBe 0x11.toUByte()
|
||||
rawSuffix shouldBe 0x24.toUByte()
|
||||
|
||||
isLeftPodMicrophone shouldBe false
|
||||
isRightPodMicrophone shouldBe true
|
||||
|
||||
batteryLeftPodPercent shouldBe null
|
||||
batteryRightPodPercent shouldBe 1.0f
|
||||
|
||||
isCaseCharging shouldBe false
|
||||
isRightPodCharging shouldBe true
|
||||
isLeftPodCharging shouldBe false
|
||||
batteryCasePercent shouldBe 0.2f
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.UNKNOWN.name
|
||||
|
||||
model shouldBe PodDevice.Model.BEATS_FIT_PRO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package eu.darken.capod.pods.core.apple.beats
|
||||
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.airpods.HasStateDetectionAirPods
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class PowerBeats4Test : BaseAirPodsTest() {
|
||||
|
||||
@Test
|
||||
fun `playing music`() = runTest {
|
||||
create<PowerBeats4>("07 19 01 0D 20 00 02 80 01 00 05 07 C5 E1 9C BD 9A 05 0E AE 9E 56 53 2F F9 75 4A") {
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x0D20.toUShort()
|
||||
rawStatus shouldBe 0x0.toUByte()
|
||||
rawPodsBattery shouldBe 0x02.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x05.toUByte()
|
||||
|
||||
batteryHeadsetPercent shouldBe 0.2f
|
||||
|
||||
model shouldBe PodDevice.Model.POWERBEATS_4
|
||||
|
||||
state shouldBe HasStateDetectionAirPods.ConnectionState.MUSIC
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `extra test case`() = runTest {
|
||||
create<PowerBeats4>("07 19 01 0D 20 00 02 80 02 00 04 80 90 60 77 32 C2 0C 75 7A 3D 7E D7 1C 0E B8 43") {
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x0D20.toUShort()
|
||||
rawStatus shouldBe 0x0.toUByte()
|
||||
rawPodsBattery shouldBe 0x02.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x02.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
batteryHeadsetPercent shouldBe 0.2f
|
||||
|
||||
model shouldBe PodDevice.Model.POWERBEATS_4
|
||||
|
||||
state shouldBe HasStateDetectionAirPods.ConnectionState.IDLE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `disconnected state`() = runTest {
|
||||
create<PowerBeats4>("07 19 01 0D 20 00 02 80 01 00 00 25 DF 66 40 AF 44 7B 77 95 8F D1 92 50 26 11 74") {
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x0D20.toUShort()
|
||||
rawStatus shouldBe 0x0.toUByte()
|
||||
rawPodsBattery shouldBe 0x02.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0x0.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x00.toUByte()
|
||||
rawSuffix shouldBe 0x00.toUByte()
|
||||
|
||||
batteryHeadsetPercent shouldBe 0.2f
|
||||
|
||||
model shouldBe PodDevice.Model.POWERBEATS_4
|
||||
|
||||
state shouldBe HasStateDetectionAirPods.ConnectionState.DISCONNECTED
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
package="eu.darken.capod">
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<uses-feature android:name="android.hardware.type.watch" />
|
||||
|
||||
<application
|
||||
@@ -41,4 +42,4 @@
|
||||
tools:node="remove" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/request_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
@@ -44,11 +44,12 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/grant_action"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:text="@string/general_grant_permission_action"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/permission_description" />
|
||||
|
||||
@@ -69,11 +69,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
|
||||
app:layout_constraintEnd_toStartOf="@id/pod_case_container"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier_top"
|
||||
app:layout_constraintVertical_bias="0.2">
|
||||
app:layout_constraintTop_toTopOf="@+id/pod_right_container">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_icon"
|
||||
@@ -199,8 +197,7 @@
|
||||
android:layout_marginEnd="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/pod_case_container"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier_top"
|
||||
app:layout_constraintVertical_bias="0.2">
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier_top">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_icon"
|
||||
|
||||
@@ -38,6 +38,11 @@ android {
|
||||
create("foss") {
|
||||
dimension = "version"
|
||||
signingConfig = signingConfigs["releaseFoss"]
|
||||
// The info block is encrypted and can only be read by google
|
||||
dependenciesInfo {
|
||||
includeInApk = false
|
||||
includeInBundle = false
|
||||
}
|
||||
}
|
||||
create("gplay") {
|
||||
dimension = "version"
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="foss_upgrade_donate_label">Donează</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">Am donat deja</string>
|
||||
<string name="foss_upgrade_no_money_label">Mi-am cheltuit toți banii pe AirPods</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="upgrades_gplay_unavailable_error">Serviciile Google Play nu sunt disponibile.</string>
|
||||
<string name="upgrades_no_purchases_found_check_account">Nu s-au găsit achiziții. Folosești contul corect?</string>
|
||||
</resources>
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
<activity
|
||||
android:name=".main.ui.MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppThemeSplash"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/AppThemeSplash">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -76,8 +76,6 @@
|
||||
android:name=".common.debug.recording.ui.RecorderActivity"
|
||||
android:theme="@style/AppThemeFloating" />
|
||||
|
||||
<service android:name=".common.debug.recording.core.RecorderService" />
|
||||
|
||||
<!-- Worker stuff-->
|
||||
<service
|
||||
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
||||
@@ -87,7 +85,15 @@
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
tools:node="remove" />
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
|
||||
<meta-data
|
||||
android:name="androidx.work.WorkManagerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -14,9 +14,12 @@ import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.debug.recording.ui.RecorderActivity
|
||||
import eu.darken.capod.common.flow.DynamicStateFlow
|
||||
import eu.darken.capod.common.startServiceCompat
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.plus
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
@@ -55,8 +58,6 @@ class RecorderModule @Inject constructor(
|
||||
newRecorder.start(createRecordingFilePath())
|
||||
triggerFile.createNewFile()
|
||||
|
||||
context.startServiceCompat(Intent(context, RecorderService::class.java))
|
||||
|
||||
log(TAG, INFO) { "Build.Fingerprint: ${Build.FINGERPRINT}" }
|
||||
log(TAG, INFO) { "BuildConfig.Versions: ${BuildConfigWrap.VERSION_DESCRIPTION_LONG}" }
|
||||
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
package eu.darken.capod.common.debug.recording.core
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.BuildConfigWrap
|
||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
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.common.uix.Service2
|
||||
import eu.darken.capod.main.ui.MainActivity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class RecorderService : Service2() {
|
||||
private lateinit var builder: NotificationCompat.Builder
|
||||
|
||||
@Inject lateinit var recorderModule: RecorderModule
|
||||
@Inject lateinit var notificationManager: NotificationManager
|
||||
@Inject lateinit var dispatcherProvider: DispatcherProvider
|
||||
private val recorderScope by lazy {
|
||||
CoroutineScope(SupervisorJob() + dispatcherProvider.IO)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(
|
||||
NOTIF_CHANID_DEBUG,
|
||||
getString(R.string.debug_notification_channel_label),
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
val openIntent = Intent(this, MainActivity::class.java)
|
||||
val openPi = PendingIntent.getActivity(
|
||||
this,
|
||||
0,
|
||||
openIntent,
|
||||
PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val stopIntent = Intent(this, RecorderService::class.java)
|
||||
stopIntent.action = STOP_ACTION
|
||||
val stopPi = PendingIntent.getService(
|
||||
this,
|
||||
0,
|
||||
stopIntent,
|
||||
PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
builder = NotificationCompat.Builder(this, NOTIF_CHANID_DEBUG)
|
||||
.setChannelId(NOTIF_CHANID_DEBUG)
|
||||
.setContentIntent(openPi)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setSmallIcon(R.drawable.ic_baseline_bug_report_24)
|
||||
.setContentText("Idle")
|
||||
.setContentTitle(getString(eu.darken.capod.common.R.string.app_name))
|
||||
.addAction(NotificationCompat.Action.Builder(0, getString(R.string.general_done_action), stopPi).build())
|
||||
|
||||
startForeground(NOTIFICATION_ID, builder.build())
|
||||
|
||||
recorderModule.state
|
||||
.onEach {
|
||||
if (it.isRecording) {
|
||||
builder.setContentText("Recording debug log: ${it.currentLogPath?.path}")
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
} else {
|
||||
stopForeground(true)
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
.launchIn(recorderScope)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
log(TAG) { "onStartCommand(intent=$intent, flags=$flags, startId=$startId" }
|
||||
if (intent?.action == STOP_ACTION) {
|
||||
recorderScope.launch {
|
||||
recorderModule.stopRecorder()
|
||||
}
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
recorderScope.coroutineContext.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Debug", "Log", "Recorder", "Service")
|
||||
private val NOTIF_CHANID_DEBUG = "${BuildConfigWrap.APPLICATION_ID}.notification.channel.debug"
|
||||
private const val STOP_ACTION = "STOP_SERVICE"
|
||||
private const val NOTIFICATION_ID = 53
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ class RecorderActivityVM @Inject constructor(
|
||||
}
|
||||
|
||||
|
||||
val chooserIntent = Intent.createChooser(intent, context.getString(R.string.debug_debuglog_file_label))
|
||||
val chooserIntent = Intent.createChooser(intent, context.getString(R.string.support_debuglog_label))
|
||||
shareEvent.postValue(chooserIntent)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package eu.darken.capod.common.debug.recording.ui
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.PrivacyPolicy
|
||||
import eu.darken.capod.common.WebpageTool
|
||||
|
||||
class RecorderConsentDialog(
|
||||
private val context: Context,
|
||||
private val webpageTool: WebpageTool
|
||||
) {
|
||||
fun showDialog(onStartRecord: () -> Unit) {
|
||||
MaterialAlertDialogBuilder(context).apply {
|
||||
setTitle(R.string.support_debuglog_label)
|
||||
setMessage(R.string.settings_debuglog_explanation)
|
||||
setPositiveButton(R.string.debug_debuglog_record_action) { _, _ -> onStartRecord() }
|
||||
setNegativeButton(R.string.general_cancel_action) { _, _ -> }
|
||||
setNeutralButton(R.string.settings_privacy_policy_label) { _, _ ->
|
||||
webpageTool.open(PrivacyPolicy.URL)
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
-17
@@ -1,14 +1,10 @@
|
||||
package eu.darken.capod.main.ui.settings.general.debug
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.preference.Preference
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.debug.DebugSettings
|
||||
import eu.darken.capod.common.observe2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment3
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -25,17 +21,4 @@ class DebugSettingsFragment : PreferenceFragment3() {
|
||||
|
||||
override val preferenceFile: Int = R.xml.preferences_debug
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val logPref = findPreference<Preference>("debug.log.record")!!
|
||||
vm.state.observe2(this) {
|
||||
logPref.summary = it.currentLogPath?.path
|
||||
}
|
||||
logPref.setOnPreferenceClickListener {
|
||||
vm.toggleRecorder()
|
||||
true
|
||||
}
|
||||
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
|
||||
}
|
||||
-12
@@ -6,11 +6,9 @@ import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
import eu.darken.capod.common.debug.DebugSettings
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.debug.recording.core.RecorderModule
|
||||
import eu.darken.capod.common.uix.ViewModel3
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -18,13 +16,10 @@ import javax.inject.Inject
|
||||
class DebugSettingsFragmentVM @Inject constructor(
|
||||
private val handle: SavedStateHandle,
|
||||
dispatcherProvider: DispatcherProvider,
|
||||
private val recorderModule: RecorderModule,
|
||||
private val generalSettings: GeneralSettings,
|
||||
private val debugSettings: DebugSettings,
|
||||
) : ViewModel3(dispatcherProvider) {
|
||||
|
||||
val state = recorderModule.state.asLiveData2()
|
||||
|
||||
init {
|
||||
debugSettings.showUnfiltered.flow
|
||||
.distinctUntilChanged()
|
||||
@@ -37,13 +32,6 @@ class DebugSettingsFragmentVM @Inject constructor(
|
||||
.launchInViewModel()
|
||||
}
|
||||
|
||||
fun toggleRecorder() = launch {
|
||||
if (recorderModule.state.first().isRecording) {
|
||||
recorderModule.stopRecorder()
|
||||
} else {
|
||||
recorderModule.startRecorder()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Settings", "Debug", "VM")
|
||||
|
||||
@@ -5,10 +5,10 @@ import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.preference.Preference
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.ClipboardHelper
|
||||
import eu.darken.capod.common.WebpageTool
|
||||
import eu.darken.capod.common.debug.recording.ui.RecorderConsentDialog
|
||||
import eu.darken.capod.common.observe2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment3
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
@@ -25,28 +25,36 @@ class SupportFragment : PreferenceFragment3() {
|
||||
|
||||
override val settings: GeneralSettings by lazy { generalSettings }
|
||||
|
||||
@Inject lateinit var clipboardHelper: ClipboardHelper
|
||||
@Inject lateinit var webpageTool: WebpageTool
|
||||
|
||||
private val installIdPref by lazy { findPreference<Preference>("support.installid")!! }
|
||||
|
||||
override fun onPreferencesCreated() {
|
||||
installIdPref.setOnPreferenceClickListener {
|
||||
vm.copyInstallID()
|
||||
true
|
||||
}
|
||||
|
||||
super.onPreferencesCreated()
|
||||
}
|
||||
private val debugLogPref by lazy { findPreference<Preference>("support.debuglog")!! }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
vm.clipboardEvent.observe2(this) { installId ->
|
||||
Snackbar.make(requireView(), installId, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.general_copy_action) {
|
||||
clipboardHelper.copyToClipboard(installId)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
vm.recorderState.observe2(this) { state ->
|
||||
debugLogPref.setIcon(
|
||||
if (state.isRecording) R.drawable.ic_cancel
|
||||
else R.drawable.ic_baseline_bug_report_24
|
||||
)
|
||||
debugLogPref.setTitle(
|
||||
if (state.isRecording) R.string.debug_debuglog_stop_action
|
||||
else R.string.debug_debuglog_record_action
|
||||
)
|
||||
debugLogPref.summary = when {
|
||||
state.isRecording -> state.currentLogPath?.path
|
||||
else -> getString(R.string.debug_debuglog_record_action)
|
||||
}
|
||||
|
||||
debugLogPref.setOnPreferenceClickListener {
|
||||
if (state.isRecording) {
|
||||
vm.stopDebugLog()
|
||||
} else {
|
||||
RecorderConsentDialog(requireContext(), webpageTool).showDialog {
|
||||
vm.startDebugLog()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,27 @@
|
||||
package eu.darken.capod.main.ui.settings.support
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import eu.darken.capod.common.InstallId
|
||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
import eu.darken.capod.common.livedata.SingleLiveEvent
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.recording.core.RecorderModule
|
||||
import eu.darken.capod.common.uix.ViewModel3
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class SupportFragmentVM @Inject constructor(
|
||||
private val handle: SavedStateHandle,
|
||||
private val dispatcherProvider: DispatcherProvider,
|
||||
private val installId: InstallId,
|
||||
private val recorderModule: RecorderModule,
|
||||
) : ViewModel3(dispatcherProvider) {
|
||||
|
||||
val clipboardEvent = SingleLiveEvent<String>()
|
||||
val recorderState = recorderModule.state.asLiveData2()
|
||||
|
||||
fun copyInstallID() = launch {
|
||||
clipboardEvent.postValue(installId.id)
|
||||
fun startDebugLog() = launch {
|
||||
log(TAG) { "startDebugLog()" }
|
||||
recorderModule.startRecorder()
|
||||
}
|
||||
|
||||
fun stopDebugLog() = launch {
|
||||
log(TAG) { "stopDebugLog()" }
|
||||
recorderModule.stopRecorder()
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import androidx.annotation.LayoutRes
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.coroutine.AppScope
|
||||
@@ -41,6 +42,7 @@ import kotlinx.coroutines.withTimeout
|
||||
import java.time.Duration
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WidgetProvider : AppWidgetProvider() {
|
||||
|
||||
@@ -95,6 +97,27 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of cells needed for given size of the widget.
|
||||
*
|
||||
* The value is determined in accordance with official guidelines
|
||||
* for designing widgets, see:
|
||||
* https://developer.android.com/guide/practices/ui_guidelines/widget_design
|
||||
*
|
||||
* Thanks to Jakub S. on Stackoverflow for this solution:
|
||||
* https://stackoverflow.com/a/37522648/10866268
|
||||
*
|
||||
* @param size Widget size in dp.
|
||||
* @return Size in number of cells.
|
||||
*/
|
||||
private fun getCellsForSize(size: Int): Int {
|
||||
var n = 2
|
||||
while (70 * n - 30 < size) {
|
||||
++n
|
||||
}
|
||||
return n - 1
|
||||
}
|
||||
|
||||
private suspend fun updateWidget(
|
||||
context: Context,
|
||||
widgetManager: AppWidgetManager,
|
||||
@@ -107,7 +130,23 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
|
||||
val layout = when {
|
||||
!upgradeRepo.isPro() -> createUpgradeRequiredLayout(context)
|
||||
device is DualPodDevice -> createDualPodLayout(context, device)
|
||||
device is DualPodDevice -> {
|
||||
val minWidth = widgetManager.getAppWidgetOptions(widgetId)
|
||||
.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
|
||||
val columns = getCellsForSize(minWidth)
|
||||
|
||||
/* Enable wide widgets only when we are provided with 5 or
|
||||
* more columns of space.
|
||||
* Although the minimum size is only 2x1, the safeguards are
|
||||
* added if these restrictions will ever be loosened in the future.
|
||||
*/
|
||||
val layout = when (columns) {
|
||||
in 1 .. 4 -> R.layout.widget_pod_dual_compact_layout
|
||||
else -> R.layout.widget_pod_dual_wide_layout
|
||||
}
|
||||
|
||||
createDualPodLayout(context, device, layout)
|
||||
}
|
||||
device is SinglePodDevice -> createSinglePodLayout(context, device)
|
||||
device is PodDevice -> createUnknownPodLayout(context, device)
|
||||
else -> createNoDeviceLayout(context)
|
||||
@@ -169,8 +208,9 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
private fun createDualPodLayout(
|
||||
context: Context,
|
||||
podDevice: DualPodDevice,
|
||||
): RemoteViews = RemoteViews(context.packageName, R.layout.widget_pod_dual_layout).apply {
|
||||
log(TAG, VERBOSE) { "createSinglePodLayout(context=$context, podDevice=$podDevice)" }
|
||||
@LayoutRes layout: Int
|
||||
): RemoteViews = RemoteViews(context.packageName, layout).apply {
|
||||
log(TAG, VERBOSE) { "createSinglePodLayout(context=$context, podDevice=$podDevice), layout=${layout}" }
|
||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
|
||||
@@ -80,8 +80,6 @@ class MonitorWorker @AssistedInject constructor(
|
||||
val start = System.currentTimeMillis()
|
||||
log(TAG, VERBOSE) { "Executing $inputData now (runAttemptCount=$runAttemptCount)" }
|
||||
|
||||
setForeground(monitorNotifications.getForegroundInfo(null))
|
||||
|
||||
doDoWork()
|
||||
|
||||
val duration = System.currentTimeMillis() - start
|
||||
@@ -108,6 +106,8 @@ class MonitorWorker @AssistedInject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
setForeground(monitorNotifications.getForegroundInfo(null))
|
||||
|
||||
val monitorJob = podMonitor.mainDevice
|
||||
.setupCommonEventHandlers(TAG) { "PodMonitor" }
|
||||
.distinctUntilChanged()
|
||||
|
||||
@@ -19,7 +19,16 @@ import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.hasApiLevel
|
||||
import eu.darken.capod.common.notifications.PendingIntentCompat
|
||||
import eu.darken.capod.main.ui.MainActivity
|
||||
import eu.darken.capod.pods.core.DualPodDevice
|
||||
import eu.darken.capod.pods.core.HasCase
|
||||
import eu.darken.capod.pods.core.HasChargeDetection
|
||||
import eu.darken.capod.pods.core.HasEarDetection
|
||||
import eu.darken.capod.pods.core.PodDevice
|
||||
import eu.darken.capod.pods.core.SinglePodDevice
|
||||
import eu.darken.capod.pods.core.getBatteryLevelCase
|
||||
import eu.darken.capod.pods.core.getBatteryLevelHeadset
|
||||
import eu.darken.capod.pods.core.getBatteryLevelLeftPod
|
||||
import eu.darken.capod.pods.core.getBatteryLevelRightPod
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import javax.inject.Inject
|
||||
@@ -71,9 +80,65 @@ class MonitorNotifications @Inject constructor(
|
||||
}
|
||||
|
||||
return builder.apply {
|
||||
|
||||
// Options here should be mutually exclusive, and are prioritized by their order of importance
|
||||
// Some options are omitted here, as they will conflict with other options
|
||||
// TODO: Implement a settings pane to allow user to customize this
|
||||
val stateText = when {
|
||||
// Pods charging state
|
||||
// This goes first as pods should not be worn if it is still charging
|
||||
device is HasChargeDetection && device.isHeadsetBeingCharged -> {
|
||||
context.getString(eu.darken.capod.common.R.string.pods_charging_label)
|
||||
}
|
||||
|
||||
// Pods wear state
|
||||
device is HasEarDetection -> {
|
||||
if (device.isBeingWorn) context.getString(eu.darken.capod.common.R.string.headset_being_worn_label)
|
||||
else context.getString(eu.darken.capod.common.R.string.headset_not_being_worn_label)
|
||||
}
|
||||
|
||||
// Case charge state
|
||||
// This is under pods wear state as we don't want it conflicting with it
|
||||
device is HasCase && device.isCaseCharging -> {
|
||||
context.getString(eu.darken.capod.common.R.string.pods_charging_label)
|
||||
}
|
||||
|
||||
else -> context.getString(eu.darken.capod.common.R.string.pods_case_unknown_state)
|
||||
}
|
||||
|
||||
val batteryText = when (device) {
|
||||
is DualPodDevice -> {
|
||||
val left = device.getBatteryLevelLeftPod(context)
|
||||
val right = device.getBatteryLevelRightPod(context)
|
||||
when {
|
||||
device is HasCase -> {
|
||||
val case = device.getBatteryLevelCase(context)
|
||||
"$left $case $right"
|
||||
}
|
||||
|
||||
else -> "$left $right"
|
||||
}
|
||||
}
|
||||
|
||||
is SinglePodDevice -> {
|
||||
val headset = device.getBatteryLevelHeadset(context)
|
||||
when {
|
||||
device is HasCase -> {
|
||||
val case = device.getBatteryLevelCase(context)
|
||||
"$headset $case"
|
||||
}
|
||||
|
||||
else -> headset
|
||||
}
|
||||
}
|
||||
|
||||
else -> "?"
|
||||
}
|
||||
|
||||
setStyle(NotificationCompat.DecoratedCustomViewStyle())
|
||||
setCustomContentView(notificationViewFactory.createContentView(device))
|
||||
setCustomBigContentView(notificationViewFactory.createContentView(device))
|
||||
setSmallIcon(device.iconRes)
|
||||
setContentTitle("$batteryText ~ $stateText")
|
||||
setSubText(null)
|
||||
log(TAG, VERBOSE) { "updatingNotification(): $device" }
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.preference.CheckBoxPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.TwoStatePreference
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.bluetooth.BluetoothDevice2
|
||||
@@ -51,17 +51,17 @@ class ReactionSettingsFragment : PreferenceFragment3() {
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||
if (preference.key == reactionSettings.autoPlay.key && !isPro) {
|
||||
preference as CheckBoxPreference
|
||||
preference as TwoStatePreference
|
||||
upgradeRepo.launchBillingFlow(requireActivity())
|
||||
preference.isChecked = false
|
||||
return true
|
||||
} else if (preference.key == reactionSettings.autoPause.key && !isPro) {
|
||||
preference as CheckBoxPreference
|
||||
preference as TwoStatePreference
|
||||
upgradeRepo.launchBillingFlow(requireActivity())
|
||||
preference.isChecked = false
|
||||
return true
|
||||
} else if (preference.key == reactionSettings.autoConnect.key) {
|
||||
preference as CheckBoxPreference
|
||||
preference as TwoStatePreference
|
||||
|
||||
if (!isPro) {
|
||||
upgradeRepo.launchBillingFlow(requireActivity())
|
||||
@@ -79,12 +79,12 @@ class ReactionSettingsFragment : PreferenceFragment3() {
|
||||
return true
|
||||
}
|
||||
} else if (preference.key == reactionSettings.showPopUpOnCaseOpen.key && !isPro) {
|
||||
preference as CheckBoxPreference
|
||||
preference as TwoStatePreference
|
||||
upgradeRepo.launchBillingFlow(requireActivity())
|
||||
preference.isChecked = false
|
||||
return true
|
||||
} else if (preference.key == reactionSettings.showPopUpOnConnection.key && !isPro) {
|
||||
preference as CheckBoxPreference
|
||||
preference as TwoStatePreference
|
||||
upgradeRepo.launchBillingFlow(requireActivity())
|
||||
preference.isChecked = false
|
||||
return true
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z" />
|
||||
</vector>
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_path"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recording_path"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_size"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recording_size"
|
||||
style="@style/TextAppearance.AppCompat.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="32dp"
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_compressed_size"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/recording_size_compressed"
|
||||
style="@style/TextAppearance.AppCompat.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="@+id/label_compressed_size"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Primary"
|
||||
style="@style/Widget.Material3.Toolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body1"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body2"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body3"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/body4"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/bluetooth_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/request_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/permission_description"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/privacy_policy"
|
||||
style="@style/TextAppearance.MaterialComponents.Tooltip"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/grant_action"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/last_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/first_seen"
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/first_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/reception"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reception_icon"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -432,7 +432,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/status"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/last_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/reception"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reception_icon"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -175,7 +175,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/status"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/name"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/last_seen"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/reception"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reception_icon"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/details"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -86,7 +86,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/rawdata_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/rawdata"
|
||||
style="@style/TextAppearance.MaterialComponents.Body2"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/signal"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableEnd="@drawable/ic_baseline_signal_cellular_alt_24"
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_left_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_case_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/pod_right_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/signal"
|
||||
style="@style/TextAppearance.MaterialComponents.Caption"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableEnd="@drawable/ic_baseline_signal_cellular_alt_24"
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/headphones_battery_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Primary"
|
||||
style="@style/Widget.Material3.Toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Primary"
|
||||
style="@style/Widget.Material3.Toolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/PodWidget.Container"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_icon"
|
||||
style="@style/PodInfoItemIcon.Notification.Large"
|
||||
android:src="@drawable/devic_airpods_pro2_left"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_left_label"
|
||||
style="@style/PodInfoItemText.Notification"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
tools:text="100%" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_charging"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_power_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_left_ear"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_hearing_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_case_icon"
|
||||
style="@style/PodInfoItemIcon.Notification.Large"
|
||||
android:src="@drawable/devic_airpods_gen1_case"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_case_label"
|
||||
style="@style/PodInfoItemText.Notification"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
tools:text="100%" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_case_charging"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_power_24" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_icon"
|
||||
style="@style/PodInfoItemIcon.Notification.Large"
|
||||
android:src="@drawable/devic_airpods_pro2_right"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pod_right_label"
|
||||
style="@style/PodInfoItemText.Notification"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
tools:text="100%" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_charging"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_power_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pod_right_ear"
|
||||
style="@style/PodInfoItemIcon.Notification"
|
||||
android:src="@drawable/ic_baseline_hearing_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/PodWidget.TextPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="AirPods Max" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -4,16 +4,6 @@
|
||||
style="@style/PodWidget.Container"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/PodWidget.TextPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
tools:text="AirPods Max" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -46,4 +36,14 @@
|
||||
android:src="@drawable/ic_baseline_hearing_24"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headphones_label"
|
||||
style="@style/PodWidget.TextPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
tools:text="AirPods Max" />
|
||||
</LinearLayout>
|
||||
@@ -18,6 +18,8 @@
|
||||
app:destination="@id/troubleShooterFragment" />
|
||||
<action
|
||||
android:id="@+id/action_overviewFragment_to_onboardingFragment"
|
||||
app:popUpTo="@id/overviewFragment"
|
||||
app:popUpToInclusive="true"
|
||||
app:destination="@id/onboardingFragment" />
|
||||
</fragment>
|
||||
|
||||
@@ -36,7 +38,9 @@
|
||||
tools:layout="@layout/onboarding_fragment">
|
||||
<action
|
||||
android:id="@+id/action_onboardingFragment_to_overviewFragment"
|
||||
app:destination="@id/overviewFragment" />
|
||||
app:destination="@id/overviewFragment"
|
||||
app:popUpToInclusive="true"
|
||||
app:popUpTo="@id/onboardingFragment" />
|
||||
</fragment>
|
||||
|
||||
</navigation>
|
||||
@@ -44,8 +44,6 @@
|
||||
<string name="debug_debuglog_size_label">الحجم</string>
|
||||
<string name="debug_debuglog_size_compressed_label">الحجم المضغوط</string>
|
||||
<string name="debug_notification_channel_label">اشعارات التصحيح</string>
|
||||
<string name="debug_debuglog_file_label">ملف مسجل</string>
|
||||
<string name="debug_debuglog_record_action">ملف التصحيح مسجل</string>
|
||||
<string name="settings_support_installid_label">مُعرف التثبيت</string>
|
||||
<string name="settings_support_installid_desc">تقارير الأخطاء والمشاكل التلقائية تكون مجهول المصدر. شارك مُعرف التثبيت الخاص بك إذا احتاج المطور إلى العثور على الأخطاء والمشاكل الخاصة بك.</string>
|
||||
<string name="settings_support_label">الدعم</string>
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
<string name="debug_debuglog_size_label">Həcm</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Sıxışdırılmış həcm</string>
|
||||
<string name="debug_notification_channel_label">Sazlama bildirişləri</string>
|
||||
<string name="debug_debuglog_file_label">Yazılmış jurnal faylı</string>
|
||||
<string name="debug_debuglog_record_action">Sazlama jurnalına yaz</string>
|
||||
<string name="settings_support_installid_label">Quraşdırma kimliyi</string>
|
||||
<string name="settings_support_installid_desc">Avtomatik xəta hesabatları anonimdir. Tərtibatçının xəta hesabatlarınızı tapmasına ehtiyacı varsa quraşdırma kimliyinizi paylaşın.</string>
|
||||
<string name="settings_support_label">Dəstək</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Памер</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Сціснуты памер</string>
|
||||
<string name="debug_notification_channel_label">Апавяшчэнні адладкі</string>
|
||||
<string name="debug_debuglog_file_label">Файл журнала</string>
|
||||
<string name="debug_debuglog_record_action">Запісаць лог аладкі ў журнал</string>
|
||||
<string name="settings_support_installid_label">ID інсталяцыі</string>
|
||||
<string name="settings_support_installid_desc">Аўтаматычныя справаздачы пра памылкі з\'яўляюцца ананімнымі. Падзяліцеся вашым ID інсталяцыі, калі распрацоўшчыку спатрэбіцца доступ да вашых справаздач пра памылкі.</string>
|
||||
<string name="settings_support_label">Падтрымка</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Mida</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Mida comprimida</string>
|
||||
<string name="debug_notification_channel_label">Notificacions de depuració</string>
|
||||
<string name="debug_debuglog_file_label">Fitxer de registre gravat</string>
|
||||
<string name="debug_debuglog_record_action">Grava el registre de depuració</string>
|
||||
<string name="settings_support_installid_label">ID d\'instal·lació</string>
|
||||
<string name="settings_support_installid_desc">Els informes d\'error automàtics són anònims. Compartiu el vostre ID d\'instal·lació si el desenvolupador necessita trobar els vostres informes d\'error.</string>
|
||||
<string name="settings_support_label">Suport</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Velikost</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Komprimovaná velikost</string>
|
||||
<string name="debug_notification_channel_label">Oznámení o ladění</string>
|
||||
<string name="debug_debuglog_file_label">Zaznamenaný soubor protokolu</string>
|
||||
<string name="debug_debuglog_record_action">Zaznamenat protokol ladění</string>
|
||||
<string name="settings_support_installid_label">ID instalace</string>
|
||||
<string name="settings_support_installid_desc">Automatická hlášení chyb jsou anonymní. Sdílíte pouze své ID instalace, pokud vývojář potřebuje najít vaše chybová hlášení.</string>
|
||||
<string name="settings_support_label">Podpora</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Größe</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Komprimierte Größe</string>
|
||||
<string name="debug_notification_channel_label">Debug Benachrichtigungen</string>
|
||||
<string name="debug_debuglog_file_label">Aufgenommene Log-Datei</string>
|
||||
<string name="debug_debuglog_record_action">Debug Log aufnehmen</string>
|
||||
<string name="settings_support_installid_label">Installations-ID</string>
|
||||
<string name="settings_support_installid_desc">Automatische Fehlermeldungen sind anonym. Teilen Sie Ihre Installations- ID dem Entwickler mit, wenn er Ihre Fehlerberichte finden muss.</string>
|
||||
<string name="settings_support_label">Unterstützung</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Μέγεθος</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Συμπιεσμένο μέγεθος</string>
|
||||
<string name="debug_notification_channel_label">Ειδοποιήσεις εντοπισμού σφαλμάτων</string>
|
||||
<string name="debug_debuglog_file_label">Εγγεγραμμένο αρχείο καταγραφής</string>
|
||||
<string name="debug_debuglog_record_action">Εγγραφή καταγραφής εντοπισμού σφαλμάτων</string>
|
||||
<string name="settings_support_installid_label">Αναγνωριστικό εγκατάστασης</string>
|
||||
<string name="settings_support_installid_desc">Οι αυτόματες αναφορές σφαλμάτων είναι ανώνυμες. Κοινοποιήστε το αναγνωριστικό εγκατάστασης εάν ο προγραμματιστής πρέπει να βρει τις αναφορές σας σφαλμάτων.</string>
|
||||
<string name="settings_support_label">Υποστήριξη</string>
|
||||
|
||||
@@ -11,6 +11,4 @@
|
||||
<string name="debug_debuglog_size_label">Tamaño</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Tamaño comprimido</string>
|
||||
<string name="debug_notification_channel_label">Depurar notificaciones</string>
|
||||
<string name="debug_debuglog_file_label">Archivo de registro guardado</string>
|
||||
<string name="debug_debuglog_record_action">Grabar registro de depuracion</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Tamaño</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Tamaño comprimido</string>
|
||||
<string name="debug_notification_channel_label">Notificaciones de la depuración</string>
|
||||
<string name="debug_debuglog_file_label">Registro guardado</string>
|
||||
<string name="debug_debuglog_record_action">Registro de depuración</string>
|
||||
<string name="settings_support_installid_label">ID de la instalación</string>
|
||||
<string name="settings_support_installid_desc">Los informes automáticos de errores son anónimos. Comparte tu ID de la instalación si el desarrollador necesita encontrar tus informes de errores.</string>
|
||||
<string name="settings_support_label">Ayuda</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Taille</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Taille compressée</string>
|
||||
<string name="debug_notification_channel_label">Notifications de débogage</string>
|
||||
<string name="debug_debuglog_file_label">Ficher journal enregistré</string>
|
||||
<string name="debug_debuglog_record_action">Enregistrer le journal de débogage</string>
|
||||
<string name="settings_support_installid_label">ID d’installation</string>
|
||||
<string name="settings_support_installid_desc">Les relevés automatiques d’erreur sont anonymes. Partagez votre ID d’installation au cas où le développeur aurait besoin de trouver votre relevé d’erreur.</string>
|
||||
<string name="settings_support_label">Assistance</string>
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
<string name="debug_debuglog_size_label">Méret</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Tömörített_méret</string>
|
||||
<string name="debug_notification_channel_label">Hibakeresési_értesítések</string>
|
||||
<string name="debug_debuglog_file_label">Rögzített_naplófájl</string>
|
||||
<string name="debug_debuglog_record_action">Hibakeresési_napló_rögzítése</string>
|
||||
<string name="settings_support_installid_label">Azonosító</string>
|
||||
<string name="settings_support_installid_desc">Az automatikus hibajelentések névtelenek. Ossza meg azonosítóját, hogy a fejlesztő megtalálja a hibajelentéseket.</string>
|
||||
<string name="settings_support_label">Támogatás</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Ukuran</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Ukuran terkompresi</string>
|
||||
<string name="debug_notification_channel_label">Notifikasi debug</string>
|
||||
<string name="debug_debuglog_file_label">File log yang direkam</string>
|
||||
<string name="debug_debuglog_record_action">Rekam log debug</string>
|
||||
<string name="settings_support_installid_label">ID pemasangan</string>
|
||||
<string name="settings_support_installid_desc">Laporan kesalahan otomatis bersifat anonim. Bagikan ID pemasangan anda jika pengembang perlu menemukan laporan kesalahan anda.</string>
|
||||
<string name="settings_support_label">Dukungan</string>
|
||||
|
||||
@@ -7,24 +7,24 @@
|
||||
<string name="general_upgrade_action">Aggiorna</string>
|
||||
<string name="general_check_action">Controlla</string>
|
||||
<string name="general_close_action">Chiudi</string>
|
||||
<string name="upgrade_capod_label">Aggiorna CAPod</string>
|
||||
<string name="upgrade_capod_label">Passa a CAPod PRO</string>
|
||||
<string name="upgrade_capod_description">Ottieni funzionalità aggiuntive e supporta lo sviluppatore.</string>
|
||||
<string name="settings_monitor_mode_label">Modalità monitoraggio</string>
|
||||
<string name="settings_monitor_mode_description">Sotto quali circostanze questa applicazione monitora i dati Bluetooth.</string>
|
||||
<string name="settings_monitor_mode_label">Modalità di monitoraggio</string>
|
||||
<string name="settings_monitor_mode_description">Circostanze in cui questa applicazione monitora i dati Bluetooth.</string>
|
||||
<string name="settings_scanner_mode_label">Modalità di scansione</string>
|
||||
<string name="settings_scanner_mode_description">Il Bluetooth a basso consumo energetico dovrebbe dare priorità alle performance o risparmiare batteria?</string>
|
||||
<string name="settings_scanner_mode_description">La scansione dei dati BLE deve dare priorità alle performance o al risparmio di batteria?</string>
|
||||
<string name="settings_autopause_label">Pausa automatica</string>
|
||||
<string name="settings_autopause_description">Metti in pausa l\'audio quando viene rimossa la cuffia da un orecchio.</string>
|
||||
<string name="settings_showall_label">Mostra tutti i dispositivi</string>
|
||||
<string name="settings_showall_description">Mostra i dispositivi delle altre persone vicine a te.</string>
|
||||
<string name="settings_autopplay_label">Riproduzione automatica</string>
|
||||
<string name="settings_autoplay_description">Avvia riproduzione audio quando il dispositivo è indossato.</string>
|
||||
<string name="settings_fake_data_label">Dati immaginari</string>
|
||||
<string name="settings_fake_data_label">Dati fittizzi</string>
|
||||
<string name="settings_fake_data_description">Mostra dati fittizi, ovvero simula dispositivi che in realtà non esistono.</string>
|
||||
<string name="settings_debug_label">Impostazioni di debug</string>
|
||||
<string name="settings_debug_description">Impostazioni aggiuntive che possono aiutare a risolvere i problemi con l\'applicazione.</string>
|
||||
<string name="settings_signal_minimum_label">Qualità del segnale minima</string>
|
||||
<string name="settings_signal_minimum_description">La minima qualità del segnale che il dispositivo necessità per poter essere considerato tuo.</string>
|
||||
<string name="settings_debug_description">Impostazioni aggiuntive che possono aiutare a risolvere i problemi dell\'app.</string>
|
||||
<string name="settings_signal_minimum_label">Qualità minima di segnale</string>
|
||||
<string name="settings_signal_minimum_description">La qualità minima di segnale che il dispositivo necessita per essere considerato tuo.</string>
|
||||
<string name="settings_autoconnect_label">Connessione automatica</string>
|
||||
<string name="settings_autoconnect_description">Se Android non si connette automaticamente, possiamo chiedergli di farlo. Questo imposterà la modalità di monitoraggio su \'Sempre\'.</string>
|
||||
<string name="settings_autoconnect_condition_label">Condizione per la connessione automatica</string>
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Dimensione</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Dimensione compressa</string>
|
||||
<string name="debug_notification_channel_label">Notifiche di Debug</string>
|
||||
<string name="debug_debuglog_file_label">File di log registrati</string>
|
||||
<string name="debug_debuglog_record_action">Log di debug</string>
|
||||
<string name="settings_support_installid_label">ID d\'installazione</string>
|
||||
<string name="settings_support_installid_desc">Le segnalazioni automatiche degli errori sono anonime. Condividi il tuo ID d\'installazione con lo sviluppatore se necessita di trovare la tua segnalazione all\'interno del registro segnalazioni.</string>
|
||||
<string name="settings_support_label">Supporto</string>
|
||||
@@ -83,8 +81,7 @@
|
||||
<string name="help_translate_label">Traduzione</string>
|
||||
<string name="help_translate_description">Aiuta a tradurre l\'applicazione nella tua lingua preferita.</string>
|
||||
<string name="translators_thanks_title">Traduttori</string>
|
||||
<string name="translators_thanks_description">darken
|
||||
Filippo Lolli</string>
|
||||
<string name="translators_thanks_description">Filippo Lolli (IG: @lolli_filippo)</string>
|
||||
<string name="widget_description">Un widget che mostra l\'ultimo stato del dispositivo.</string>
|
||||
<string name="settings_compat_indirectcallback_title">Consegna indiretta dei dati</string>
|
||||
<string name="settings_compat_indirectcallback_summary">Utilizza un metodo alternativo per ricevere dati BLE dal sistema (broadcast invece di callback).</string>
|
||||
|
||||
@@ -50,8 +50,6 @@
|
||||
<string name="debug_debuglog_size_label">מידה</string>
|
||||
<string name="debug_debuglog_size_compressed_label">גודל דחיסה</string>
|
||||
<string name="debug_notification_channel_label">ניפוי באגים</string>
|
||||
<string name="debug_debuglog_file_label">קובץ לוג מוקלט</string>
|
||||
<string name="debug_debuglog_record_action">הקלט יומן ניפוי באגים</string>
|
||||
<string name="settings_support_installid_label">מזהה התקנה</string>
|
||||
<string name="settings_support_installid_desc">דוחות שגיאה אוטומטיים הם אנונימיים. שתף את מזהה ההתקנה שלך אם המפתח צריך למצוא את דוחות השגיאות שלך.</string>
|
||||
<string name="settings_support_label">תמיכה</string>
|
||||
|
||||
@@ -48,8 +48,6 @@
|
||||
<string name="debug_debuglog_size_label">サイズ</string>
|
||||
<string name="debug_debuglog_size_compressed_label">圧縮サイズ</string>
|
||||
<string name="debug_notification_channel_label">デバッグ通知</string>
|
||||
<string name="debug_debuglog_file_label">記録されたログファイル</string>
|
||||
<string name="debug_debuglog_record_action">デバッグログを記録する</string>
|
||||
<string name="settings_support_installid_label">インストールID</string>
|
||||
<string name="settings_support_installid_desc">自動エラーレポートは匿名です。開発者があなたのエラーレポートを見つける必要がある場合は、インストールIDを共有してください。</string>
|
||||
<string name="settings_support_label">サポート</string>
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
<string name="debug_debuglog_size_label">크기</string>
|
||||
<string name="debug_debuglog_size_compressed_label">압축된 크기</string>
|
||||
<string name="debug_notification_channel_label">디버그 알림</string>
|
||||
<string name="debug_debuglog_file_label">기록된 로그 파일</string>
|
||||
<string name="debug_debuglog_record_action">기록된 디버그 로그</string>
|
||||
<string name="settings_support_installid_label">설치 ID</string>
|
||||
<string name="settings_support_installid_desc">자동 오류 보고는 익명성이 보장됩니다. 개발자가 오류 보고서를 필요로 할 때 설치 ID를 알려주세요.</string>
|
||||
<string name="settings_support_label">지원</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Saiz</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Saiz termampat</string>
|
||||
<string name="debug_notification_channel_label">Notifikasi nyahpepijat</string>
|
||||
<string name="debug_debuglog_file_label">Fail log yang direkodkan</string>
|
||||
<string name="debug_debuglog_record_action">Rekod log nyahpepijat</string>
|
||||
<string name="settings_support_installid_label">Pasang ID</string>
|
||||
<string name="settings_support_installid_desc">Laporan ralat automatik adalah tanpa nama. Kongsi ID pemasangan anda jika pembangun perlu mencari laporan ralat anda.</string>
|
||||
<string name="settings_support_label">Sokongan</string>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<item name="colorSurfaceInverse">@color/md_theme_dark_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_dark_primaryInverse</item>
|
||||
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item tools:targetApi="29" name="android:enforceNavigationBarContrast">true</item>
|
||||
<item tools:targetApi="29" name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Grootte</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Gecomprimeerde grootte</string>
|
||||
<string name="debug_notification_channel_label">Foutopsporingsmeldingen</string>
|
||||
<string name="debug_debuglog_file_label">Opgenomen logbestand</string>
|
||||
<string name="debug_debuglog_record_action">Foutopsporingslogboek opnemen</string>
|
||||
<string name="settings_support_installid_label">Installatie-ID</string>
|
||||
<string name="settings_support_installid_desc">Automatische foutmeldingen zijn anoniem. Deel uw installatie-ID als de ontwikkelaar uw foutrapporten moet vinden.</string>
|
||||
<string name="settings_support_label">Ondersteuning</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Størrelse</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Komprimert størrelse</string>
|
||||
<string name="debug_notification_channel_label">Feilsøkingsvarslinger</string>
|
||||
<string name="debug_debuglog_file_label">Registrert loggfil</string>
|
||||
<string name="debug_debuglog_record_action">Registrer feilsøkingslogg</string>
|
||||
<string name="settings_support_installid_label">Installasjons-ID</string>
|
||||
<string name="settings_support_installid_desc">Automatiske feilrapporter er anonyme. Del installasjons-ID-en din hvis utvikleren skal finne feilrapportene dine.</string>
|
||||
<string name="settings_support_label">Brukerstøtte</string>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<string name="settings_maindevice_model_description">Model twojego głównego urządzenia. Pomaga aplikacji rozpoznać twoje urządzenie, gdy nie jest połączone z telefonem.</string>
|
||||
<string name="settings_onepod_mode_label">Tryb jednego pod\'a</string>
|
||||
<string name="settings_onepod_mode_description">Noszenie obu pod\'ów nie jest wymagane. Wystarczy jeden, aby aktywować reakcje.</string>
|
||||
<string name="settings_popup_caseopen_label">Wyświetl okienko przybornika</string>
|
||||
<string name="settings_popup_caseopen_label">Wyświetl okienko obudowy</string>
|
||||
<string name="settings_popup_caseopen_description">Wyświetla informację, gdy obudowa urządzenia jest otwarta (eksperymentalnie).</string>
|
||||
<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>
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Rozmiar</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Rozmiar skompresowanego</string>
|
||||
<string name="debug_notification_channel_label">Powiadomienia debugowania</string>
|
||||
<string name="debug_debuglog_file_label">Nagrany plik logowania</string>
|
||||
<string name="debug_debuglog_record_action">Nagraj plik logowania</string>
|
||||
<string name="settings_support_installid_label">ID instalacji</string>
|
||||
<string name="settings_support_installid_desc">Automatyczne raporty błędów są anonimowe. Udostępni swoje ID instalacji, aby autor mógł znaleźć twój raport błędu.</string>
|
||||
<string name="settings_support_label">Wsparcie</string>
|
||||
@@ -89,7 +87,7 @@
|
||||
<string name="settings_compat_indirectcallback_summary">Użyj alternatywnej metody odbierania danych BLE z systemu (transmisja zamiast połączenia zwrotnego).</string>
|
||||
<string name="troubleshooter_title">Rozwiązywanie problemów</string>
|
||||
<string name="troubleshooter_ble_intro_title">Transmisja Bluetooth Low Energy</string>
|
||||
<string name="troubleshooter_ble_intro_body1">AirPods (i podobne słuchawki) transmitują informacje o stanie za pomocą technologii BLE zwanej „reklamami”. Niektóre telefony nie obsługują tej technologii poprawnie. CAPod może spróbować to naprawić, wypróbowując różne opcje zgodności, dopóki dane nie zostaną odebrane. Rozpocznij odtwarzanie muzyki na słuchawkach i umieść je blisko telefonu, a następnie rozpocznij proces.</string>
|
||||
<string name="troubleshooter_ble_intro_body1">AirPods (i podobne słuchawki) transmitują informacje o stanie za pomocą technologii BLE zwanej „reklamami”. Niektóre telefony nie obsługują tej technologii poprawnie. CAPod może spróbować to naprawić, testując różne opcje zgodności, dopóki dane nie zostaną odebrane. Rozpocznij odtwarzanie muzyki na słuchawkach i umieść je blisko telefonu, a następnie rozpocznij proces.</string>
|
||||
<string name="troubleshooter_ble_intro_start_action">Rozpocznij rozwiązywanie problemów</string>
|
||||
<string name="troubleshooter_ble_process_title">Rozwiązywanie problemów w toku</string>
|
||||
<string name="troubleshooter_ble_process_subtile">Każdy etap zajmuje 5–10 sekund</string>
|
||||
@@ -97,8 +95,8 @@
|
||||
<string name="troubleshooter_ble_result_success_body">Audycje reklamowe BLE są odbierane przez CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Niepowodzenie</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">Rozwiązywanie problemów nie powiodło się. Nie pomogła żadna kombinacja opcji kompatybilności.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Twój telefon nie odebrał żadnych danych BLE. Możesz ponowić test w zatłoczonym obszarze, aby sprawdzić, czy źródła danych (inne niż twoje słuchawki) mogą być odbierane. Brak odbioru danych wskazuje na problem z systemem operacyjnym telefonu.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Twój telefon odebrał dane BLE, jednak nie pochodzą one od obsługiwanego urządzenia. Czy twoje słuchawki są włączone? Czy CAPod obsługuje twoje słuchawki?</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Twój telefon nie odebrał żadnych danych BLE. Możesz ponowić test w zatłoczonym obszarze, aby sprawdzić, czy źródła danych (inne niż Twoje słuchawki) mogą być odbierane. Brak odbioru danych wskazuje na problem z systemem operacyjnym telefonu.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Twój telefon odebrał dane BLE, jednak nie pochodzą one z obsługiwanego urządzenia. Czy Twoje słuchawki są włączone? Czy CAPod obsługuje Twoje słuchawki?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Spróbuj ponownie</string>
|
||||
<string name="troubleshoot_action">Rozwiązywanie problemów</string>
|
||||
<string name="onboarding_body1">Ta aplikacja dodaje wsparcie dla funkcji AirPods na Androidzie.</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Tamanho</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Tamanho compactado</string>
|
||||
<string name="debug_notification_channel_label">Notificações de depuração</string>
|
||||
<string name="debug_debuglog_file_label">Arquivo de registro gravado</string>
|
||||
<string name="debug_debuglog_record_action">Gravar registro de depuração</string>
|
||||
<string name="settings_support_installid_label">ID de instalação</string>
|
||||
<string name="settings_support_installid_desc">Os relatórios automáticos de erros são anônimos. Compartilhe seu ID de instalação se o desenvolvedor precisar encontrar seus relatórios de erros.</string>
|
||||
<string name="settings_support_label">Suporte</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Tamanho</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Tamanho comprimido</string>
|
||||
<string name="debug_notification_channel_label">Notificações de debug</string>
|
||||
<string name="debug_debuglog_file_label">Ficheiro de registo gravado</string>
|
||||
<string name="debug_debuglog_record_action">Gravar ficheiro de registo</string>
|
||||
<string name="settings_support_installid_label">ID de instalação</string>
|
||||
<string name="settings_support_installid_desc">Os relatórios de erros automáticos são anónimos. Compartilhe o seu ID de instalação se o programador precisar encontrar os seus relatórios de erro.</string>
|
||||
<string name="settings_support_label">Suporte</string>
|
||||
|
||||
@@ -1,2 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"></resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="general_share_action">Distribuie</string>
|
||||
<string name="general_done_action">Efectuat</string>
|
||||
<string name="general_copy_action">Copiază</string>
|
||||
<string name="general_thank_you_label">Mulțumesc</string>
|
||||
<string name="general_upgrade_action">Actualizare</string>
|
||||
<string name="general_check_action">Verifică</string>
|
||||
<string name="general_close_action">Închide</string>
|
||||
<string name="upgrade_capod_label">Actualizați CaPod</string>
|
||||
<string name="upgrade_capod_description">Obțineți funcții suplimentare și sprijiniți dezvoltatorul.</string>
|
||||
<string name="settings_monitor_mode_label">Modul monitorizare</string>
|
||||
<string name="settings_monitor_mode_description">În ce circumstanțe această aplicație monitorizează datele Bluetooth.</string>
|
||||
<string name="settings_scanner_mode_label">Modul scanare</string>
|
||||
<string name="settings_scanner_mode_description">Scanerul de date Bluetooth Energie Scăzută (BLE) ar trebui să prioritizeze performanța sau să economisească energia?</string>
|
||||
<string name="settings_autopause_label">Pauză automată</string>
|
||||
<string name="settings_autopause_description">Întrerupeți sunetul când scoateți dispozitivul din ureche.</string>
|
||||
<string name="settings_showall_label">Arată toate dispozitivele</string>
|
||||
<string name="settings_showall_description">Afișați dispozitivele altor persoane care sunt în apropierea dvs.</string>
|
||||
<string name="settings_autopplay_label">Redare automată</string>
|
||||
<string name="settings_autoplay_description">Porniți redarea audio când dispozitivul este purtat.</string>
|
||||
<string name="settings_fake_data_label">Date false</string>
|
||||
<string name="settings_fake_data_description">Afișați date false, ex: simulați dispozitive care nu există.</string>
|
||||
<string name="settings_debug_label">Setări de depanare</string>
|
||||
<string name="settings_debug_description">Setări suplimentare pentru a ajuta la depanarea problemelor cu aplicația.</string>
|
||||
<string name="settings_signal_minimum_label">Calitatea minimă a semnalului</string>
|
||||
<string name="settings_signal_minimum_description">Calitatea minimă a semnalului pe care trebuie să o aibă un dispozitiv trebuie să fie considerată a dvs.</string>
|
||||
<string name="settings_autoconnect_label">Conectare automată</string>
|
||||
<string name="settings_autoconnect_description">Dacă Android nu se conectează automat, îl putem întreba și noi. Aceasta va seta setarea modului monitorizare la „Întotdeauna”.</string>
|
||||
<string name="settings_autoconnect_condition_label">Condiția de conectare automată</string>
|
||||
<string name="settings_autoconnect_condition_description">Când ar trebui să încercăm să ne conectăm la dispozitivul dvs.?</string>
|
||||
<string name="settings_reaction_label">Reacții</string>
|
||||
<string name="settings_reaction_description">Reacționați la evenimente și comportamente.</string>
|
||||
<string name="settings_category_yourdevice_label">Dispozitivul tău</string>
|
||||
<string name="settings_category_compatibility_options_title">Opțiuni de compatibilitate</string>
|
||||
<string name="settings_category_compatibility_options_description">Nu atingeți dacă totul funcționează ;)</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_title">Dezactivați filtrarea hardware-ului</string>
|
||||
<string name="settings_compat_offloaded_filtering_disabled_summary">Nu delegați filtrarea datelor către sistem, în schimb, obțineți toate datele și filtrați în cadrul aplicației.</string>
|
||||
<string name="settings_compat_offloaded_batching_disabled_title">Dezactivați lotizarea hardware</string>
|
||||
<string name="settings_compat_offloaded_batching_disabled_summary">Nu lăsați sistemul să grupeze datele BLE colectate înainte de a ni le transmite.</string>
|
||||
<string name="settings_maindevice_address_label">Adresa dispozitivului dvs.</string>
|
||||
<string name="settings_maindevice_address_description">Adresa dispozitivului dvs. asociat. Aplicația utilizează aceasta pentru a determina când este conectată la telefonul dvs.</string>
|
||||
<string name="settings_maindevice_address_none">Niciunul</string>
|
||||
<string name="settings_maindevice_model_label">Modelul dispozitivului dvs.</string>
|
||||
<string name="settings_maindevice_model_description">Modelul dispozitivului principal. Acest lucru ajută aplicația să recunoască dispozitivul dvs. atunci când nu este conectat la telefonul dvs.</string>
|
||||
<string name="settings_onepod_mode_label">Modul de utilizare o singură cască</string>
|
||||
<string name="settings_onepod_mode_description">Nu este necesar să purtați ambele caști, o singură cască este suficientă pentru a declanșa reacțiile.</string>
|
||||
<string name="settings_popup_caseopen_label">Afișați pop-upul carcasei</string>
|
||||
<string name="settings_popup_caseopen_description">Afișați un pop-up când este deschisă carcasa dispozitivului (experimental).</string>
|
||||
<string name="settings_popup_connected_label">Afișați pop-upul conexiunii</string>
|
||||
<string name="settings_popup_connected_description">Afișați un pop-up când dispozitivul se conectează pentru prima dată.</string>
|
||||
<string name="notification_channel_device_status_label">Starea dispozitivului</string>
|
||||
<string name="debug_debuglog_size_label">Dimensiune</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Dimensiune comprimată</string>
|
||||
<string name="debug_notification_channel_label">Notificări de depanare</string>
|
||||
<string name="settings_support_installid_label">ID de instalare</string>
|
||||
<string name="settings_support_installid_desc">Rapoartele automate de eroare sunt anonime. Partajați ID-ul de instalare dacă dezvoltatorul trebuie să vă găsească rapoartele de eroare.</string>
|
||||
<string name="settings_support_label">Suport</string>
|
||||
<string name="settings_support_description">Dacă ai nevoie de ajutor.</string>
|
||||
<string name="issue_tracker_label">Detector de probleme</string>
|
||||
<string name="issue_tracker_description">Un instrument public de urmărire a problemelor pentru rapoartele de erori și solicitările de funcții (numai în limba engleză).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Un loc în care să stai și să pui întrebări.</string>
|
||||
<string name="changelog_label">Jurnalul modificărilor</string>
|
||||
<string name="settings_label">Setări</string>
|
||||
<string name="settings_privacy_policy_label">Politica de confidențialitate</string>
|
||||
<string name="settings_privacy_policy_desc">Responsabilitatea gestionării datelor.</string>
|
||||
<string name="settings_licenses_label">Licențe</string>
|
||||
<string name="settings_category_other_label">Altele</string>
|
||||
<string name="settings_general_label">Setări</string>
|
||||
<string name="settings_general_description">Ajustări generale care afectează întreaga aplicație.</string>
|
||||
<string name="settings_acknowledgements_label">Mulțumiri</string>
|
||||
<string name="settings_debug_autoreports_label">Rapoarte automate de erori</string>
|
||||
<string name="settings_debug_autoreports_description">Raportează automat probleme, ex: detalii despre o blocare a aplicației, astfel încât să îmi dau seama cum să o rezolv.</string>
|
||||
<string name="settings_debug_mode_label">Modul de depanare</string>
|
||||
<string name="settings_debug_mode_description">Afișați informații suplimentare pentru a remedia problemele.</string>
|
||||
<string name="settings_blescanner_unfiltered_label">Date BLE nefiltrate</string>
|
||||
<string name="settings_blescanner_unfiltered_description">Eliminați toate filtrele din scanerul BLE pentru a afișa toate datele BLE difuzate. Util pentru a adăuga suport pentru noile tipuri de căști.</string>
|
||||
<string name="settings_compatibility_mode_label">Mod de compatibilitate</string>
|
||||
<string name="settings_compatibility_mode_description">Dezactivați optimizările pentru a îmbunătăți compatibilitatea. Încercați acest lucru dacă nu vedeți nicio dată.</string>
|
||||
<string name="help_translate_label">Traducere</string>
|
||||
<string name="help_translate_description">Ajută la traducerea acestei aplicații în limba ta preferată.</string>
|
||||
<string name="translators_thanks_title">Traducători</string>
|
||||
<string name="translators_thanks_description">Darken</string>
|
||||
<string name="widget_description">Un widget care arată starea ultimului dispozitiv cunoscut.</string>
|
||||
<string name="settings_compat_indirectcallback_title">Livrarea indirectă a datelor</string>
|
||||
<string name="settings_compat_indirectcallback_summary">Utilizați o metodă alternativă pentru a primi date BLE de la sistem (difuzare în loc de apel invers).</string>
|
||||
<string name="troubleshooter_title">Depanator</string>
|
||||
<string name="troubleshooter_ble_intro_title">Transmisii Bluetooth Energie Scăzută (BLE)</string>
|
||||
<string name="troubleshooter_ble_intro_body1">AirPod-urile (și căștile similare) transmit informații despre stare folosind o tehnologie BLE numită „reclame”. Unele telefoane nu implementează corect această tehnologie. CAPod poate încerca să remedieze acest lucru încercând diferite opțiuni de compatibilitate până la primirea datelor. Porniți redarea muzicii pe căști și plasați-le aproape de telefon, apoi începeți procesul.</string>
|
||||
<string name="troubleshooter_ble_intro_start_action">Începeți depanarea</string>
|
||||
<string name="troubleshooter_ble_process_title">Depanare în progres</string>
|
||||
<string name="troubleshooter_ble_process_subtile">Fiecare pas durează 5-10 secunde</string>
|
||||
<string name="troubleshooter_ble_result_success_title">Succes</string>
|
||||
<string name="troubleshooter_ble_result_success_body">Emisiunile de reclame BLE sunt recepționate de CAPod.</string>
|
||||
<string name="troubleshooter_ble_result_failure_title">Eșuat</string>
|
||||
<string name="troubleshooter_ble_result_failure_body">Depanarea a eșuat. Nicio combinație de compatibilitate nu a ajutat.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_body">Telefonul dvs. nu a primit deloc date BLE. Puteți reîncerca acest test într-o zonă aglomerată pentru a vedea dacă sursele de date (altele decât căștile) pot fi recepționate. Nicio dată primită indică o problemă cu sistemul de operare al telefonului dvs.</string>
|
||||
<string name="troubleshooter_ble_result_failure_phone_headphones">Telefonul dvs. a primit date BLE, dar datele nu provin de la niciun dispozitiv acceptat. Căștile tale sunt pornite? CAPod vă acceptă căștile?</string>
|
||||
<string name="troubleshooter_ble_result_failure_action">Încearcă din nou</string>
|
||||
<string name="troubleshoot_action">Depanare</string>
|
||||
<string name="onboarding_body1">Această aplicație adaugă suport pentru caracteristicile specifice AirPod pentru Android.</string>
|
||||
<string name="onboarding_body2">Nu toate dispozitivele Android acceptă pe deplin funcțiile suplimentare AirPod. Sistemul dvs. de operare necesită o implementare Bluetooth Energie Scăzută (BLE) care funcționează corect.</string>
|
||||
<string name="onboarding_body3">CAPod nu are reclame și nu colectează datele dumneavoastră.</string>
|
||||
<string name="onboarding_body4">Puteți face upgrade la CAPod Pro pentru a obține funcții suplimentare și pentru a sprijini dezvoltarea.</string>
|
||||
<string name="general_continue_action">Continuă</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Размер</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Сжатый размер</string>
|
||||
<string name="debug_notification_channel_label">Уведомления отладки</string>
|
||||
<string name="debug_debuglog_file_label">Записанный файл лога</string>
|
||||
<string name="debug_debuglog_record_action">Записать лог отладки</string>
|
||||
<string name="settings_support_installid_label">ID установки</string>
|
||||
<string name="settings_support_installid_desc">Автоматические отчёты об ошибках анонимны. Поделитесь Вашим ID установки, если разработчику нужен доступ к Вашим отчётам об ошибках.</string>
|
||||
<string name="settings_support_label">Поддержка</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Veľkosť</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Komprimovaná veľkosť</string>
|
||||
<string name="debug_notification_channel_label">Oznámenia o ladení</string>
|
||||
<string name="debug_debuglog_file_label">Zaznamenaný súbor protokolu</string>
|
||||
<string name="debug_debuglog_record_action">Zaznamenať protokol ladenia</string>
|
||||
<string name="settings_support_installid_label">ID inštalácie</string>
|
||||
<string name="settings_support_installid_desc">Automatické chybové hlásenia sú anonymné. Zdieľajte svoje ID inštalácie, ak vývojár potrebuje nájsť vaše chybové hlásenia.</string>
|
||||
<string name="settings_support_label">Podpora</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Boyut</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Sıkıştırılmış boyut</string>
|
||||
<string name="debug_notification_channel_label">Hata ayıklama bildirimleri</string>
|
||||
<string name="debug_debuglog_file_label">Kayıtlı günlük dosyası</string>
|
||||
<string name="debug_debuglog_record_action">Hata ayıklama günlüğünü kaydet</string>
|
||||
<string name="settings_support_installid_label">Kurulum Kimliği</string>
|
||||
<string name="settings_support_installid_desc">Otomatik hata raporları anonimdir. Geliştiricinin hata raporlarınızı bulması gerekiyorsa kurulum kimliğinizi paylaşabilirsiniz.</string>
|
||||
<string name="settings_support_label">Destek</string>
|
||||
@@ -66,7 +64,7 @@
|
||||
<string name="changelog_label">Sürüm günlüğü</string>
|
||||
<string name="settings_label">Ayarlar</string>
|
||||
<string name="settings_privacy_policy_label">Gizlilik politikası</string>
|
||||
<string name="settings_privacy_policy_desc">Verileri sorumlu bir şekilde işler.</string>
|
||||
<string name="settings_privacy_policy_desc">Verilerinizi sorumlu bir şekilde işliyoruz.</string>
|
||||
<string name="settings_licenses_label">Lisanslar</string>
|
||||
<string name="settings_category_other_label">Diğer</string>
|
||||
<string name="settings_general_label">Ayarlar</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">Розмір</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Стиснутий розмір</string>
|
||||
<string name="debug_notification_channel_label">Повідомлення зневадження</string>
|
||||
<string name="debug_debuglog_file_label">Журнал зневадження</string>
|
||||
<string name="debug_debuglog_record_action">Зберегти журнал зневадження</string>
|
||||
<string name="settings_support_installid_label">ID інсталяції</string>
|
||||
<string name="settings_support_installid_desc">Автоматичні звіти про помилки є анонімними. Поділіться своїм ID інсталяції, якщо розробнику потрібно знайти ваші звіти про помилки.</string>
|
||||
<string name="settings_support_label">Підтримка</string>
|
||||
|
||||
@@ -47,8 +47,6 @@
|
||||
<string name="debug_debuglog_size_label">Kích thước</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Kích thước nén</string>
|
||||
<string name="debug_notification_channel_label">Thông báo gỡ lỗi</string>
|
||||
<string name="debug_debuglog_file_label">Tệp nhật ký đã ghi</string>
|
||||
<string name="debug_debuglog_record_action">Ghi nhật ký gỡ lỗi</string>
|
||||
<string name="settings_support_installid_label">ID Cài đặt</string>
|
||||
<string name="settings_support_installid_desc">Các báo cáo lỗi tự động được ẩn danh. Chia sẻ ID cài đặt của bạn nếu nhà phát triển cần tìm các báo cáo lỗi của bạn.</string>
|
||||
<string name="settings_support_label">Hỗ trợ</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">大小</string>
|
||||
<string name="debug_debuglog_size_compressed_label">压缩后大小</string>
|
||||
<string name="debug_notification_channel_label">调试通知</string>
|
||||
<string name="debug_debuglog_file_label">记录的日志文件</string>
|
||||
<string name="debug_debuglog_record_action">记录调试日志</string>
|
||||
<string name="settings_support_installid_label">安装 ID</string>
|
||||
<string name="settings_support_installid_desc">自动发送的错误报告是匿名的。如果需要,给开发者发送您的安装 ID 以便找出您的错误报告。</string>
|
||||
<string name="settings_support_label">用户支持</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">大小</string>
|
||||
<string name="debug_debuglog_size_compressed_label">壓縮後大小</string>
|
||||
<string name="debug_notification_channel_label">偵錯通知</string>
|
||||
<string name="debug_debuglog_file_label">已記錄的記錄檔</string>
|
||||
<string name="debug_debuglog_record_action">記錄偵錯記錄</string>
|
||||
<string name="settings_support_installid_label">安裝 ID</string>
|
||||
<string name="settings_support_installid_desc">自動傳送的錯誤報告是匿名的。如果開發人員需要找出您的錯誤報告將分享你的安裝 ID。</string>
|
||||
<string name="settings_support_label">支援</string>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
<string name="debug_debuglog_size_label">大小</string>
|
||||
<string name="debug_debuglog_size_compressed_label">壓縮後大小</string>
|
||||
<string name="debug_notification_channel_label">偵錯通知</string>
|
||||
<string name="debug_debuglog_file_label">已記錄的記錄檔</string>
|
||||
<string name="debug_debuglog_record_action">記錄偵錯記錄</string>
|
||||
<string name="settings_support_installid_label">安裝 ID</string>
|
||||
<string name="settings_support_installid_desc">自動傳送的錯誤報告是匿名的。如果開發人員需要找出您的錯誤報告將分享你的安裝 ID。</string>
|
||||
<string name="settings_support_label">支援</string>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="general_share_action">Share</string>
|
||||
<string name="general_done_action">Done</string>
|
||||
<string name="general_cancel_action">Cancel</string>
|
||||
<string name="general_copy_action">Copy</string>
|
||||
<string name="general_thank_you_label">Thank you</string>
|
||||
<string name="general_upgrade_action">Upgrade</string>
|
||||
@@ -53,15 +54,19 @@
|
||||
<string name="settings_popup_connected_label">Show connection popup</string>
|
||||
<string name="settings_popup_connected_description">Show a popup when the device connects for the first time.</string>
|
||||
|
||||
|
||||
<string name="notification_channel_device_status_label">Device status</string>
|
||||
|
||||
<string name="support_debuglog_label">Debug log</string>
|
||||
<string name="support_debuglog_desc">Record everything the app is doing into a text file that you can share.</string>
|
||||
<string name="debug_debuglog_size_label">Size</string>
|
||||
<string name="debug_debuglog_size_compressed_label">Compressed size</string>
|
||||
<string name="debug_notification_channel_label">Debug notifications</string>
|
||||
<string name="debug_debuglog_file_label">Recorded log file</string>
|
||||
<string name="debug_debuglog_recording_progress">Recording debug log</string>
|
||||
<string name="debug_debuglog_record_action">Record debug log</string>
|
||||
|
||||
<string name="debug_debuglog_stop_action">Stop recording</string>
|
||||
<string name="debug_debuglog_sensitive_information_message">The generated file contains sensitive information (e.g. Bluetooth device details). Only share it with trusted parties.</string>
|
||||
<string name="settings_debuglog_explanation">This feature records everything the app is doing into a shareable file. The generated file contains sensitive information (e.g. Bluetooth device details). Only share it with trusted parties (e.g. a developer that is troubleshooting an issue).</string>
|
||||
|
||||
<string name="settings_support_installid_label">Install ID</string>
|
||||
<string name="settings_support_installid_desc">Automatic error reports are anonymous. Share your install ID if the developer needs to find your error reports.</string>
|
||||
@@ -122,7 +127,7 @@
|
||||
|
||||
|
||||
<string name="onboarding_body1">This app adds support for AirPod specific features to Android.</string>
|
||||
<string name="onboarding_body2">Not all Android devices fully support the extra AirPod features. Your operating system requires a correctly working Bluetooth-Low-Energy implemtation.</string>
|
||||
<string name="onboarding_body2">Not all Android devices fully support the extra AirPod features. Your operating system requires a correctly working Bluetooth-Low-Energy implementation.</string>
|
||||
<string name="onboarding_body3">CAPod has no ads and does not collect your data.</string>
|
||||
<string name="onboarding_body4">You can upgrade to CAPod Pro to gain extra features and support development.</string>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="MyCardView" parent="Widget.MaterialComponents.CardView">
|
||||
<style name="MyCardView" parent="Widget.Material3.CardView.Outlined">
|
||||
<item name="android:layout_marginTop">8dp</item>
|
||||
<item name="android:layout_marginStart">8dp</item>
|
||||
<item name="android:layout_marginEnd">8dp</item>
|
||||
@@ -24,13 +24,18 @@
|
||||
<item name="tint">?android:attr/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemIcon.Notification.Large" parent="PodInfoItemIcon.Notification">
|
||||
<item name="android:layout_height">40dp</item>
|
||||
<item name="android:layout_width">40dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemText.Notification" parent="TextAppearance.Compat.Notification.Title">
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemIcon" parent="TextAppearance.MaterialComponents.Body2">
|
||||
<style name="PodInfoItemIcon" parent="TextAppearance.Material3.BodyMedium">
|
||||
<item name="android:layout_height">20dp</item>
|
||||
<item name="android:layout_width">20dp</item>
|
||||
<item name="android:tintMode">multiply</item>
|
||||
@@ -43,7 +48,7 @@
|
||||
<item name="android:layout_width">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PodInfoItemText" parent="TextAppearance.MaterialComponents.Body2">
|
||||
<style name="PodInfoItemText" parent="TextAppearance.Material3.BodyMedium">
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">end</item>
|
||||
</style>
|
||||
@@ -72,4 +77,4 @@
|
||||
<style name="PodWidget.TextSecondary">
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
</style>
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
<item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item>
|
||||
<item name="colorPrimaryInverse">@color/md_theme_light_primaryInverse</item>
|
||||
|
||||
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item tools:targetApi="29" name="android:enforceNavigationBarContrast">true</item>
|
||||
<item tools:targetApi="29" name="android:navigationBarColor">@android:color/transparent</item>
|
||||
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://github.com/adolfintel/OpenPods" />
|
||||
</eu.darken.capod.common.preferences.IntentPreference>
|
||||
<eu.darken.capod.common.preferences.IntentPreference
|
||||
android:key="thanks.magicpods"
|
||||
android:summary="Pioneering AirPod support on Windows"
|
||||
android:title="MagicPods project"
|
||||
app:iconSpaceReserved="false">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://github.com/steam3d/MagicPods-Windows" />
|
||||
</eu.darken.capod.common.preferences.IntentPreference>
|
||||
<eu.darken.capod.common.preferences.IntentPreference
|
||||
android:key="thanks.furiousmac"
|
||||
android:summary="Research on the continuity protocol"
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_baseline_text_snippet_24"
|
||||
android:key="debug.log.record"
|
||||
android:title="@string/debug_debuglog_record_action" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_bug_report_24"
|
||||
android:key="debug.mode.enabled"
|
||||
android:summary="@string/settings_debug_mode_description"
|
||||
android:title="@string/settings_debug_mode_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_data_array_24"
|
||||
android:key="debug.fakedata.enabled"
|
||||
android:summary="@string/settings_fake_data_description"
|
||||
android:title="@string/settings_fake_data_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_devices_other_24"
|
||||
android:key="debug.blescanner.unfiltered.enabled"
|
||||
android:summary="@string/settings_blescanner_unfiltered_description"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
android:summary="@string/settings_scanner_mode_description"
|
||||
android:title="@string/settings_scanner_mode_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_devices_other_24"
|
||||
android:key="core.showall.enabled"
|
||||
android:summary="@string/settings_showall_description"
|
||||
@@ -49,19 +49,19 @@
|
||||
android:title="@string/settings_category_compatibility_options_title"
|
||||
app:icon="@drawable/ic_chip_24">
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_filter_cog_outline_24"
|
||||
android:key="core.compat.offloaded.filtering.disabled"
|
||||
android:summary="@string/settings_compat_offloaded_filtering_disabled_summary"
|
||||
android:title="@string/settings_compat_offloaded_filtering_disabled_title" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_format_list_group_24"
|
||||
android:key="core.compat.offloaded.batching.disabled"
|
||||
android:summary="@string/settings_compat_offloaded_batching_disabled_summary"
|
||||
android:title="@string/settings_compat_offloaded_batching_disabled_title" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_strategy_24"
|
||||
android:key="core.compat.indirectcallback.enabled"
|
||||
android:summary="@string/settings_compat_indirectcallback_summary"
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_looks_one_24"
|
||||
android:key="reaction.onepod.enabled"
|
||||
android:summary="@string/settings_onepod_mode_description"
|
||||
android:title="@string/settings_onepod_mode_label" />
|
||||
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_play_circle_24"
|
||||
android:key="reaction.autoplay.enabled"
|
||||
android:summary="@string/settings_autoplay_description"
|
||||
android:title="@string/settings_autopplay_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_pause_circle_24"
|
||||
android:key="reaction.autopause.enabled"
|
||||
android:summary="@string/settings_autopause_description"
|
||||
android:title="@string/settings_autopause_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_baseline_bluetooth_connected_24"
|
||||
android:key="reaction.autoconnect.enabled"
|
||||
android:summary="@string/settings_autoconnect_description"
|
||||
@@ -32,13 +32,13 @@
|
||||
android:summary="@string/settings_autoconnect_condition_description"
|
||||
android:title="@string/settings_autoconnect_condition_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_message_outline_24"
|
||||
android:key="reaction.popup.caseopen"
|
||||
android:summary="@string/settings_popup_caseopen_description"
|
||||
android:title="@string/settings_popup_caseopen_label" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<eu.darken.capod.common.preferences.MaterialSwitchPreference
|
||||
android:icon="@drawable/ic_message_24"
|
||||
android:key="reaction.popup.connected"
|
||||
android:summary="@string/settings_popup_connected_description"
|
||||
|
||||
@@ -20,17 +20,9 @@
|
||||
|
||||
<PreferenceCategory app:title="@string/settings_category_other_label">
|
||||
<Preference
|
||||
android:icon="@drawable/ic_id_onsurface"
|
||||
android:key="support.installid"
|
||||
android:summary="@string/settings_support_installid_desc"
|
||||
android:title="@string/settings_support_installid_label"
|
||||
app:isPreferenceVisible="false" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:icon="@drawable/ic_spider_thread_onsurface"
|
||||
android:key="debug.bugreport.automatic.enabled"
|
||||
app:isPreferenceVisible="false"
|
||||
android:summary="@string/settings_debug_autoreports_description"
|
||||
android:title="@string/settings_debug_autoreports_label" />
|
||||
android:icon="@drawable/ic_baseline_bug_report_24"
|
||||
android:key="support.debuglog"
|
||||
android:summary="@string/support_debuglog_desc"
|
||||
android:title="@string/support_debuglog_label" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
||||
+1
-1
@@ -20,4 +20,4 @@ allprojects {
|
||||
|
||||
tasks.register("clean").configure {
|
||||
delete("build")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ dependencies {
|
||||
implementation("com.android.tools.build:gradle:8.1.2")
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
|
||||
implementation("com.squareup:javapoet:1.13.0")
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user