mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Compare commits
17
Commits
v2.1.0-rc0
...
v2.2.1-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63f37e51ad | ||
|
|
01ea08a5cb | ||
|
|
bddb20c5bb | ||
|
|
f9a97297da | ||
|
|
5fc2b56635 | ||
|
|
172953ccb3 | ||
|
|
d55300f53d | ||
|
|
c3d4500e3a | ||
|
|
cf72e28727 | ||
|
|
b488a1be16 | ||
|
|
805d0cb4b6 | ||
|
|
fa045c2504 | ||
|
|
23fd373a9b | ||
|
|
ab619cb073 | ||
|
|
2d96822014 | ||
|
|
887adc87de | ||
|
|
4219bd02c5 |
@@ -24,7 +24,8 @@ Currently supported models:
|
||||
* AirPods 1. Generation
|
||||
* AirPods 2. Generation
|
||||
* AirPods 3. Generation
|
||||
* AirPods Pro
|
||||
* AirPods Pro 1. Generation
|
||||
* AirPods Pro 2. Generation
|
||||
* AirPods Max
|
||||
* Power Beats Pro
|
||||
* Power Beats 3
|
||||
|
||||
@@ -35,7 +35,7 @@ class BleScanner @Inject constructor(
|
||||
log(TAG, VERBOSE) { "scan(filters=$filters, scannerMode=$scannerMode, compatMode=$compatMode)" }
|
||||
if (compatMode) log(TAG, WARN) { "Using compatibilityMode!" }
|
||||
|
||||
val adapter = bluetoothManager.adapter
|
||||
val adapter = bluetoothManager.adapter ?: throw IllegalStateException("Bluetooth adapter unavailable")
|
||||
|
||||
val supportsOffloadFiltering = adapter.isOffloadedFilteringSupported.also {
|
||||
log(TAG, if (it) DEBUG else WARN) { "isOffloadedFilteringSupported=$it" }
|
||||
@@ -45,7 +45,7 @@ class BleScanner @Inject constructor(
|
||||
log(TAG, if (it) DEBUG else WARN) { "isOffloadedScanBatchingSupported=$it" }
|
||||
} && !compatMode
|
||||
|
||||
val scanner = bluetoothManager.scanner
|
||||
val scanner = bluetoothManager.scanner ?: throw IllegalStateException("BLE scanner unavailable")
|
||||
|
||||
val callback = object : ScanCallback() {
|
||||
var lastScanAt = System.currentTimeMillis()
|
||||
|
||||
@@ -30,12 +30,11 @@ class BluetoothManager2 @Inject constructor(
|
||||
private val dispatcherProvider: DispatcherProvider,
|
||||
) {
|
||||
|
||||
val adapter: BluetoothAdapter
|
||||
val adapter: BluetoothAdapter?
|
||||
get() = manager.adapter
|
||||
|
||||
val scanner: BluetoothLeScanner
|
||||
get() = adapter.bluetoothLeScanner
|
||||
?: throw IllegalStateException("Bluetooth is disabled or permissiong missing")
|
||||
val scanner: BluetoothLeScanner?
|
||||
get() = adapter?.bluetoothLeScanner
|
||||
|
||||
val isBluetoothEnabled: Flow<Boolean> = callbackFlow {
|
||||
send(manager.adapter?.isEnabled ?: false)
|
||||
@@ -158,7 +157,9 @@ class BluetoothManager2 @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun bondedDevices(): Set<BluetoothDevice> = adapter.bondedDevices
|
||||
fun bondedDevices(): Flow<Set<BluetoothDevice>> = flow {
|
||||
emit(adapter?.bondedDevices ?: throw IllegalStateException("Bluetooth adapter unavailable"))
|
||||
}
|
||||
|
||||
suspend fun nudgeConnection(device: BluetoothDevice): Boolean = getBluetoothProfile().map { bluetoothProfile ->
|
||||
try {
|
||||
|
||||
@@ -71,7 +71,13 @@ enum class Permission(
|
||||
isGranted = {
|
||||
android.provider.Settings.canDrawOverlays(it)
|
||||
},
|
||||
)
|
||||
),
|
||||
POST_NOTIFICATIONS(
|
||||
minApiLevel = Build.VERSION_CODES.S,
|
||||
labelRes = R.string.permission_post_notifications_label,
|
||||
descriptionRes = R.string.permission_post_notifications_description,
|
||||
permissionId = "android.permission.POST_NOTIFICATIONS",
|
||||
),
|
||||
}
|
||||
|
||||
fun Permission.isRequired(context: Context): Boolean = when {
|
||||
|
||||
@@ -78,6 +78,10 @@ interface PodDevice {
|
||||
"AirPods Pro",
|
||||
R.drawable.ic_device_airpods_gen2
|
||||
),
|
||||
@Json(name = "airpods.pro2") AIRPODS_PRO2(
|
||||
"AirPods Pro 2",
|
||||
R.drawable.ic_device_airpods_gen2
|
||||
),
|
||||
@Json(name = "airpods.max") AIRPODS_MAX(
|
||||
"AirPods Max",
|
||||
R.drawable.ic_device_generic_headphones
|
||||
|
||||
@@ -19,6 +19,7 @@ abstract class AppleFactoryModule {
|
||||
@Binds @IntoSet abstract fun airPodsGen3(factory: AirPodsGen3.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>
|
||||
@Binds @IntoSet abstract fun airPodsMax(factory: AirPodsMax.Factory): ApplePodsFactory<out ApplePods>
|
||||
|
||||
@Binds @IntoSet abstract fun beatsFlex(factory: BeatsFlex.Factory): ApplePodsFactory<out ApplePods>
|
||||
|
||||
@@ -83,7 +83,7 @@ abstract class ApplePodsFactory<PodType : ApplePods>(private val tag: String) {
|
||||
if (definitive.contains(basic.caseLidState)) return null
|
||||
|
||||
return history
|
||||
.filterIsInstance<AirPodsPro>()
|
||||
.filterIsInstance<AirPodsPro>() // TODO why is this AirPodsPro specific here?
|
||||
.lastOrNull { it.caseLidState != DualAirPods.LidState.NOT_IN_CASE }
|
||||
?.caseLidState
|
||||
}
|
||||
|
||||
@@ -62,9 +62,10 @@ data class AirPodsPro(
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEVICE_CODE = 0x0e20.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Pro", "Factory")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEVICE_CODE = 0x0e20.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Pro")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
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.DualAirPods
|
||||
import eu.darken.capod.pods.core.apple.DualAirPods.LidState
|
||||
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 AirPodsPro2(
|
||||
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 confidence: Float = PodDevice.BASE_CONFIDENCE,
|
||||
private val rssiAverage: Int? = null,
|
||||
private val cachedBatteryPercentage: Float? = null,
|
||||
private val cachedCaseState: LidState? = null
|
||||
) : DualAirPods {
|
||||
|
||||
override val model: PodDevice.Model = PodDevice.Model.AIRPODS_PRO2
|
||||
|
||||
override val batteryCasePercent: Float?
|
||||
get() = super.batteryCasePercent ?: cachedBatteryPercentage
|
||||
|
||||
override val caseLidState: LidState
|
||||
get() = cachedCaseState ?: super.caseLidState
|
||||
|
||||
override val rssi: Int
|
||||
get() = rssiAverage ?: super.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 = AirPodsPro2(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,
|
||||
confidence = result.confidence,
|
||||
cachedBatteryPercentage = result.getLatestCaseBattery(),
|
||||
rssiAverage = result.averageRssi(basic.rssi),
|
||||
cachedCaseState = result.getLatestCaseLidState(basic)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEVICE_CODE = 0x1420.toUShort()
|
||||
private val TAG = logTag("PodDevice", "Apple", "AirPods", "Pro2")
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,8 @@ class AutoConnect @Inject constructor(
|
||||
return@map
|
||||
}
|
||||
|
||||
val bondedDevice = bluetoothManager.bondedDevices().firstOrNull { it.address == mainDeviceAddr }
|
||||
val bondedDevice = bluetoothManager.bondedDevices().first().firstOrNull { it.address == mainDeviceAddr }
|
||||
|
||||
if (bondedDevice == null) {
|
||||
log(TAG, WARN) { "No bonded device matches $mainDeviceAddr" }
|
||||
return@map
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">Н/д</string>
|
||||
<string name="general_error_label">Памылка</string>
|
||||
<string name="general_grant_permission_action">Даць дазвол</string>
|
||||
@@ -11,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Гэтай праграме патрабуецца дазвол на выкарыстанне Bluetooth для ўзаемадзеяння са спалучанымі прыладамі і стварэння новых злучэнняў.</string>
|
||||
<string name="permission_bluetooth_scan_label">Сканіраванне Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Дазвол на сканіраванне Bluetooth дасць магчымасць гэтай праграме выяўляць і атрымліваць даныя па Bluetooth з навакольных прылад, такіх як вашы AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Гэтай праграме патрабуецца дазвол на выкарыстанне Bluetooth для злучэння са спалучанымі прыладамі.</string>
|
||||
<string name="permission_access_fine_location_label">Доступ да дакладнага месцазнаходжання</string>
|
||||
<string name="permission_access_fine_location_description">CAPod выкарыстоўвае дазвол \"Дакладнае месцазнаходжанне\" для атрымання даных Bluetooth Low Energy. Вашы навушнікі з дапамогай тэхналогіі Bluetooth Low Energy перадаюць інфармацыю пра свой стан. Гэта праграма НЕ будзе карыстацца данымі Bluetooth для вызначэння вашага месцазнаходжання.</string>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">Chyba</string>
|
||||
<string name="general_grant_permission_action">Udělit oprávnění</string>
|
||||
<string name="overview_nomaindevice_label">Žádné hlavní zařízení</string>
|
||||
@@ -10,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Tato aplikace vyžaduje oprávnění „připojení Bluetooth“ pro interakci se spárovanými zařízeními a zahájení připojení.</string>
|
||||
<string name="permission_bluetooth_scan_label">Skenování Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Oprávnění „Skenování Bluetooth“ umožňuje této aplikaci zjišťovat a přijímat data z okolních Bluetooth zařízení, jako jsou například sluchátka AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Tato aplikace vyžaduje oprávněni k „Bluetooth“ pro připojení ke spárovaným zařízením Bluetooth.</string>
|
||||
<string name="permission_access_fine_location_label">Přístup k přesné poloze</string>
|
||||
<string name="permission_access_fine_location_description">CAPod používá pro příjem dat Bluetooth Low Energy oprávnění k „přesné poloze“. Sluchátka používají k vysílání svého stavu technologii Bluetooth Low Energy. Tato aplikace NEPOUŽÍVÁ data Bluetooth k určování vaší polohy.</string>
|
||||
@@ -19,7 +24,7 @@
|
||||
<string name="permission_ignore_battery_optimizations_description">Optimalizace baterie zabraňuje této aplikaci spolehlivě přijímat data Bluetooth, pokud běží na pozadí.</string>
|
||||
<string name="permission_required_title">Je vyžadováno následující oprávnění:</string>
|
||||
<string name="permission_system_alert_window_label">Okno systémových upozornění</string>
|
||||
<string name="permission_system_alert_window_description">Aby bylo možné použít unkci „Zobrazit vyskakovací okno“, je nutné umožnot aplikaci CAPod vykreslení přes jiné aplikace.</string>
|
||||
<string name="permission_system_alert_window_description">Aby bylo možné použít unkci „Zobrazit vyskakovací okno“, je nutné umožnit aplikaci CAPod vykreslení přes jiné aplikace.</string>
|
||||
<string name="settings_scanner_mode_lowpower_label">Nízký výkon</string>
|
||||
<string name="settings_scanner_mode_balanced_label">Vyvážený</string>
|
||||
<string name="settings_scanner_mode_lowlatency_label">Nízká latence</string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">k.A.</string>
|
||||
<string name="general_error_label">Fehler</string>
|
||||
<string name="general_grant_permission_action">Berechtigung erteilen</string>
|
||||
@@ -11,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Diese App benötigt die \"Bluetooth verbinden\" Berechtigung um mit bereits verbundenen und neuen Geräten zu interagieren.</string>
|
||||
<string name="permission_bluetooth_scan_label">Bluetooth Suche</string>
|
||||
<string name="permission_bluetooth_scan_description">Die \"Bluetooth verbinden\" Berechtigung erlaubt dieser App Bluetooth Daten von Geräten wie AirPods zu finden und zu erhalten.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Diese App benötigt die \"Bluetooth\" Berechtigung um sich mit gekoppelten Geräten zu verbinden.</string>
|
||||
<string name="permission_access_fine_location_label">Auf genauen Standort zugreifen</string>
|
||||
<string name="permission_access_fine_location_description">CAPod benutzt die \"genauen Gerätestandort verwenden\" Berechtigung um Bluetooth Low Energy Daten zu erhalten. Ihre Kopfhörer nutzen Bluetooth Low Energy um ihren Batterie Status zu übertragen. Diese App greift nicht auf ihren Standort zu.</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Αυτή η εφαρμογή απαιτεί την άδεια \"Σύνδεση Bluetooth\" για να αλληλεπιδρά με αντιστοιχισμένες συσκευές και να ξεκινά συνδέσεις.</string>
|
||||
<string name="permission_bluetooth_scan_label">Σάρωση Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Η άδεια \"Σάρωση Bluetooth\" επιτρέπει σε αυτήν την εφαρμογή να εντοπίζει και να λαμβάνει δεδομένα Bluetooth από κοντινές συσκευές, όπως τα AirPods σας.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Αυτή η εφαρμογή απαιτεί την άδεια \"Bluetooth\" για να συνδέεται σε αντιστοιχισμένες συσκευές Bluetooth.</string>
|
||||
<string name="permission_access_fine_location_label">Πρόσβαση ακριβούς τοποθεσίας</string>
|
||||
<string name="permission_access_fine_location_description">Το CAPod χρησιμοποιεί την άδεια \"Ακριβής τοποθεσία\" για να λαμβάνει δεδομένα χαμηλής ενέργειας Bluetooth. Τα ακουστικά σας χρησιμοποιούν τεχνολογία χαμηλής ενέργειας Bluetooth για να μεταδίδουν την κατάστασή τους. Αυτή η εφαρμογή ΔΕΝ θα χρησιμοποιεί δεδομένα Bluetooth για να προσδιορίσει την τοποθεσία σας.</string>
|
||||
|
||||
@@ -1,2 +1,10 @@
|
||||
<?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/D</string>
|
||||
<string name="general_error_label">Error</string>
|
||||
<string name="general_grant_permission_action">Conceder permiso</string>
|
||||
<string name="overview_nomaindevice_label">Ningún dispositivo principal</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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 (libre)</string>
|
||||
<string name="general_value_not_available_label">Non disponible</string>
|
||||
<string name="general_error_label">Erreur</string>
|
||||
<string name="general_grant_permission_action">Accorder l’autorisation</string>
|
||||
@@ -11,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Cette appli exige l’autorisation « Connexion Bluetooth » pour interagir avec les appareils jumelés et démarrer les connexions.</string>
|
||||
<string name="permission_bluetooth_scan_label">Analyse Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">L’autorisation « Analyse Bluetooth » permet à l’appli de découvrir et de réceptionner les données Bluetooth des appareils à proximité tels que vos AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Cette appli exige l’autorisation « Bluetooth » pour se connecter aux appareils Bluetooth jumelés.</string>
|
||||
<string name="permission_access_fine_location_label">Accéder à la position précise</string>
|
||||
<string name="permission_access_fine_location_description">CAPod utilise l’autorisation « position précise » pour recevoir les données « faible énergie » de Bluetooth. Votre casque-micro utilise la technologie « basse énergie » de Bluetooth pour diffuser son état. Cette appli n’utilisera PAS les données Bluetooth pour déterminer votre position.</string>
|
||||
@@ -48,6 +52,7 @@
|
||||
<string name="pods_none_label_short">Aucun appareil</string>
|
||||
<string name="pods_charging_label">En charge</string>
|
||||
<string name="pods_inear_label">Dans l’oreille</string>
|
||||
<string name="pods_microphone_label">Microphone</string>
|
||||
<string name="pods_yours">Les vôtres</string>
|
||||
<string name="headset_being_worn_label">Porté</string>
|
||||
<string name="pods_case_unknown_state">État inconnu</string>
|
||||
|
||||
@@ -1,4 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="app_name">कैपोड</string>
|
||||
<string name="app_name_pro">कैपोड प्रो</string>
|
||||
<string name="app_name_foss">कैपोड फोस</string>
|
||||
<string name="general_value_not_available_label">एन/ए</string>
|
||||
<string name="general_error_label">त्रुटि</string>
|
||||
<string name="general_grant_permission_action">अनुदान अनुमति</string>
|
||||
<string name="overview_nomaindevice_label">कोई प्राथमिक उपकरण नहीं</string>
|
||||
<string name="overview_nomaindevice_description">सभी खोजे गए डिवाइस आपके होने की संभावना नहीं है। अपने डिवाइस को चालू करें और कनेक्ट करें या सेटिंग समायोजित करें</string>
|
||||
<string name="overview_bluetooth_disabled_label">ब्लूटूथ अक्षम है</string>
|
||||
<string name="overview_bluetooth_disabled_description">ब्लूटूथ अक्षम है, इसे सक्षम करें;)</string>
|
||||
<string name="permission_bluetooth_connect_label">ब्लूटूथ कनेक्ट</string>
|
||||
<string name="permission_bluetooth_connect_description">इस ऐप को युग्मित उपकरणों के साथ बातचीत करने और कनेक्शन शुरू करने के लिए \"ब्लूटूथ कनेक्ट\" अनुमति की आवश्यकता है।</string>
|
||||
<string name="permission_bluetooth_scan_label">ब्लूटूथ स्कैनिंग</string>
|
||||
<string name="permission_bluetooth_scan_description">\"ब्लूटूथ स्कैनिंग\" अनुमति इस ऐप को आपके AirPods जैसे आस-पास के उपकरणों से ब्लूटूथ डेटा खोजने और प्राप्त करने की अनुमति देती है।</string>
|
||||
<string name="permission_bluetooth_label">ब्लूटूथ</string>
|
||||
<string name="permission_bluetooth_description">इस ऐप को युग्मित ब्लूटूथ डिवाइस से कनेक्ट करने के लिए \"ब्लूटूथ\" अनुमति की आवश्यकता है।</string>
|
||||
<string name="permission_access_fine_location_label">बढ़िया स्थान पर पहुंचें</string>
|
||||
<string name="permission_access_fine_location_description">CAPod ब्लूटूथ कम ऊर्जा डेटा प्राप्त करने के लिए \"ठीक स्थान\" अनुमति का उपयोग करता है। आपके हेडफ़ोन अपनी स्थिति प्रसारित करने के लिए ब्लूटूथ लो एनर्जी तकनीक का उपयोग करते हैं। यह ऐप ब्लूटूथ डेटा का उपयोग डी . के लिए नहीं करेगा</string>
|
||||
<string name="permission_background_location_label">पृष्ठभूमि स्थान पहुंच</string>
|
||||
<string name="permission_background_location_description">ऐप बंद होने पर \"शो पॉपअप\" और \"ऑटोकनेक्ट\" जैसी सुविधाओं को सक्षम करने के लिए कैपोड \"पृष्ठभूमि स्थान पहुंच\" का उपयोग करता है। बैकग्राउंड लोकेशन एक्सेस ऐप को ब्लूटूथ लो एनर्जी डेटा w . प्राप्त करने की अनुमति देता है</string>
|
||||
<string name="permission_ignore_battery_optimizations_label">बैटरी अनुकूलन अक्षम करें</string>
|
||||
<string name="permission_ignore_battery_optimizations_description">बैटरी ऑप्टिमाइज़ेशन इस ऐप को बैकग्राउंड में होने पर ब्लूटूथ डेटा को मज़बूती से प्राप्त करने से रोकता है।</string>
|
||||
<string name="permission_required_title">निम्नलिखित अनुमति की आवश्यकता है:</string>
|
||||
<string name="permission_system_alert_window_label">सिस्टम अलर्ट विंडो</string>
|
||||
<string name="permission_system_alert_window_description">\"पॉपअप दिखाएं\" सुविधा को संभव बनाने के लिए CAPod को अन्य ऐप्स पर आकर्षित करने दें।</string>
|
||||
<string name="settings_scanner_mode_lowpower_label">कम बिजली</string>
|
||||
<string name="settings_scanner_mode_balanced_label">संतुलित</string>
|
||||
<string name="settings_scanner_mode_lowlatency_label">कम विलंबता</string>
|
||||
<string name="settings_monitor_mode_manual_label">जब ऐप खुला हो</string>
|
||||
<string name="settings_monitor_mode_automatic_label">जब डिवाइस कनेक्ट होता है</string>
|
||||
<string name="settings_monitor_mode_always_label">हमेशा</string>
|
||||
<string name="settings_reaction_autoconnect_whenseen_label">जब देखा</string>
|
||||
<string name="settings_reaction_autoconnect_caseopen_label">मामला खुला है</string>
|
||||
<string name="settings_reaction_autoconnect_inear_label">कान में</string>
|
||||
<string name="pods_dual_left_label">लेफ्ट पॉड</string>
|
||||
<string name="pods_dual_right_label">दायां पॉड</string>
|
||||
<string name="pods_case_label">मामला</string>
|
||||
<string name="pods_case_status_open_label">खुला हुआ</string>
|
||||
<string name="pods_case_status_closed_label">बंद किया हुआ</string>
|
||||
<string name="pods_connection_state_disconnected_label">किसी डिवाइस से कनेक्ट नहीं है</string>
|
||||
<string name="pods_connection_state_idle_label">डिवाइस से कनेक्ट है, लेकिन निष्क्रिय है</string>
|
||||
<string name="pods_connection_state_music_label">संगीत मोड में</string>
|
||||
<string name="pods_connection_state_call_label">कॉल मोड में</string>
|
||||
<string name="pods_connection_state_ringing_label">बज</string>
|
||||
<string name="pods_connection_state_hanging_up_label">लटकाना</string>
|
||||
<string name="pods_connection_state_unknown_label">अज्ञात कनेक्शन स्थिति</string>
|
||||
<string name="pods_unknown_raw_data_label">कच्चा डेटा</string>
|
||||
<string name="pods_unknown_label">अज्ञात उपकरण</string>
|
||||
<string name="pods_unknown_contact_dev">यह एक अज्ञात डिवाइस है, लेकिन यह समान संदेश प्रारूप का उपयोग कर रहा है। आइए इसके लिए समर्थन जोड़ें, मुझसे संपर्क करें :)</string>
|
||||
<string name="pods_none_label_short">उपकरण नहीं</string>
|
||||
<string name="pods_charging_label">चार्ज</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">Errore</string>
|
||||
<string name="general_grant_permission_action">Concedi permessi</string>
|
||||
<string name="overview_nomaindevice_label">Nessun device primario</string>
|
||||
@@ -10,7 +14,9 @@
|
||||
<string name="permission_bluetooth_connect_description">Questa applicazione richiede il permesso di \"Connesione bluetooth\" per interagire con i dispotivi collegati e iniziare le connesioni.</string>
|
||||
<string name="permission_bluetooth_scan_label">Scansione bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Il permesso di \"Scansione bluetooth\" permette a questa app di trovare e ricevere dati Bluetooth da dispositivi vicini come le tue Airpods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Questa app richiede il permesso \"Bluetooth\" per connettersi ai dispoitivi Bluetooth.</string>
|
||||
<string name="permission_access_fine_location_label">Accedi alla posizione precisa</string>
|
||||
<string name="permission_access_fine_location_description">CAPod usa i permessi di Geolocalizzazione per ricevere dati Bluetooth a basso consumo. Le tue cuffie suano la tecnologia Bluetooth a basso consumo per inviare al dispositivo al quale sono connesse il loro stato. Questa app non utilizza i dati Bluetooth per geolocalizzarti.</string>
|
||||
<string name="permission_background_location_label">Accesso in background alla tua posizione</string>
|
||||
<string name="permission_background_location_description">CAPod usa l\'accesso in background alla tua posizione per far funzionare opzioni come \"Mostra popup\" e \"AutoConnect\" mentre l\'applicazione é chiusa. L\'accesso in background abiliterà l\'applicazione nella ricezione di dati Bluetooth a basso consume mentre l\'app non é aperta. Questa applicazione non utilizza i dati Bluetooth per geolocalizzarti.</string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">該当なし</string>
|
||||
<string name="general_error_label">エラー</string>
|
||||
<string name="general_grant_permission_action">許可する</string>
|
||||
@@ -10,16 +13,17 @@
|
||||
<string name="permission_bluetooth_connect_label">Bluetooth接続</string>
|
||||
<string name="permission_bluetooth_connect_description">このアプリでは、ペアリングされたデバイスとやり取りして接続を開始するには、「Bluetooth接続」の権限が必要です。</string>
|
||||
<string name="permission_bluetooth_scan_label">Bluetoothスキャン</string>
|
||||
<string name="permission_bluetooth_scan_description">「Bluetooth スキャン」権限により、このアプリはAirPodsなどの近くのデバイスからBluetoothのデータを検出して受信することができます。</string>
|
||||
<string name="permission_bluetooth_scan_description">「Bluetoothスキャン」権限により、このアプリはAirPodsなどの近くのデバイスからBluetoothのデータを検出して受信することができます。</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">このアプリは、ペアリングされたBluetoothデバイスに接続するために「Bluetooth」権限が必要です。</string>
|
||||
<string name="permission_access_fine_location_label">正確な位置情報</string>
|
||||
<string name="permission_access_fine_location_description">CAPodは、Bluetooth Low Energyデータを受信するために、「正確な位置情報」権限の許可を使用します。ヘッドホンはBluetooth Low Energyテクノロジーを使用してデバイスの状態を送信します。このアプリは、Bluetoothデータを使用して現在地を特定することはありません。</string>
|
||||
<string name="permission_background_location_label">バックグラウンドでの位置情報へのアクセス</string>
|
||||
<string name="permission_background_location_description">CAPodは「バックグラウンドでの位置情報へのアクセス」を使用して、アプリが閉じている間に「ポップアップ表示」や「自動接続」などの機能を有効にします。バックグラウンドでの位置情報アクセスにより、アプリはバックグラウンドでBluetooth Low Energyデータを受信できます。このアプリはBluetoothデータを使用して現在地を特定しません。</string>
|
||||
<string name="permission_ignore_battery_optimizations_label">バッテリーの最適化を無効にする</string>
|
||||
<string name="permission_ignore_battery_optimizations_label">バッテリーの最適化を無効</string>
|
||||
<string name="permission_ignore_battery_optimizations_description">バッテリーの最適化により、アプリがバックグラウンドにある間、このアプリはBluetoothデータを確実に受信できなくなります。</string>
|
||||
<string name="permission_required_title">次の権限の許可が必要です:</string>
|
||||
<string name="permission_system_alert_window_label">他のアプリの上に重ねて表示できるようにする。</string>
|
||||
<string name="permission_system_alert_window_label">他のアプリの上に重ねて表示</string>
|
||||
<string name="permission_system_alert_window_description">CAPodが他のアプリの上に描画できるようにして、「ポップアップ表示」機能を有効にします。</string>
|
||||
<string name="settings_scanner_mode_lowpower_label">省電力</string>
|
||||
<string name="settings_scanner_mode_balanced_label">バランス</string>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">오류</string>
|
||||
<string name="general_grant_permission_action">권한 부여</string>
|
||||
<string name="overview_nomaindevice_label">내 기기 없음</string>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<string name="general_grant_permission_action">Berikan kebenaran</string>
|
||||
<string name="overview_nomaindevice_label">Tiada peranti utama</string>
|
||||
<string name="overview_nomaindevice_description">Semua peranti yang dikesan tidak mungkin menjadi milik anda. Hidupkan dan sambung peranti anda atau laraskan tetapan.</string>
|
||||
<string name="overview_bluetooth_disabled_label">Bluetooth dinyahdayakan</string>
|
||||
<string name="overview_bluetooth_disabled_description">Bluetooth dinyahdayakan, dayakan ia ;)</string>
|
||||
<string name="overview_bluetooth_disabled_label">Bluetooth dilumpuhkan</string>
|
||||
<string name="overview_bluetooth_disabled_description">Bluetooth dilumpuhkan, dayakan ia ;)</string>
|
||||
<string name="permission_bluetooth_connect_label">Sambung bluetooth</string>
|
||||
<string name="permission_bluetooth_connect_description">Apl ini memerlukan kebenaran \"Bluetooth connect\" untuk berinteraksi dengan pasangan peranti dan memulakan sambungan.</string>
|
||||
<string name="permission_bluetooth_scan_label">Pengimbasan bluetooth</string>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">Fout</string>
|
||||
<string name="general_grant_permission_action">Toestemming geven</string>
|
||||
<string name="overview_nomaindevice_label">Geen primair apparaat</string>
|
||||
@@ -10,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Deze app heeft de toestemming \"Bluetooth verbinding\" nodig om te communiceren met gekoppelde apparaten en verbindingen tot stand te brengen.</string>
|
||||
<string name="permission_bluetooth_scan_label">Bluetooth scannen</string>
|
||||
<string name="permission_bluetooth_scan_description">Met de machtiging \'Bluetooth-scannen\' kan deze app Bluetooth-gegevens van apparaten in de buurt, zoals uw AirPods, ontdekken en ontvangen.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Deze app heeft de toestemming van \"Bluetooth\" nodig om verbinding te maken met gekoppelde Bluetooth-apparaten.</string>
|
||||
<string name="permission_access_fine_location_label">Toegang prima locatie</string>
|
||||
<string name="permission_access_fine_location_description">CAPod gebruikt de \"prima locatie\"-toestemming om Bluetooth Low Energy-gegevens te ontvangen. Uw hoofdtelefoon gebruikt Bluetooth Low Energy-technologie om hun status uit te zenden. Deze app gebruikt GEEN Bluetooth-gegevens om uw locatie te bepalen.</string>
|
||||
@@ -31,7 +36,8 @@
|
||||
<string name="settings_reaction_autoconnect_inear_label">In oor</string>
|
||||
<string name="pods_dual_left_label">Linker pod</string>
|
||||
<string name="pods_dual_right_label">Rechter pod</string>
|
||||
<string name="pods_case_label">Geval</string>
|
||||
<string name="pods_case_label">Oplaadcase</string>
|
||||
<string name="pods_case_status_open_label">Open</string>
|
||||
<string name="pods_case_status_closed_label">Gesloten</string>
|
||||
<string name="pods_connection_state_disconnected_label">Niet aangesloten op een apparaat</string>
|
||||
<string name="pods_connection_state_idle_label">Aangesloten op een apparaat, maar inactief</string>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">Feil</string>
|
||||
<string name="general_grant_permission_action">Gi tillatelse</string>
|
||||
<string name="overview_nomaindevice_label">Ingen primær enhet</string>
|
||||
@@ -10,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Denne appen må ha \"Bluetooth-tilkobling\"-tillatelsen for å kunne snakke med sammenkoblede enheter og starte tilkoblinger.</string>
|
||||
<string name="permission_bluetooth_scan_label">Bluetooth-skanning</string>
|
||||
<string name="permission_bluetooth_scan_description">\"Bluetooth-skanning\"-tillatelsen lar denne appen oppdage og motta Bluetooth-data fra enheter i nærheten, som for eksempel AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Denne appen må ha \"Bluetooth\"-tillatelsen for å koble til sammenkoblede Bluetooth-enheter.</string>
|
||||
<string name="permission_access_fine_location_label">Forbedret posisjonsnøyaktighet</string>
|
||||
<string name="permission_access_fine_location_description">CAPod bruker tillatelsen \"Forbedret posisjonsnøyaktighet\" for å motta Bluetooth Low Energy-data. Hodetelefonene dine bruker Bluetooth Low Energy-teknologi for å kringkaste statusen. Denne appen bruker IKKE Bluetooth-data til å se posisjonen din.</string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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/D</string>
|
||||
<string name="general_error_label">Błąd</string>
|
||||
<string name="general_grant_permission_action">Udziel uprawnień</string>
|
||||
@@ -11,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Aplikacja wymaga uprawnień do \"Połączenia Bluetooth\", aby oddziaływać na sparowane urządzenia i inicjować połączenia.</string>
|
||||
<string name="permission_bluetooth_scan_label">Skanowanie Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Uprawnienie \"Skanowanie Bluetooth\" zezwala aplikacji na odkrywanie i odbieranie danych Bluetooth od urządzeń znajdujących się w pobliżu, takich jak AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Aplikacja wymaga uprawnień \"Bluetooth\", aby łączyć się ze sparowanymi urządzeniami bluetooth.</string>
|
||||
<string name="permission_access_fine_location_label">Dostęp do dokładnej lokalizacji</string>
|
||||
<string name="permission_access_fine_location_description">CAPod korzysta z uprawnienia do \"dokładnej lokalizacji\", aby odbierać dane Bluetooth Low Energy. Twoje słuchawki korzystają z technologii Bluetooth Low Energy, aby przekazywać informacje o swoim stanie. Aplikacja NIE BĘDZIE korzystać z danych Bluetooth do ustalenia twojego położenia.</string>
|
||||
@@ -22,7 +26,7 @@
|
||||
<string name="permission_system_alert_window_label">Okna alertów systemowych</string>
|
||||
<string name="permission_system_alert_window_description">Zezwól na wyświetlanie CAPod nad innymi aplikacjami, aby aktywować funkcję \"Wyświetlanie informacji\".</string>
|
||||
<string name="settings_scanner_mode_lowpower_label">Oszczędzanie energii</string>
|
||||
<string name="settings_scanner_mode_balanced_label">Zabalansowana</string>
|
||||
<string name="settings_scanner_mode_balanced_label">Zbalansowana</string>
|
||||
<string name="settings_scanner_mode_lowlatency_label">Małe opóźnienia</string>
|
||||
<string name="settings_monitor_mode_manual_label">Gdy aplikacja jest uruchomiona</string>
|
||||
<string name="settings_monitor_mode_automatic_label">Gdy urządzenie jest podłączone</string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">Недоступно</string>
|
||||
<string name="general_error_label">Ошибка</string>
|
||||
<string name="general_grant_permission_action">Предоставить разрешение</string>
|
||||
@@ -11,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Этому приложению требуется разрешение \"Подключение по Bluetooth\" для взаимодействия с сопряженными устройствами и инициирования соединений.</string>
|
||||
<string name="permission_bluetooth_scan_label">Сканирование Bluetooth</string>
|
||||
<string name="permission_bluetooth_scan_description">Разрешение \"Сканирование Bluetooth\" позволяет этому приложению обнаруживать и получать данные по Bluetooth с близлежащих устройств, таких как Ваши AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Этому приложению требуется разрешение\"Bluetooth\" для подключения к сопряженным устройствам.</string>
|
||||
<string name="permission_access_fine_location_label">Доступ к точному местоположению</string>
|
||||
<string name="permission_access_fine_location_description">CAPod необходимо разрешение \"Точное местоположение\" для получения данных Bluetooth Low Energy. Ваши наушники задействуют технологию Bluetooth Low Energy (Bluetooth с низким энергопотреблением) для передачи своего состояния. Это приложение НЕ будет использовать данные Bluetooth для определения Вашего местоположения.</string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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/D</string>
|
||||
<string name="general_error_label">Chyba</string>
|
||||
<string name="general_grant_permission_action">Udeliť povolenie</string>
|
||||
@@ -11,6 +14,7 @@
|
||||
<string name="permission_bluetooth_connect_description">Táto aplikácia vyžaduje povolenie „Bluetooth pripojenie“ na interakciu so spárovanými zariadeniami a iniciovanie pripojení.</string>
|
||||
<string name="permission_bluetooth_scan_label">Bluetooth skenovanie</string>
|
||||
<string name="permission_bluetooth_scan_description">Povolenie „Bluetooth skenovanie“ umožňuje tejto aplikácii zisťovať a prijímať údaje z okolitých zariadení, ako sú vaše AirPods.</string>
|
||||
<string name="permission_bluetooth_label">Bluetooth</string>
|
||||
<string name="permission_bluetooth_description">Táto aplikácia vyžaduje povolenie „Bluetooth“ na pripojenie k spárovaným bluetooth zariadeniam.</string>
|
||||
<string name="permission_access_fine_location_label">Prístup k presnej polohe</string>
|
||||
<string name="permission_access_fine_location_description">CAPod používa oprávnenie „presná poloha“ na prijímanie údajov Bluetooth Low Energy. Vaše slúchadlá využívajú technológiu Bluetooth Low Energy na vysielanie svojho stavu. Táto aplikácia NEBUDE používať údaje Bluetooth na určenie vašej polohy.</string>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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">不可用</string>
|
||||
<string name="general_error_label">錯誤</string>
|
||||
<string name="general_grant_permission_action">授予權限</string>
|
||||
|
||||
@@ -65,4 +65,6 @@
|
||||
|
||||
<string name="last_seen_x">Last seen: %s</string>
|
||||
<string name="first_seen_x">First seen: %s</string>
|
||||
<string name="permission_post_notifications_label">Post notifications</string>
|
||||
<string name="permission_post_notifications_description">"Allow CAPod to show you notifications about your AirPods, e.g. their current status while connected."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,80 @@
|
||||
package eu.darken.capod.pods.core.apple.airpods
|
||||
|
||||
import eu.darken.capod.pods.core.apple.BaseAirPodsTest
|
||||
import eu.darken.capod.pods.core.apple.HasAppleColor
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AirPodsPro2Test : BaseAirPodsTest() {
|
||||
|
||||
/**
|
||||
* https://github.com/d4rken-org/capod/issues/31#issuecomment-1256791084
|
||||
*/
|
||||
@Test
|
||||
fun `test AirPods Pro 2 - unknown setup from #31`() = runBlockingTest {
|
||||
create<AirPodsPro2>("07 19 01 14 20 55 88 F9 51 00 04 20 50 03 CA D5 C9 AC 0F FA 84 78 94 5A 4D DF F5") {
|
||||
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x1420.toUShort()
|
||||
rawStatus shouldBe 0x55.toUByte()
|
||||
rawPodsBattery shouldBe 0x88.toUByte()
|
||||
rawFlags shouldBe 0xF.toUShort()
|
||||
rawCaseBattery shouldBe 0x9.toUShort()
|
||||
rawCaseLidState shouldBe 0x51.toUByte()
|
||||
rawDeviceColor shouldBe 0x0.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
isLeftPodMicrophone shouldBe true
|
||||
isRightPodMicrophone shouldBe false
|
||||
|
||||
isLeftPodInEar shouldBe false
|
||||
isRightPodInEar shouldBe false
|
||||
|
||||
batteryLeftPodPercent shouldBe 0.8f
|
||||
batteryRightPodPercent shouldBe 0.8f
|
||||
|
||||
isCaseCharging shouldBe true
|
||||
isRightPodCharging shouldBe true
|
||||
isLeftPodCharging shouldBe true
|
||||
batteryCasePercent shouldBe 0.9f
|
||||
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://old.reddit.com/message/messages/1hst12h
|
||||
*/
|
||||
@Test
|
||||
fun `test AirPods Pro 2 - unknown setup from reddit user`() = runBlockingTest {
|
||||
create<AirPodsPro2>("07 19 01 14 20 2B 9A 8F 01 00 04 0F 26 1A C4 2B FA 2F B9 B6 08 CD 60 CB DF 75 AB") {
|
||||
|
||||
rawPrefix shouldBe 0x01.toUByte()
|
||||
rawDeviceModel shouldBe 0x1420.toUShort()
|
||||
rawStatus shouldBe 0x2B.toUByte()
|
||||
rawPodsBattery shouldBe 0x9A.toUByte()
|
||||
rawFlags shouldBe 0x8.toUShort()
|
||||
rawCaseBattery shouldBe 0xF.toUShort()
|
||||
rawCaseLidState shouldBe 0x01.toUByte()
|
||||
rawDeviceColor shouldBe 0x0.toUByte()
|
||||
rawSuffix shouldBe 0x04.toUByte()
|
||||
|
||||
isLeftPodMicrophone shouldBe true
|
||||
isRightPodMicrophone shouldBe false
|
||||
|
||||
isLeftPodInEar shouldBe true
|
||||
isRightPodInEar shouldBe true
|
||||
|
||||
batteryLeftPodPercent shouldBe 1.0f
|
||||
batteryRightPodPercent shouldBe 0.9f
|
||||
|
||||
isCaseCharging shouldBe false
|
||||
isRightPodCharging shouldBe false
|
||||
isLeftPodCharging shouldBe false
|
||||
batteryCasePercent shouldBe null
|
||||
|
||||
podStyle.identifier shouldBe HasAppleColor.DeviceColor.WHITE.name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,8 @@ open class App : Application(), Configuration.Provider {
|
||||
private fun setupWorker() {
|
||||
log(TAG) { "setupWorker()" }
|
||||
val workRequest = PeriodicWorkRequestBuilder<MonitorWorker>(
|
||||
Duration.ofMinutes(15),
|
||||
Duration.ofMinutes(5)
|
||||
Duration.ofMinutes(30),
|
||||
Duration.ofMinutes(30)
|
||||
).apply {
|
||||
setInputData(Data.Builder().build())
|
||||
}.build()
|
||||
|
||||
@@ -86,12 +86,12 @@ class MonitorWorker @AssistedInject constructor(
|
||||
|
||||
val monitorJob = podMonitor.mainDevice
|
||||
.filterNotNull()
|
||||
.take(5)
|
||||
.take(3)
|
||||
.setupCommonEventHandlers(TAG) { "monitorJob" }
|
||||
.launchIn(workerScope)
|
||||
|
||||
try {
|
||||
withTimeout(60 * 1000) {
|
||||
withTimeout(15 * 1000) {
|
||||
monitorJob.join()
|
||||
}
|
||||
log(TAG) { "Monitor job quit after a few takes." }
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class DualPodsCardVH(parent: ViewGroup) :
|
||||
}
|
||||
text = sb
|
||||
|
||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||
else setTypeface(typeface, Typeface.NORMAL)
|
||||
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
|
||||
else setTypeface(null, Typeface.NORMAL)
|
||||
|
||||
if (device is DualAirPods && item.showDebug) {
|
||||
append(" [${device.primaryPod.name}]")
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ class SinglePodsCardVH(parent: ViewGroup) :
|
||||
|
||||
name.apply {
|
||||
text = device.getLabel(context)
|
||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||
else setTypeface(typeface, Typeface.NORMAL)
|
||||
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
|
||||
else setTypeface(null, Typeface.NORMAL)
|
||||
}
|
||||
|
||||
deviceIcon.setImageResource(device.iconRes)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="foss_upgrade_donate_label">Derma</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">Saya sudah menderma</string>
|
||||
<string name="foss_upgrade_donate_label">Sumbang</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">Saya telah menyumbang</string>
|
||||
<string name="foss_upgrade_no_money_label">Saya belanjakan semua wang saya untuk AirPods</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="upgrades_gplay_unavailable_error">Los servicios de Google Play no están disponibles.</string>
|
||||
<string name="upgrades_no_purchases_found_check_account">No se encontraron compras. ¿Está usando la cuenta correcta?</string>
|
||||
</resources>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.BLUETOOTH"
|
||||
|
||||
@@ -10,9 +10,7 @@ import androidx.annotation.MenuRes
|
||||
import androidx.annotation.XmlRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import eu.darken.capod.common.preferences.Settings
|
||||
import eu.darken.capod.main.ui.settings.SettingsFragment
|
||||
|
||||
@@ -69,17 +67,4 @@ abstract class PreferenceFragment2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> LiveData<T>.observe2(
|
||||
crossinline callback: (T) -> Unit
|
||||
) {
|
||||
observe(viewLifecycleOwner) { callback.invoke(it) }
|
||||
}
|
||||
|
||||
inline fun <T, reified VB : ViewBinding?> LiveData<T>.observe2(
|
||||
ui: VB,
|
||||
crossinline callback: VB.(T) -> Unit
|
||||
) {
|
||||
observe(viewLifecycleOwner) { callback.invoke(ui, it) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package eu.darken.capod.common.uix
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import eu.darken.capod.common.error.asErrorDialogBuilder
|
||||
|
||||
abstract class PreferenceFragment3 : PreferenceFragment2() {
|
||||
|
||||
abstract val vm: ViewModel3
|
||||
|
||||
var onErrorEvent: ((Throwable) -> Boolean)? = null
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
vm.errorEvents.observe2 {
|
||||
val showDialog = onErrorEvent?.invoke(it) ?: true
|
||||
if (showDialog) it.asErrorDialogBuilder(requireContext()).show()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> LiveData<T>.observe2(
|
||||
crossinline callback: (T) -> Unit
|
||||
) {
|
||||
observe(viewLifecycleOwner) { callback.invoke(it) }
|
||||
}
|
||||
|
||||
inline fun <T, reified VB : ViewBinding?> LiveData<T>.observe2(
|
||||
ui: VB,
|
||||
crossinline callback: VB.(T) -> Unit
|
||||
) {
|
||||
observe(viewLifecycleOwner) { callback.invoke(ui, it) }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package eu.darken.capod.main.ui.overview.cards
|
||||
import android.text.Html
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isGone
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.PrivacyPolicy
|
||||
import eu.darken.capod.common.lists.binding
|
||||
@@ -33,6 +34,12 @@ class PermissionCardVH(parent: ViewGroup) :
|
||||
val ppText = getString(R.string.settings_privacy_policy_label)
|
||||
val ppLink = PrivacyPolicy.URL
|
||||
text = Html.fromHtml("<html><a href=\"$ppLink\">$ppText</a></html>", 0)
|
||||
val ppp = setOf(
|
||||
Permission.ACCESS_FINE_LOCATION,
|
||||
Permission.ACCESS_BACKGROUND_LOCATION,
|
||||
Permission.BLUETOOTH_SCAN
|
||||
)
|
||||
isGone = !ppp.contains(item.permission)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ class DualPodsCardVH(parent: ViewGroup) :
|
||||
}
|
||||
text = sb
|
||||
|
||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||
else setTypeface(typeface, Typeface.NORMAL)
|
||||
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
|
||||
else setTypeface(null, Typeface.NORMAL)
|
||||
|
||||
if (device is DualAirPods && item.showDebug) {
|
||||
append(" [${device.primaryPod.name}]")
|
||||
|
||||
@@ -23,8 +23,8 @@ class SinglePodsCardVH(parent: ViewGroup) :
|
||||
|
||||
name.apply {
|
||||
text = device.getLabel(context)
|
||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||
else setTypeface(typeface, Typeface.NORMAL)
|
||||
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
|
||||
else setTypeface(null, Typeface.NORMAL)
|
||||
}
|
||||
|
||||
deviceIcon.setImageResource(device.iconRes)
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@ class UnknownPodDeviceCardVH(parent: ViewGroup) :
|
||||
val device = item.device
|
||||
name.apply {
|
||||
text = device.getLabel(context)
|
||||
if (item.isMainPod) setTypeface(typeface, Typeface.BOLD)
|
||||
else setTypeface(typeface, Typeface.NORMAL)
|
||||
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
|
||||
else setTypeface(null, Typeface.NORMAL)
|
||||
}
|
||||
|
||||
lastSeen.text = device.lastSeenFormatted(item.now)
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.bluetooth.ScannerMode
|
||||
import eu.darken.capod.common.preferences.PercentSliderPreference
|
||||
import eu.darken.capod.common.uix.PreferenceFragment2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment3
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
import eu.darken.capod.main.core.MonitorMode
|
||||
@@ -19,9 +19,9 @@ import javax.inject.Inject
|
||||
|
||||
@Keep
|
||||
@AndroidEntryPoint
|
||||
class GeneralSettingsFragment : PreferenceFragment2() {
|
||||
class GeneralSettingsFragment : PreferenceFragment3() {
|
||||
|
||||
private val vm: GeneralSettingsFragmentVM by viewModels()
|
||||
override val vm: GeneralSettingsFragmentVM by viewModels()
|
||||
|
||||
@Inject lateinit var generalSettings: GeneralSettings
|
||||
@Inject lateinit var upgradeRepo: UpgradeRepo
|
||||
|
||||
+4
-4
@@ -6,7 +6,7 @@ import eu.darken.capod.common.bluetooth.BluetoothManager2
|
||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.uix.ViewModel3
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -16,9 +16,9 @@ class GeneralSettingsFragmentVM @Inject constructor(
|
||||
private val bluetoothManager: BluetoothManager2,
|
||||
) : ViewModel3(dispatcherProvider) {
|
||||
|
||||
val bondedDevices = flow {
|
||||
emit(bluetoothManager.bondedDevices().toList())
|
||||
}.asLiveData2()
|
||||
val bondedDevices = bluetoothManager.bondedDevices()
|
||||
.map { it.toList() }
|
||||
.asLiveData2()
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Settings", "General", "VM")
|
||||
|
||||
+3
-3
@@ -9,14 +9,14 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.debug.autoreport.DebugSettings
|
||||
import eu.darken.capod.common.observe2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment3
|
||||
import javax.inject.Inject
|
||||
|
||||
@Keep
|
||||
@AndroidEntryPoint
|
||||
class DebugSettingsFragment : PreferenceFragment2() {
|
||||
class DebugSettingsFragment : PreferenceFragment3() {
|
||||
|
||||
private val vm: DebugSettingsFragmentVM by viewModels()
|
||||
override val vm: DebugSettingsFragmentVM by viewModels()
|
||||
|
||||
@Inject lateinit var debugSettings: DebugSettings
|
||||
|
||||
|
||||
@@ -10,15 +10,15 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.ClipboardHelper
|
||||
import eu.darken.capod.common.observe2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment3
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
import javax.inject.Inject
|
||||
|
||||
@Keep
|
||||
@AndroidEntryPoint
|
||||
class SupportFragment : PreferenceFragment2() {
|
||||
class SupportFragment : PreferenceFragment3() {
|
||||
|
||||
private val vm: SupportFragmentVM by viewModels()
|
||||
override val vm: SupportFragmentVM by viewModels()
|
||||
|
||||
override val preferenceFile: Int = R.xml.preferences_support
|
||||
@Inject lateinit var generalSettings: GeneralSettings
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package eu.darken.capod.reaction.ui
|
||||
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.Keep
|
||||
@@ -10,7 +11,7 @@ import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.uix.PreferenceFragment2
|
||||
import eu.darken.capod.common.uix.PreferenceFragment3
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import eu.darken.capod.main.core.GeneralSettings
|
||||
import eu.darken.capod.main.core.MonitorMode
|
||||
@@ -21,9 +22,9 @@ import javax.inject.Inject
|
||||
|
||||
@Keep
|
||||
@AndroidEntryPoint
|
||||
class ReactionSettingsFragment : PreferenceFragment2() {
|
||||
class ReactionSettingsFragment : PreferenceFragment3() {
|
||||
|
||||
private val vm: ReactionSettingsFragmentVM by viewModels()
|
||||
override val vm: ReactionSettingsFragmentVM by viewModels()
|
||||
|
||||
@Inject lateinit var generalSettings: GeneralSettings
|
||||
@Inject lateinit var reactionSettings: ReactionSettings
|
||||
@@ -35,6 +36,7 @@ class ReactionSettingsFragment : PreferenceFragment2() {
|
||||
override val preferenceFile: Int = R.xml.preferences_reactions
|
||||
|
||||
private var isPro: Boolean = false
|
||||
private var bondedDevices: List<BluetoothDevice> = emptyList()
|
||||
private val autoConnectConditionPref by lazy { findPreference<ListPreference>(settings.autoConnectCondition.key)!! }
|
||||
|
||||
override fun onPreferencesCreated() {
|
||||
@@ -66,10 +68,9 @@ class ReactionSettingsFragment : PreferenceFragment2() {
|
||||
preference.isChecked = false
|
||||
return true
|
||||
} else if (generalSettings.mainDeviceAddress.value == null) {
|
||||
val devices = vm.bondedDevices
|
||||
DeviceSelectionDialogFactory(requireContext()).create(
|
||||
devices = devices,
|
||||
current = devices.firstOrNull { it.address == generalSettings.mainDeviceAddress.value }
|
||||
devices = bondedDevices,
|
||||
current = bondedDevices.firstOrNull { it.address == generalSettings.mainDeviceAddress.value }
|
||||
) { selected ->
|
||||
generalSettings.mainDeviceAddress.value = selected?.address
|
||||
if (selected != null) preference.isChecked = true
|
||||
@@ -87,14 +88,21 @@ class ReactionSettingsFragment : PreferenceFragment2() {
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
|
||||
// Some UI interactions shortly turn autoConnect on, then off again
|
||||
private val previousMonitorMode by lazy { generalSettings.monitorMode.value }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
settings.autoConnect.flow.asLiveData().observe2 {
|
||||
generalSettings.monitorMode.value = MonitorMode.ALWAYS
|
||||
autoConnectConditionPref.isEnabled = it
|
||||
settings.autoConnect.flow.asLiveData().observe2 { isEnabled ->
|
||||
if (isEnabled) generalSettings.monitorMode.value = MonitorMode.ALWAYS
|
||||
else generalSettings.monitorMode.value = previousMonitorMode
|
||||
|
||||
autoConnectConditionPref.isEnabled = isEnabled
|
||||
}
|
||||
|
||||
vm.isPro.observe2 { isPro = it }
|
||||
|
||||
vm.bondedDevices.observe2 { bondedDevices = it }
|
||||
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,12 @@ class ReactionSettingsFragmentVM @Inject constructor(
|
||||
private val upgradeRepo: UpgradeRepo,
|
||||
) : ViewModel3(dispatcherProvider) {
|
||||
|
||||
val bondedDevices = bluetoothManager.bondedDevices().toList()
|
||||
|
||||
val isPro = upgradeRepo.upgradeInfo.map { it.isPro }.asLiveData2()
|
||||
|
||||
val bondedDevices = bluetoothManager.bondedDevices()
|
||||
.map { it.toList() }
|
||||
.asLiveData2()
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Settings", "Reaction", "VM")
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">Калі неабходна дапамога.</string>
|
||||
<string name="issue_tracker_label">Спіс праблем</string>
|
||||
<string name="issue_tracker_description">Агульнадаступны спіс для справаздач пра памылкі і запыту новых функцый (толькі англійская мова).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Месца для гутарак і задавання пытанняў.</string>
|
||||
<string name="changelog_label">Спіс змяненняў</string>
|
||||
<string name="settings_label">Налады</string>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">Potřebujete-li pomoc.</string>
|
||||
<string name="issue_tracker_label">Sledování problémů</string>
|
||||
<string name="issue_tracker_description">Veřejné sledování problémů pro hlášení chyb a požadavky na funkce (pouze v angličtině).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Místo, kde můžete psát a klást otázky.</string>
|
||||
<string name="changelog_label">Seznam změn</string>
|
||||
<string name="settings_label">Nastavení</string>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<string name="general_done_action">Fertig</string>
|
||||
<string name="general_copy_action">Kopieren</string>
|
||||
<string name="general_thank_you_label">Danke</string>
|
||||
<string name="general_upgrade_action">Aktualisierung</string>
|
||||
<string name="general_check_action">Überprüfen</string>
|
||||
<string name="general_close_action">Schließen</string>
|
||||
<string name="upgrade_capod_label">Verbesser CAPod</string>
|
||||
@@ -52,6 +53,7 @@
|
||||
<string name="settings_support_description">Wenn Sie Hilfe brauchen.</string>
|
||||
<string name="issue_tracker_label">Issue-Tracker</string>
|
||||
<string name="issue_tracker_description">Ein öffentlicher Issue-Tracker für Fehlerberichte und Funktionsanfragen (nur auf Englisch).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Ein Ort zum Verweilen und Fragen stellen.</string>
|
||||
<string name="changelog_label">Änderungsprotokoll</string>
|
||||
<string name="settings_label">Einstellungen</string>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">Si vous avez besoin d’aide.</string>
|
||||
<string name="issue_tracker_label">Gestionnaire de problèmes</string>
|
||||
<string name="issue_tracker_description">Un gestionnaire public de problèmes pour les signalements de bogues et les demandes de fonction (anglais seulement).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Un endroit à fréquenter où poser des questions.</string>
|
||||
<string name="changelog_label">Journal des changements</string>
|
||||
<string name="settings_label">Paramètres</string>
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
<string name="general_copy_action">प्रतिलिपि</string>
|
||||
<string name="general_thank_you_label">शुक्रिया</string>
|
||||
<string name="notification_channel_device_status_label">उपकरण की स्थिति</string>
|
||||
<string name="settings_support_installid_desc">स्वचालित त्रुटि रिपोर्ट गुमनाम हैं। यदि डेवलपर को आपकी त्रुटि रिपोर्ट ढूंढ़ने की आवश्यकता हो, तो अपना इंस्टॉल आईडी साझा करें.</string>
|
||||
</resources>
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
<string name="settings_support_label">Supporto</string>
|
||||
<string name="settings_support_description">Se ti serve un aiuto.</string>
|
||||
<string name="issue_tracker_description">Un issue tracker pubblico per segnalare i problemi e le richieste per aggiungere nuove funzionalità (solo in inglese).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Un posto dove poter fare domande.</string>
|
||||
<string name="changelog_label">Changelog</string>
|
||||
<string name="settings_label">Impostazioni</string>
|
||||
<string name="settings_privacy_policy_label">Politica sulla privacy</string>
|
||||
<string name="settings_privacy_policy_desc">Gestione dei dati responsabile.</string>
|
||||
@@ -71,4 +73,5 @@
|
||||
<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</string>
|
||||
</resources>
|
||||
|
||||
@@ -10,27 +10,27 @@
|
||||
<string name="upgrade_capod_label">CAPodをアップグレード</string>
|
||||
<string name="upgrade_capod_description">追加機能を取得し、開発者を支援する。</string>
|
||||
<string name="settings_monitor_mode_label">モニターモード</string>
|
||||
<string name="settings_monitor_mode_description">いつ、このアプリがBluetoothデータの監視をしますか。</string>
|
||||
<string name="settings_monitor_mode_description">このアプリがいつ、Bluetoothデータの監視をするのかを選択します。</string>
|
||||
<string name="settings_scanner_mode_label">スキャンモード</string>
|
||||
<string name="settings_scanner_mode_description">Bluetooth Low Energyデータスキャンは、パフォーマンスと省電力のどちらを優先すべきでしょうか?</string>
|
||||
<string name="settings_scanner_mode_description">Bluetooth Low Energyデータスキャンがパフォーマンスと省電力のどちらを優先すべきかを選択します。</string>
|
||||
<string name="settings_autopause_label">自動停止</string>
|
||||
<string name="settings_autopause_description">耳から外したときに再生を一時停止する。</string>
|
||||
<string name="settings_showall_label">すべてのデバイスを表示</string>
|
||||
<string name="settings_showall_description">近くにいる他の人の端末を表示します。</string>
|
||||
<string name="settings_showall_description">近くにいる他の人のデバイスを表示します。</string>
|
||||
<string name="settings_autopplay_label">自動再生</string>
|
||||
<string name="settings_autoplay_description">装着時に再生を開始する。</string>
|
||||
<string name="settings_fake_data_label">フェイクデータ</string>
|
||||
<string name="settings_fake_data_description">実在しない機器を模したフェイクデータを表示する。</string>
|
||||
<string name="settings_fake_data_description">実在しない機器を模したフェイクデータを表示します。</string>
|
||||
<string name="settings_debug_label">デバッグ用の設定</string>
|
||||
<string name="settings_debug_description">トラブルシューティングに役立つ追加設定。</string>
|
||||
<string name="settings_signal_minimum_label">最低限必要な信号品質</string>
|
||||
<string name="settings_signal_minimum_description">デバイスが自分のものとみなすために必要な最低限の信号品質。</string>
|
||||
<string name="settings_signal_minimum_description">デバイスが自分のものとみなすために必要な最低限の信号品質を調節します。</string>
|
||||
<string name="settings_autoconnect_label">自動接続</string>
|
||||
<string name="settings_autoconnect_description">Androidが自動的に接続しない場合は、こちらからも問い合わせることができます。これにより、モニターモードの設定が「常に」になります。</string>
|
||||
<string name="settings_autoconnect_condition_label">自動接続の条件</string>
|
||||
<string name="settings_autoconnect_condition_description">いつ接続を試みればよいですか。</string>
|
||||
<string name="settings_autoconnect_condition_description">接続をいつ試みるのかを選択します。</string>
|
||||
<string name="settings_reaction_label">アクション</string>
|
||||
<string name="settings_reaction_description">イベントや行動に対して機能が動作します。</string>
|
||||
<string name="settings_reaction_description">イベントや行動に対して機能が動作します</string>
|
||||
<string name="settings_category_yourdevice_label">あなたのデバイス</string>
|
||||
<string name="settings_maindevice_address_label">あなたのデバイスのアドレス</string>
|
||||
<string name="settings_maindevice_address_description">ペアリングされたデバイスのアドレス。 アプリはこれを使って、携帯電話にいつ接続されたかを判断します。</string>
|
||||
@@ -53,11 +53,12 @@
|
||||
<string name="settings_support_description">何か困ったことがあったら</string>
|
||||
<string name="issue_tracker_label">イシュー・トラッカー</string>
|
||||
<string name="issue_tracker_description">バグレポートや機能要望のための公開されたイシュー・トラッカー(英語のみ)。</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">質問がしやすい場所です。</string>
|
||||
<string name="changelog_label">更新の内容</string>
|
||||
<string name="settings_label">設定</string>
|
||||
<string name="settings_privacy_policy_label">個人情報の取り扱いについて</string>
|
||||
<string name="settings_privacy_policy_desc">責任を持ってデータを取り扱います。</string>
|
||||
<string name="settings_privacy_policy_desc">責任を持ってデータを取り扱います</string>
|
||||
<string name="settings_licenses_label">ライセンス情報</string>
|
||||
<string name="settings_category_other_label">その他</string>
|
||||
<string name="settings_general_label">全般</string>
|
||||
@@ -72,7 +73,7 @@
|
||||
<string name="settings_compatibility_mode_label">互換モード</string>
|
||||
<string name="settings_compatibility_mode_description">互換性を向上させるために最適化を無効にします。データが表示されない場合は、こちらをお試しください。</string>
|
||||
<string name="help_translate_label">翻訳</string>
|
||||
<string name="help_translate_description">このアプリをあなたの好きな言語に翻訳するのを手伝ってください。</string>
|
||||
<string name="help_translate_description">このアプリをあなたの好きな言語に翻訳するのを手伝ってください</string>
|
||||
<string name="translators_thanks_title">翻訳者</string>
|
||||
<string name="translators_thanks_description">OrangeOC(translation.love@na-cat.com)</string>
|
||||
</resources>
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<string name="general_check_action">Semak</string>
|
||||
<string name="general_close_action">Tutup</string>
|
||||
<string name="upgrade_capod_label">Naik taraf CAPod</string>
|
||||
<string name="upgrade_capod_description">Dapatkan ciri tambahan dan sokongi pemaju.</string>
|
||||
<string name="upgrade_capod_description">Dapatkan ciri tambahan dan dokongi pemaju.</string>
|
||||
<string name="settings_monitor_mode_label">Mod monitor</string>
|
||||
<string name="settings_monitor_mode_description">Dalam keadaan yang mana apl ini memantau data Bluetooth.</string>
|
||||
<string name="settings_monitor_mode_description">Dalam keadaan di mana apl ini memantau data Bluetooth.</string>
|
||||
<string name="settings_scanner_mode_label">Mod pengimbas</string>
|
||||
<string name="settings_scanner_mode_description">Apakah sepatutnya pengimbas data Tenaga Rendah Bluetooth mengutamakan prestasi atau penjimatan tenaga?</string>
|
||||
<string name="settings_autopause_label">Auto jeda</string>
|
||||
@@ -53,7 +53,9 @@
|
||||
<string name="settings_support_description">Jika anda perlukan bantuan.</string>
|
||||
<string name="issue_tracker_label">Penjejak isu</string>
|
||||
<string name="issue_tracker_description">Penjejak isu awam untuk laporan pepijat dan permintaan ciri (bahasa Inggeris sahaja).</string>
|
||||
<string name="discord_label">Perselisihan</string>
|
||||
<string name="discord_description">Tempat melepak dan bertanya soalan.</string>
|
||||
<string name="changelog_label">Log perubahan</string>
|
||||
<string name="settings_label">Tetapan</string>
|
||||
<string name="settings_privacy_policy_label">Polisi privasi</string>
|
||||
<string name="settings_privacy_policy_desc">Mengendalikan data secara bertanggungjawab.</string>
|
||||
|
||||
@@ -75,4 +75,5 @@
|
||||
<string name="help_translate_label">Vertaling</string>
|
||||
<string name="help_translate_description">Help deze app te vertalen in uw favoriete taal.</string>
|
||||
<string name="translators_thanks_title">Vertalers</string>
|
||||
<string name="translators_thanks_description">darken</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">Hvis du trenger hjelp med noe.</string>
|
||||
<string name="issue_tracker_label">Problemsporing</string>
|
||||
<string name="issue_tracker_description">En offentlig problemsporing for feilrapporter og funksjonsforespørsler (kun på engelsk).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Et sted til å henge og for å stille spørsmål.</string>
|
||||
<string name="changelog_label">Endringslogg</string>
|
||||
<string name="settings_label">Innstillinger</string>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<string name="settings_monitor_mode_label">Tryb monitorowania</string>
|
||||
<string name="settings_monitor_mode_description">W pewnych okolicznościach aplikacja może monitorować dane Bluetooth.</string>
|
||||
<string name="settings_scanner_mode_label">Tryb skanera</string>
|
||||
<string name="settings_scanner_mode_description">Czy skaner danych Bluetooth Low Energy ma priorytetowo działać w ramach wydajności czy oszczędzania energii?</string>
|
||||
<string name="settings_scanner_mode_description">Czy skaner danych Bluetooth Low Energy ma priorytetowo działać w ramach wydajności, czy oszczędzania energii?</string>
|
||||
<string name="settings_autopause_label">Automatyczna pauza</string>
|
||||
<string name="settings_autopause_description">Pauzuj odtwarzanie, gdy urządzenia jest wyciągane z ucha.</string>
|
||||
<string name="settings_showall_label">Wyświetl wszystkie urządzenia</string>
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">Jeśli potrzebujesz pomocy.</string>
|
||||
<string name="issue_tracker_label">Śledzenie problemów</string>
|
||||
<string name="issue_tracker_description">Publiczna lista problemów, dla raportów błędów oraz próśb o nowe funkcjonalności (tylko po angielsku).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Miejsce do rozmów i zadawania pytań.</string>
|
||||
<string name="changelog_label">Lista zmian</string>
|
||||
<string name="settings_label">Ustawienia</string>
|
||||
|
||||
@@ -75,5 +75,6 @@
|
||||
<string name="help_translate_label">Перевод</string>
|
||||
<string name="help_translate_description">Помогите перевести приложение на Ваш язык.</string>
|
||||
<string name="translators_thanks_title">Переводчики</string>
|
||||
<string name="translators_thanks_description">AL_Cool_T</string>
|
||||
<string name="translators_thanks_description">gaich
|
||||
AL_Cool_T</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">Ak potrebujete pomoc.</string>
|
||||
<string name="issue_tracker_label">Sledovač problémov</string>
|
||||
<string name="issue_tracker_description">Verejný nástroj na sledovanie problémov pre hlásenia chýb a požiadavky na funkcie (iba v angličtine).</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">Miesto, kde sa môžete stretnúť a klásť otázky.</string>
|
||||
<string name="changelog_label">Zoznam zmien</string>
|
||||
<string name="settings_label">Nastavenia</string>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="settings_support_description">如果你需要協助。</string>
|
||||
<string name="issue_tracker_label">問題追蹤器</string>
|
||||
<string name="issue_tracker_description">一個用於錯誤回報和功能需求的公用問題追蹤器 (僅英文)。</string>
|
||||
<string name="discord_label">Discord</string>
|
||||
<string name="discord_description">一個可以在其中閒逛並提出問題的地方。</string>
|
||||
<string name="changelog_label">變更記錄</string>
|
||||
<string name="settings_label">設定</string>
|
||||
|
||||
@@ -14,13 +14,16 @@ object ProjectConfig {
|
||||
const val targetSdk = 33
|
||||
|
||||
object Version {
|
||||
const val major = 2
|
||||
const val minor = 1
|
||||
const val patch = 0
|
||||
const val build = 0
|
||||
val versionProperties = Properties().apply {
|
||||
load(FileInputStream(File("version.properties")))
|
||||
}
|
||||
val major = versionProperties.getProperty("project.versioning.major").toInt()
|
||||
val minor = versionProperties.getProperty("project.versioning.minor").toInt()
|
||||
val patch = versionProperties.getProperty("project.versioning.patch").toInt()
|
||||
val build = versionProperties.getProperty("project.versioning.build").toInt()
|
||||
|
||||
const val name = "${major}.${minor}.${patch}-rc${build}"
|
||||
const val code = major * 10000000 + minor * 100000 + patch * 1000 + build * 10
|
||||
val name = "${major}.${minor}.${patch}-rc${build}"
|
||||
val code = major * 10000000 + minor * 100000 + patch * 1000 + build * 10
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ platform :android do
|
||||
skip_upload_images: 'true',
|
||||
skip_upload_screenshots: 'true',
|
||||
skip_upload_metadata: 'true',
|
||||
aab_paths: [
|
||||
"app/build/outputs/bundle/gplayRelease/app-gplay-beta.aab",
|
||||
"app-wear/build/outputs/bundle/gplayRelease/app-wear-gplay-beta.aab",
|
||||
],
|
||||
)
|
||||
end
|
||||
|
||||
@@ -45,6 +49,10 @@ platform :android do
|
||||
skip_upload_images: 'true',
|
||||
skip_upload_screenshots: 'true',
|
||||
skip_upload_metadata: 'true',
|
||||
aab_paths: [
|
||||
"app/build/outputs/bundle/gplayRelease/app-gplay-release.aab",
|
||||
"app-wear/build/outputs/bundle/gplayRelease/app-wear-gplay-release.aab",
|
||||
],
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
CAPod is a companion app for AirPods.
|
||||
CAPod es una aplicación complementaria para AirPods.
|
||||
|
||||
Features:
|
||||
Funciones:
|
||||
|
||||
* Battery level for pods and cases.
|
||||
* Charging status for pods and case.
|
||||
* Additional infos about connection, microphone and case.
|
||||
* Can receive and show all nearby devices.
|
||||
* Ear detection with automatic play/pause.
|
||||
* Automatically connect phone and AirPods.
|
||||
* Show popup when case is opened.
|
||||
* Nivel de batería para los auriculares y estuches.
|
||||
* Indicador de carga de auriculares y estuche.
|
||||
* Información adicional de conexión, micrófono y estuche.
|
||||
* Puede recibir y mostrar todos los dispositivos cercanos.
|
||||
* Detección de oído con reproducción/pausa automática.
|
||||
* Conecta automáticamente el teléfono y los AirPods.
|
||||
* Muestra un aviso emergente de estuche abierto.
|
||||
|
||||
CAPod is ad-free. Some features require an in-app purchase.
|
||||
CAPod es libre de publicidad. Algunas funciones requieren compras en la aplicación.
|
||||
|
||||
Most popular AirPods and Beats devices are supported.
|
||||
If your device is similar to AirPods but not yet supported, send me a short mail.
|
||||
Válido para la mayoría de AirPods populares y Beats.
|
||||
Si su dispositivo es similar a AirPods pero aún no es compatible, envíeme un correo.
|
||||
|
||||
Got a cool idea for a new feature? Reach out!
|
||||
¿Tienes una buena idea para una nueva característica? ¡Háznoslo saber!
|
||||
@@ -1 +1 @@
|
||||
CAPod is a companion app for AirPods on Android.
|
||||
CAPod es una aplicación complementaria para AirPods en Android.
|
||||
@@ -1 +1 @@
|
||||
CAPod - Companion for AirPods
|
||||
CAPod - Asistente para AirPods
|
||||
@@ -1,18 +1,18 @@
|
||||
CAPod ialah apl pendamping untuk AirPods.
|
||||
CAPod ialah aplikasi peneman untuk AirPods.
|
||||
|
||||
Ciri-ciri:
|
||||
|
||||
* Paras bateri untuk pods dan sarung.
|
||||
* Paras bateri untuk pod dan sarung.
|
||||
* Status pengecasan untuk pod dan sarung.
|
||||
* Maklumat tambahan tentang sambungan, mikrofon dan sarung.
|
||||
* Boleh menerima dan menunjukkan semua peranti berdekatan.
|
||||
* Pengesanan telinga dengan main/jeda automatik.
|
||||
* Sambungkan telefon dan AirPod secara automatik.
|
||||
* Tunjukkan popup apabila sarung dibuka.
|
||||
* Pamerkan timbul apabila sarung dibuka.
|
||||
|
||||
CAPod bebas iklan. Sesetengah ciri memerlukan pembelian dalam apl.
|
||||
CAPod adalah bebas iklan. Sesetengah ciri memerlukan pembelian dalam aplikasi.
|
||||
|
||||
Kebanyakan peranti AirPods dan Beats yang popular disokong.
|
||||
Jika peranti anda serupa dengan AirPods tetapi belum disokong, kirimkan mel ringkas kepada saya.
|
||||
|
||||
Peroleh idea hebat untuk ciri baharu? Menjangkau!
|
||||
Ada idea hebat untuk ciri yang baharu? Menjangkau!
|
||||
@@ -1 +1 @@
|
||||
CAPod - Rakan untuk AirPods
|
||||
CAPod - Teman untuk AirPod
|
||||
Executable
+458
@@ -0,0 +1,458 @@
|
||||
#!/bin/bash
|
||||
# Based on
|
||||
# * https://gist.github.com/jv-k/703e79306554c26a65a7cfdb9ca119c6
|
||||
# * https://github.com/jv-k/ver-bump
|
||||
|
||||
# █▄▄ █░█ █▀▄▀█ █▀█ ▄▄ █░█ █▀▀ █▀█ █▀ █ █▀█ █▄░█
|
||||
# █▄█ █▄█ █░▀░█ █▀▀ ░░ ▀▄▀ ██▄ █▀▄ ▄█ █ █▄█ █░▀█
|
||||
#
|
||||
#
|
||||
# Description:
|
||||
# - This script automates bumping the git software project's version using automation.
|
||||
|
||||
# - It does several things that are typically required for releasing a Git repository, like git tagging,
|
||||
# automatic updating of CHANGELOG.md, and incrementing the version number in various JSON files.
|
||||
|
||||
# - Increments / suggests the current software project's version number
|
||||
# - Adds a Git tag, named after the chosen version number
|
||||
# - Updates CHANGELOG.md
|
||||
# - Updates VERSION file
|
||||
# - Commits files to a new branch
|
||||
# - Pushes to remote (optionally)
|
||||
# - Updates "version" : "x.x.x" tag in JSON files if [-v file1 -v file2...] argument is supplied.
|
||||
#
|
||||
# Usage:
|
||||
# ./bump-version.sh [-v <version number>] [-m <release message>] [-j <file1>] [-j <file2>].. [-n] [-p] [-b] [-h]
|
||||
#
|
||||
# Options:
|
||||
# -v <version number> Specify a manual version number
|
||||
# -m <release message> Custom release message.
|
||||
# -f <filename.json> Update version number inside JSON files.
|
||||
# * For multiple files, add a separate -f option for each one,
|
||||
# * For example: ./bump-version.sh -f src/plugin/package.json -f composer.json
|
||||
# -p <repository alias> Push commits to remote repository, eg `-p origin`
|
||||
# -n Don't perform a commit automatically.
|
||||
# * You may want to do that yourself, for example.
|
||||
# -b Don't create automatic `release-<version>` branch
|
||||
# -h Show help message.
|
||||
|
||||
#
|
||||
# Detailed notes:
|
||||
# – The contents of the `VERSION` file which should be a semantic version number such as "1.2.3"
|
||||
# or even "1.2.3-beta+001.ab"
|
||||
#
|
||||
# – It pulls a list of changes from git history & prepends to a file called CHANGELOG.md
|
||||
# under the title of the new version # number, allows the user to review and update the changelist
|
||||
#
|
||||
# – Creates a Git tag with the version number
|
||||
#
|
||||
# - Creates automatic `release-<version>` branch
|
||||
#
|
||||
# – Commits the new version to the current repository
|
||||
#
|
||||
# – Optionally pushes the commit to remote repository
|
||||
#
|
||||
# – Make sure to set execute permissions for the script, eg `$ chmod 755 bump-version.sh`
|
||||
#
|
||||
# Credits:
|
||||
# – https://github.com/jv-k/bump-version
|
||||
#
|
||||
# - Inspired by the scripts from @pete-otaqui and @mareksuscak
|
||||
# https://gist.github.com/pete-otaqui/4188238
|
||||
# https://gist.github.com/mareksuscak/1f206fbc3bb9d97dec9c
|
||||
#
|
||||
|
||||
NOW="$(date +'%B %d, %Y')"
|
||||
|
||||
# ANSI/VT100 colours
|
||||
YELLOW='\033[1;33m'
|
||||
LIGHTYELLOW='\033[0;33m'
|
||||
RED='\033[0;31m'
|
||||
LIGHTRED='\033[1;31m'
|
||||
GREEN='\033[0;32m'
|
||||
LIGHTGREEN='\033[1;32m'
|
||||
BLUE='\033[0;34m'
|
||||
LIGHTBLUE='\033[1;34m'
|
||||
PURPLE='\033[0;35m'
|
||||
LIGHTPURPLE='\033[1;35m'
|
||||
CYAN='\033[0;36m'
|
||||
LIGHTCYAN='\033[1;36m'
|
||||
WHITE='\033[1;37m'
|
||||
LIGHTGRAY='\033[0;37m'
|
||||
DARKGRAY='\033[1;30m'
|
||||
BOLD="\033[1m"
|
||||
INVERT="\033[7m"
|
||||
RESET='\033[0m'
|
||||
|
||||
# Default options
|
||||
FLAG_JSON="false"
|
||||
FLAG_PUSH="false"
|
||||
|
||||
I_OK="✅"
|
||||
I_STOP="🚫"
|
||||
I_ERROR="❌"
|
||||
I_END="👋🏻"
|
||||
|
||||
S_NORM="${WHITE}"
|
||||
S_LIGHT="${LIGHTGRAY}"
|
||||
S_NOTICE="${GREEN}"
|
||||
S_QUESTION="${YELLOW}"
|
||||
S_WARN="${LIGHTRED}"
|
||||
S_ERROR="${RED}"
|
||||
|
||||
V_SUGGEST="0.1.2-rc5" # This is suggested in case VERSION file or user supplied version via -v is missing
|
||||
|
||||
V_MAJOR="" # 0
|
||||
V_MINOR="" # 1
|
||||
V_PATCH="" # 2
|
||||
V_BUILD_TYPE="" # rc
|
||||
V_BUILD_COUNTER="" # 5
|
||||
V_NAME=""
|
||||
V_CODE=""
|
||||
|
||||
SCRIPT_VER="1.0"
|
||||
|
||||
GIT_MSG="Release: "
|
||||
REL_NOTE=""
|
||||
REL_PREFIX="release/"
|
||||
PUSH_DEST="origin"
|
||||
|
||||
# Show credits & help
|
||||
usage() {
|
||||
echo -e "$GREEN" \
|
||||
"\n █▄▄ █░█ █▀▄▀█ █▀█ ▄▄ █░█ █▀▀ █▀█ █▀ █ █▀█ █▄░█ " \
|
||||
"\n █▄█ █▄█ █░▀░█ █▀▀ ░░ ▀▄▀ ██▄ █▀▄ ▄█ █ █▄█ █░▀█ " \
|
||||
"\n\t\t\t\t\t$LIGHTGRAY v${SCRIPT_VER}"
|
||||
|
||||
echo -e " ${S_NORM}${BOLD}Usage:${RESET}" \
|
||||
"\n $0 [-v <version number>] [-m <release message>] [-n] [-p] [-h]" 1>&2
|
||||
|
||||
echo -e "\n ${S_NORM}${BOLD}Options:${RESET}"
|
||||
echo -e " $S_WARN-v$S_NORM <version number>\tSpecify a manual version number"
|
||||
echo -e " $S_WARN-m$S_NORM <release message>\tCustom release message."
|
||||
echo -e " $S_WARN-p$S_NORM \t\t\tPush commits to ORIGIN. "
|
||||
echo -e " $S_WARN-n$S_NORM \t\t\tDon't perform a commit automatically. " \
|
||||
"\n\t\t\t* You may want to do that manually after checking everything, for example."
|
||||
echo -e " $S_WARN-b$S_NORM \t\t\tDon't create automatic \`release-<version>\` branch"
|
||||
echo -e " $S_WARN-h$S_NORM \t\t\tShow this help message. "
|
||||
echo -e "\n ${S_NORM}${BOLD}Original author: $S_LIGHT https://github.com/jv-t/bump-version $RESET"
|
||||
echo -e "\n ${S_NORM}${BOLD}Changes by: $S_LIGHT https://github.com/d4rken $RESET\n"
|
||||
}
|
||||
|
||||
# If there are no commits in repo, quit, because you can't tag with zero commits.
|
||||
check-commits-exist() {
|
||||
git rev-parse HEAD &>/dev/null
|
||||
if [ ! "$?" -eq 0 ]; then
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Your current branch doesn't have any commits yet. Can't tag without at least one commit." >&2
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
exit_abnormal() {
|
||||
echo -e " ${S_LIGHT}––––––"
|
||||
usage # Show help
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Process script options
|
||||
process-arguments() {
|
||||
local OPTIONS OPTIND OPTARG
|
||||
|
||||
# Get positional parameters
|
||||
JSON_FILES=()
|
||||
while getopts ":v:p:m:hbn" OPTIONS; do # Note: Adding the first : before the flags takes control of flags and prevents default error msgs.
|
||||
case "$OPTIONS" in
|
||||
h)
|
||||
# Show help
|
||||
exit_abnormal
|
||||
;;
|
||||
v)
|
||||
# User has supplied a version number
|
||||
V_USR_SUPPLIED=$OPTARG
|
||||
;;
|
||||
m)
|
||||
REL_NOTE=$OPTARG
|
||||
# Custom release note
|
||||
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Release note:" ${S_NORM}"'"$REL_NOTE"'"
|
||||
;;
|
||||
p)
|
||||
FLAG_PUSH=true
|
||||
PUSH_DEST=${OPTARG} # Replace default with user input
|
||||
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Pushing to <${S_NORM}${PUSH_DEST}${S_LIGHT}>, as the last action in this script."
|
||||
;;
|
||||
n)
|
||||
FLAG_NOCOMMIT=true
|
||||
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Disable commit after tagging."
|
||||
;;
|
||||
b)
|
||||
FLAG_NOBRANCH=true
|
||||
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Disable committing to new branch."
|
||||
;;
|
||||
\?)
|
||||
echo -e "\n${I_ERROR}${S_ERROR} Invalid option: ${S_WARN}-$OPTARG" >&2
|
||||
echo
|
||||
exit_abnormal
|
||||
;;
|
||||
:)
|
||||
echo -e "\n${I_ERROR}${S_ERROR} Option ${S_WARN}-$OPTARG ${S_ERROR}requires an argument." >&2
|
||||
echo
|
||||
exit_abnormal
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Suggests version from VERSION file, or grabs from user supplied -v <version>.
|
||||
# If none is set, suggest default from options.
|
||||
process-version() {
|
||||
V_RAW=""
|
||||
|
||||
V_FILE_REGEX='^([0-9]+\.[0-9]+\.[0-9]+-[a-zA-Z]+[0-9]+) ([0-9]+)$'
|
||||
V_FILE_RAW="$(cat VERSION)"
|
||||
if [ -f VERSION ] && [ -s VERSION ] && [[ $V_FILE_RAW =~ $V_FILE_REGEX ]]; then
|
||||
V_PREV="${BASH_REMATCH[1]}"
|
||||
V_SUGGEST=$V_PREV
|
||||
echo -e "\n${S_NOTICE}Current version from <${S_NORM}VERSION${S_NOTICE}> file: ${S_NORM}$V_PREV"
|
||||
else
|
||||
echo -ne "\n${S_WARN}The [${S_NORM}VERSION${S_WARN}] "
|
||||
if [ ! -f VERSION ]; then
|
||||
echo "VERSION file was not found."
|
||||
elif [ ! -s VERSION ]; then
|
||||
echo "VERSION file is empty."
|
||||
else
|
||||
echo "could not be parsed."
|
||||
fi
|
||||
fi
|
||||
|
||||
# If a version number is supplied by the user with [-v <version number>], then use it
|
||||
if [ -n "$V_USR_SUPPLIED" ]; then
|
||||
echo -e "\n${S_NOTICE}You selected version using [-v]:" "${S_WARN}${V_USR_SUPPLIED}"
|
||||
V_RAW="${V_USR_SUPPLIED}"
|
||||
else
|
||||
echo -ne "\n${S_QUESTION}Enter a new version number [${S_NORM}$V_SUGGEST${S_QUESTION}]: "
|
||||
echo -ne "$S_WARN"
|
||||
read -r V_RAW
|
||||
fi
|
||||
|
||||
if [ -z "$V_RAW" ]; then
|
||||
V_RAW=$V_PREV
|
||||
fi
|
||||
|
||||
if [ -z "$V_RAW" ]; then
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Error: No version was supplied (no file, no CLI)\n"
|
||||
exit_abnormal
|
||||
fi
|
||||
|
||||
SEMVER_REGEX='^([0-9]+)\.([0-9]+)\.([0-9]+)-([a-zA-Z]+)([0-9]+)$'
|
||||
|
||||
echo -e "\n${S_NOTICE}Parsing ${V_RAW}"
|
||||
|
||||
if [[ $V_RAW =~ $SEMVER_REGEX ]]; then
|
||||
echo -e "\n${I_OK} ${S_NOTICE} Successfully parsed ${V_RAW} to ${BASH_REMATCH[0]}"
|
||||
V_MAJOR="${BASH_REMATCH[1]}"
|
||||
echo "V_MAJOR=$V_MAJOR"
|
||||
V_MINOR="${BASH_REMATCH[2]}"
|
||||
echo "V_MINOR=$V_MINOR"
|
||||
V_PATCH="${BASH_REMATCH[3]}"
|
||||
echo "V_PATCH=$V_PATCH"
|
||||
V_BUILD_TYPE="${BASH_REMATCH[4]}"
|
||||
echo "V_BUILD_TYPE=$V_BUILD_TYPE"
|
||||
V_BUILD_COUNTER="${BASH_REMATCH[5]}"
|
||||
echo "V_BUILD_COUNTER=$V_BUILD_COUNTER"
|
||||
else
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Error: Failed to parse $V_RAW\n"
|
||||
exit_abnormal
|
||||
fi
|
||||
|
||||
# If no version was provided, bump the previous version
|
||||
if [ -z "$V_USR_SUPPLIED" ]; then
|
||||
if [ "$V_BUILD_COUNTER" -eq "$V_BUILD_COUNTER" ] 2>/dev/null; then # discard stderr (2) output to black hole (suppress it)
|
||||
V_BUILD_COUNTER=$((V_BUILD_COUNTER + 1)) # Increment
|
||||
fi
|
||||
fi
|
||||
|
||||
V_NAME="$V_MAJOR.$V_MINOR.$V_PATCH-$V_BUILD_TYPE$V_BUILD_COUNTER"
|
||||
V_CODE=$((V_MAJOR * 10000000 + V_MINOR * 100000 + V_PATCH * 1000 + V_BUILD_COUNTER * 10))
|
||||
echo -e "${S_NOTICE}Setting version to [${S_NORM}${V_NAME} (${V_CODE})${S_NOTICE}] ...."
|
||||
}
|
||||
|
||||
# Only tag if tag doesn't already exist
|
||||
check-tag-exists() {
|
||||
TAG_CHECK_EXISTS=$(git tag -l v"$V_NAME")
|
||||
if [ -n "$TAG_CHECK_EXISTS" ]; then
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Error: A release with that tag version number already exists!\n"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 : version
|
||||
# $2 : release note
|
||||
create-tag() {
|
||||
if [ -z "$2" ]; then
|
||||
# Default release note
|
||||
git tag -a "v$1" -m "Tag version $1."
|
||||
else
|
||||
# Custom release note
|
||||
git tag -a "v$1" -m "$2"
|
||||
fi
|
||||
echo -e "\n${I_OK} ${S_NOTICE}Added GIT tag"
|
||||
}
|
||||
|
||||
# Update version.properties which is used by Gradle to generate the `versionName` and `versionCode`
|
||||
do-version-properties() {
|
||||
PROPS_FILE_NAME="version.properties"
|
||||
echo -e "\n${S_NOTICE}Parsing ${PROPS_FILE_NAME}:\n"
|
||||
|
||||
V_MAJOR_REGEX='^([a-zA-Z\.]+major)=([0-9]+)$'
|
||||
V_MINOR_REGEX='^([a-zA-Z\.]+minor)=([0-9]+)$'
|
||||
V_PATCH_REGEX='^([a-zA-Z\.]+patch)=([0-9]+)$'
|
||||
V_BUILD_REGEX='^([a-zA-Z\.]+build)=([0-9]+)$'
|
||||
|
||||
PROPS_FILE_NEW=""
|
||||
|
||||
LAST_LINE=$(wc -l <$PROPS_FILE_NAME)
|
||||
CURRENT_LINE=0
|
||||
|
||||
while read -r line; do
|
||||
CURRENT_LINE=$((CURRENT_LINE + 1))
|
||||
|
||||
if [[ $line =~ $V_MAJOR_REGEX ]]; then
|
||||
updated="${BASH_REMATCH[1]}=${V_MAJOR}"
|
||||
echo "Found major, replacing: $line -> $updated"
|
||||
PROPS_FILE_NEW+=$updated
|
||||
elif [[ $line =~ $V_MINOR_REGEX ]]; then
|
||||
updated="${BASH_REMATCH[1]}=${V_MINOR}"
|
||||
echo "Found minor, replacing: $line -> $updated"
|
||||
PROPS_FILE_NEW+=$updated
|
||||
elif [[ $line =~ $V_PATCH_REGEX ]]; then
|
||||
updated="${BASH_REMATCH[1]}=${V_PATCH}"
|
||||
echo "Found patch, replacing: $line -> $updated"
|
||||
PROPS_FILE_NEW+=$updated
|
||||
elif [[ $line =~ $V_BUILD_REGEX ]]; then
|
||||
updated="${BASH_REMATCH[1]}=${V_BUILD_COUNTER}"
|
||||
echo "Found build, replacing: $line -> $updated"
|
||||
PROPS_FILE_NEW+=$updated
|
||||
else
|
||||
PROPS_FILE_NEW+="$line"
|
||||
fi
|
||||
|
||||
if [[ $CURRENT_LINE -ne $LAST_LINE ]]; then
|
||||
PROPS_FILE_NEW+="\n"
|
||||
fi
|
||||
|
||||
done <"$PROPS_FILE_NAME"
|
||||
|
||||
echo -e "$PROPS_FILE_NEW" >"$PROPS_FILE_NAME"
|
||||
git add "$PROPS_FILE_NAME"
|
||||
|
||||
echo -e "\n${I_OK} ${S_NOTICE}Updated [${S_NORM}${PROPS_FILE_NAME}${S_NOTICE}] file"
|
||||
}
|
||||
|
||||
# Update a version file that can be parsed by third-parties, e.g. F-Droid
|
||||
do-versionfile() {
|
||||
[ -f VERSION ] && ACTION_MSG="Updated" || ACTION_MSG="Created"
|
||||
|
||||
echo "${V_NAME} ${V_CODE}" >VERSION # Create file
|
||||
echo -e "\n${I_OK} ${S_NOTICE}${ACTION_MSG} [${S_NORM}VERSION${S_NOTICE}] file"
|
||||
|
||||
# Stage file for commit
|
||||
git add VERSION
|
||||
}
|
||||
|
||||
# Does the release branch already exist?
|
||||
check-branch-exist() {
|
||||
[ "$FLAG_NOBRANCH" = true ] && return
|
||||
|
||||
BRANCH_MSG=$(git rev-parse --verify "${REL_PREFIX}${V_NAME}" 2>&1)
|
||||
if [ "$?" -eq 0 ]; then
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Error: Branch <${S_NORM}${REL_PREFIX}${V_NAME}${S_ERROR}> already exists!\n"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Create release branch if desired
|
||||
do-branch() {
|
||||
[ "$FLAG_NOBRANCH" = true ] && return
|
||||
|
||||
echo -e "\n${S_NOTICE}Creating new release branch..."
|
||||
|
||||
BRANCH_MSG=$(git branch "${REL_PREFIX}${V_NAME}" 2>&1)
|
||||
if [ ! "$?" -eq 0 ]; then
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Error\n$BRANCH_MSG\n"
|
||||
exit 1
|
||||
else
|
||||
BRANCH_MSG=$(git checkout "${REL_PREFIX}${V_NAME}" 2>&1)
|
||||
echo -e "\n${I_OK} ${S_NOTICE}${BRANCH_MSG}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Stage & commit all files modified by this script
|
||||
do-commit() {
|
||||
[ "$FLAG_NOCOMMIT" = true ] && return
|
||||
|
||||
echo -e "\n${S_NOTICE}Committing..."
|
||||
COMMIT_MSG=$(git commit -m "${GIT_MSG}" 2>&1)
|
||||
if [ ! "$?" -eq 0 ]; then
|
||||
echo -e "\n${I_STOP} ${S_ERROR}Error\n$COMMIT_MSG\n"
|
||||
exit 1
|
||||
else
|
||||
echo -e "\n${I_OK} ${S_NOTICE}$COMMIT_MSG"
|
||||
fi
|
||||
}
|
||||
|
||||
# Pushes files + tags to remote repo. Changes are staged by earlier functions
|
||||
do-push() {
|
||||
[ "$FLAG_NOCOMMIT" = true ] && return
|
||||
|
||||
if [ "$FLAG_PUSH" = true ]; then
|
||||
CONFIRM="Y"
|
||||
else
|
||||
echo -ne "\n${S_QUESTION}Push tags to <${S_NORM}${PUSH_DEST}${S_QUESTION}>? [${S_NORM}N/y${S_QUESTION}]: "
|
||||
read CONFIRM
|
||||
fi
|
||||
|
||||
case "$CONFIRM" in
|
||||
[yY][eE][sS] | [yY])
|
||||
echo -e "\n${S_NOTICE}Pushing files + tags to <${S_NORM}${PUSH_DEST}${S_NOTICE}>..."
|
||||
|
||||
PUSH_MSG=$(git push "${PUSH_DEST}" v"$V_NAME" 2>&1) # Push new tag
|
||||
PUSH_MSG+="\n"
|
||||
PUSH_MSG+=$(git push 2>&1) # Push new tag
|
||||
|
||||
if [ ! "$?" -eq 0 ]; then
|
||||
echo -e "\n${I_STOP} ${S_WARN}Warning\n$PUSH_MSG"
|
||||
# exit 1
|
||||
else
|
||||
echo -e "\n${I_OK} ${S_NOTICE}$PUSH_MSG"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#### Initiate Script ###########################
|
||||
|
||||
check-commits-exist
|
||||
|
||||
# Process and prepare
|
||||
process-arguments "$@"
|
||||
process-version
|
||||
|
||||
GIT_MSG+="${V_NAME}"
|
||||
|
||||
check-branch-exist
|
||||
check-tag-exists
|
||||
|
||||
echo -e "\n${S_LIGHT}––––––"
|
||||
|
||||
# Update steps
|
||||
do-version-properties
|
||||
do-versionfile
|
||||
do-branch
|
||||
do-commit
|
||||
create-tag "${V_NAME}" "${REL_NOTE}"
|
||||
do-push
|
||||
|
||||
echo -e "\n${S_LIGHT}––––––"
|
||||
echo -e "\n${I_OK} ${S_NOTICE}"Bumped $([ -n "${V_PREV}" ] && echo "${V_PREV} –>" || echo "to ") "$V_NAME"
|
||||
echo -e "\n${GREEN}Done ${I_END}\n"
|
||||
@@ -0,0 +1,6 @@
|
||||
### Updated by release.sh ###
|
||||
project.versioning.major=2
|
||||
project.versioning.minor=2
|
||||
project.versioning.patch=1
|
||||
project.versioning.build=1
|
||||
#############################
|
||||
Reference in New Issue
Block a user