Compare commits

..
17 Commits
Author SHA1 Message Date
darken 7e913e7847 Make bugsnag opt-out in gplay and opt-in in foss builds. 2022-07-24 16:00:38 +02:00
darken ec7871e4e9 Change issue tracker icon 2022-07-24 16:00:07 +02:00
darken cc5a45a14f Update repo links 2022-07-24 16:00:07 +02:00
Matthias Urhahn 5fff3457ba Update README.md 2022-07-24 15:03:19 +02:00
darken 6f5d66c1d9 Update README.md 2022-07-24 14:02:53 +02:00
darken d94795bf4f Update PRIVACY_POLICY.md 2022-07-24 13:58:17 +02:00
darken 009b71c42a Update PP 2022-07-24 13:43:47 +02:00
darken a10716d74e Update gitignore 2022-07-24 13:43:06 +02:00
darken b44bf5f401 Setup CI for testing, gplay release and foss release. 2022-07-24 13:38:52 +02:00
Matthias Urhahn e0af1838e2 Delete local.properties 2022-07-24 13:38:43 +02:00
darken 7d5502a34f Version bump (1.3.13) 2022-07-08 19:27:28 +02:00
darken 78ccddf87c Fix notification icon/text color to match light/dark theme. 2022-05-01 17:48:32 +02:00
darken df1bc48e84 Version bump (1.3.12) 2022-05-01 17:36:17 +02:00
darken 3b48d61571 Version bump (1.3.11) 2022-05-01 17:17:53 +02:00
darken 92d5e2a40d Updated translations 2022-05-01 17:13:42 +02:00
darken 234857c414 When enabling unfiltered BLE data, also enable "show all" to make debugging easier. 2022-05-01 16:42:17 +02:00
darken b1bbe785ea Fix debug log naming 2022-04-18 11:10:10 +02:00
33 changed files with 419 additions and 119 deletions
@@ -1,4 +1,4 @@
name: Android CI
name: Code tests & eval
on:
push:
@@ -7,13 +7,13 @@ on:
branches: [ main ]
jobs:
build:
build-and-test:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: set up JDK 11
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
@@ -22,7 +22,13 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew assembleDebug
- name: Run tests
run: ./gradlew testGplayDebugUnitTest testFossDebugUnitTest
- name: Build FOSS variant
run: ./gradlew assembleFossDebug
- name: Test FOSS variant
run: ./gradlew testFossDebugUnitTest
- name: Build Google Play variant
run: ./gradlew assembleGplayDebug
- name: Test Google Play variant
run: ./gradlew testGplayDebugUnitTest
+153
View File
@@ -0,0 +1,153 @@
name: Tagged releases
on:
push:
tags:
- 'v*'
jobs:
release-github:
name: Create GitHub release
runs-on: ubuntu-latest
environment: foss-production
steps:
- name: Decode Keystore
env:
ENCODED_KEYSTORE: ${{ secrets.SIGNING_KEYSTORE_BASE64 }}
run: |
TMP_KEYSTORE_DIR_PATH="${RUNNER_TEMP}"/keystore
mkdir -p "${TMP_KEYSTORE_DIR_PATH}"
TMP_KEYSTORE_FILE_PATH="${TMP_KEYSTORE_DIR_PATH}"/keystore.jks
echo $ENCODED_KEYSTORE | base64 -di > "${TMP_KEYSTORE_FILE_PATH}"
echo "STORE_PATH=$(echo $TMP_KEYSTORE_FILE_PATH)" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get the version
id: tagger
uses: jimschubert/query-tag-action@v2
with:
skip-unshallow: 'true'
abbrev: false
commit-ish: HEAD
- name: Install JDK ${{ matrix.java_version }}
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: 11
- name: Assemble beta APK
if: contains(steps.tagger.outputs.tag, '-beta')
run: ./gradlew assembleFossBeta
env:
VERSION: ${{ github.ref }}
STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
BUGSNAG_API_KEY: ${{ secrets.BUGSNAG_API_KEY }}
- name: Assemble production APK
if: "!contains(steps.tagger.outputs.tag, '-beta')"
run: ./gradlew assembleFossRelease
env:
VERSION: ${{ github.ref }}
STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
BUGSNAG_API_KEY: ${{ secrets.BUGSNAG_API_KEY }}
- name: Create pre-release
if: contains(steps.tagger.outputs.tag, '-beta')
uses: softprops/action-gh-release@v1
with:
prerelease: true
tag_name: ${{ steps.tagger.outputs.tag }}
name: ${{ steps.tagger.outputs.tag }}
generate_release_notes: true
files: app/build/outputs/apk/beta/*.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
if: "!contains(steps.tagger.outputs.tag, '-beta')"
uses: softprops/action-gh-release@v1
with:
prerelease: false
tag_name: ${{ steps.tagger.outputs.tag }}
name: ${{ steps.tagger.outputs.tag }}
generate_release_notes: true
files: app/build/outputs/apk/release/*.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-gplay:
name: Create Google Play release
runs-on: ubuntu-latest
environment: gplay-production
steps:
- name: Decode Keystore
env:
ENCODED_KEYSTORE: ${{ secrets.SIGNING_KEYSTORE_BASE64 }}
run: |
TMP_KEYSTORE_DIR_PATH="${RUNNER_TEMP}"/keystore
mkdir -p "${TMP_KEYSTORE_DIR_PATH}"
TMP_KEYSTORE_FILE_PATH="${TMP_KEYSTORE_DIR_PATH}"/keystore.jks
echo $ENCODED_KEYSTORE | base64 -di > "${TMP_KEYSTORE_FILE_PATH}"
echo "STORE_PATH=$(echo $TMP_KEYSTORE_FILE_PATH)" >> $GITHUB_ENV
- name: Decode Google Play service account key
env:
ENCODED_SERVICE_KEY: ${{ secrets.GPLAY_SERVICE_ACCOUNT_KEY_JSON_BASE64 }}
run: |
TMP_SERVICEKEY_DIR="${RUNNER_TEMP}"/gplaykey
mkdir -p "${TMP_SERVICEKEY_DIR}"
TMP_SERVICEKEY_FILE_PATH="${TMP_SERVICEKEY_DIR}"/service_account.json
echo $ENCODED_SERVICE_KEY | base64 -di > "${TMP_SERVICEKEY_FILE_PATH}"
echo "SUPPLY_JSON_KEY=$(echo $TMP_SERVICEKEY_FILE_PATH)" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get the version
id: tagger
uses: jimschubert/query-tag-action@v2
with:
skip-unshallow: 'true'
abbrev: false
commit-ish: HEAD
- name: Install JDK ${{ matrix.java_version }}
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: 11
- name: Set up ruby env
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.6
bundler-cache: true
- name: Assemble beta and upload to Google Play
if: contains(steps.tagger.outputs.tag, '-beta')
run: bundle exec fastlane beta
env:
STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
BUGSNAG_API_KEY: ${{ secrets.BUGSNAG_API_KEY }}
- name: Assemble production and upload to Google Play
if: "!contains(steps.tagger.outputs.tag, '-beta')"
run: bundle exec fastlane production
env:
STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
BUGSNAG_API_KEY: ${{ secrets.BUGSNAG_API_KEY }}
+12
View File
@@ -2,3 +2,15 @@
.gradle
build/
/fastlane/report.xml
*.iml
local.properties
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
/.idea/**/*
!/.idea/codeStyles/
!/.idea/codeStyles/**/*
*.jks
.local/*
+28 -10
View File
@@ -1,24 +1,42 @@
# Privacy policy for the app `CAPod`
# Privacy policy
This is the privacy policy for the Android app "CAPod - Companion for AirPods".
* I do not collect personal information
* I do not sell, monetize or otherwise misappropriate any collected data.
## Preamble
CAPod respects your privacy.
Anonymous device information may be collected in the event of a crash (see [Automatic crash reports](#automatic-crash-reports)).
I do not collect, share or sell personal information.
Send a [quick mail](mailto:support@darken.eu) if you have questions.
My underlying privacy principle is the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule).
Send a [quick mail](mailto:support@darken.eu) if you have further questions.
## Location data
CAPod does not collect, share or sell location data.
Location permissions are required to receive Bluetooth Low Energy (BLE) data and ebale its core functionality.
The permission "access fine location" (`ACCESS_FINE_LOCATION`) and "access coarse location" (`ACCESS_COARSE_LOCATION`) are required to receive Bluetooth Low Energy data on Android 11 and lower.
On Android 12+ the newer and more fine grained `BLUETOOTH_SCAN` permission is used instead.
Bluetooth Low Energy is a technology that devices like AirPods use to communicate their status to nearby devices.
CAPod requests location permissions because these permissions are required to work with Bluetooth Low Energy data.
This is a privacy measure on Android's side because you could determine someones location by scanning for Bluetooth devices:
If you know the physical location of a Bluetooth device (e.g. AirTags) you could use Bluetooth data to calculate your position.
### Location access in the background
CAPod uses the "location access in the background" permission (`ACCESS_BACKGROUND_LOCATION`) on Android 11 and older to receive Bluetooth Low Energy data while the app is in the background. This permission enables the "Show popup" and "Autoconnect" features and allows CAPod to react to nearby devices whil the app is closed.
## Automatic crash reports
The app uses "Bugsnag" for automatic crash reports:
Anonymous device information may be collected in the event of an app crash or error.
To do this the app uses the service "Bugsnag":
https://www.bugsnag.com/
Bugsnags privacy policy can be found here:
Bugsnag's privacy policy can be found here:
https://docs.bugsnag.com/legal/privacy-policy/
Crash reports may contain device and app related information.
Crash reports may contain device and app related information, e.g. your phone model, Android version and app version.
You can disable automatic crash reports in the app's settings.
You can disable automatic reports in the app's settings.
+12 -10
View File
@@ -1,9 +1,10 @@
<img src="https://github.com/d4rken/capod/raw/main/.assets/banner.png" width="400">
<img src="https://github.com/d4rken-org/capod/raw/main/.assets/banner.png" width="400">
# Companion App for AirPods (CAPod)
![Build](https://github.com/d4rken/capod/actions/workflows/android.yml/badge.svg)
[![Github All Releases](https://img.shields.io/github/downloads/d4rken/capod/total.svg)](https://github.com/d4rken/capod/releases/latest)
[![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/d4rken-org/capod?include_prereleases)](https://github.com/d4rken-org/capod/releases/latest)
[![Code tests & eval](https://github.com/d4rken/capod/actions/workflows/code-checks.yml/badge.svg)](https://github.com/d4rken/capod/actions/workflows/code-checks.yml)
[![Crowdin](https://badges.crowdin.net/capod/localized.svg)](https://crowdin.com/project/capod)
[![Github All Releases](https://img.shields.io/github/downloads/d4rken-org/capod/total.svg)](https://github.com/d4rken-org/capod/releases/latest)
A companion app that adds support for AirPod specific features to Android:
@@ -19,8 +20,9 @@ CAPod is ad-free. Some additional features require an in-app purchase.
Currently supported models:
* AirPods Gen1
* AirPods Gen2
* AirPods 1. Generation
* AirPods 2. Generation
* AirPods 3. Generation
* AirPods Pro
* AirPods Max
* Power Beats Pro
@@ -33,22 +35,22 @@ Currently supported models:
## Download
* [Google Play](https://play.google.com/store/apps/details?id=eu.darken.capod)
* [GitHub](https://github.com/d4rken/capod/releases/latest)
* [GitHub](https://github.com/d4rken-org/capod/releases/latest)
## Support the project
* Buy the CAPod Pro In-App purchase on [Google Play](https://play.google.com/store/apps/details?id=eu.darken.capod)
* Help translate CAPod [on Crowdin](https://crowdin.com/project/capod)
* [Buy me a coffee](https://www.buymeacoffee.com/tydarken)
## Get help
* [Github Issues](https://github.com/d4rken/capod/issues)
* [Github Issues](https://github.com/d4rken-org/capod/issues)
* [Discord](https://discord.gg/vHubYPp)
* [Email](mailto:support@darken.eu)
## Screenshots
<img src="https://github.com/d4rken/capod/raw/main/.assets/screenshots/1.png" width="200"><img src="https://github.com/d4rken/capod/raw/main/.assets/screenshots/2.png" width="200"><img src="https://github.com/d4rken/capod/raw/main/.assets/screenshots/3.png" width="200"><img src="https://github.com/d4rken/capod/raw/main/.assets/screenshots/4.png" width="200">
<img src="https://github.com/d4rken-org/capod/raw/main/.assets/screenshots/1.png" width="200"><img src="https://github.com/d4rken-org/capod/raw/main/.assets/screenshots/2.png" width="200"><img src="https://github.com/d4rken-org/capod/raw/main/.assets/screenshots/3.png" width="200"><img src="https://github.com/d4rken-org/capod/raw/main/.assets/screenshots/4.png" width="200">
## Thanks to
+57 -28
View File
@@ -16,10 +16,6 @@ android {
compileSdkVersion buildConfig.compileSdk
Properties bugsnagProps = new Properties()
def bugsnagPropsFile = new File(System.properties['user.home'], ".appconfig/${packageName}/bugsnag.properties")
if (bugsnagPropsFile.canRead()) bugsnagProps.load(new FileInputStream(bugsnagPropsFile))
defaultConfig {
applicationId "${packageName}"
@@ -38,22 +34,55 @@ android {
}
signingConfigs {
release {}
releaseFoss {}
releaseGplay {}
}
def signingPropFile = new File(System.properties['user.home'], ".appconfig/${packageName}/signing.properties")
if (signingPropFile.canRead()) {
Properties signingProps = new Properties()
signingProps.load(new FileInputStream(signingPropFile))
signingConfigs {
release {
storeFile new File(signingProps['release.storePath'])
keyAlias signingProps['release.keyAlias']
storePassword signingProps['release.storePassword']
keyPassword signingProps['release.keyPassword']
signingConfigs {
releaseFoss {
def signingFossPropFile = new File(System.properties['user.home'], ".appconfig/${packageName}/signing-foss.properties")
Properties signingPropsFoss = new Properties()
if (signingFossPropFile.canRead()) signingPropsFoss.load(new FileInputStream(signingFossPropFile))
String keyStorePathFoss = System.getenv("STORE_PATH") ?: signingPropsFoss["release.storePath"]
File keyStoreFoss = keyStorePathFoss ? new File(keyStorePathFoss) : null
if (keyStoreFoss?.canRead()) {
storeFile keyStoreFoss
storePassword System.getenv("STORE_PASSWORD") ?: signingPropsFoss['release.storePassword']
keyAlias System.getenv("KEY_ALIAS") ?: signingPropsFoss['release.keyAlias']
keyPassword System.getenv("KEY_PASSWORD") ?: signingPropsFoss['release.keyPassword']
}
}
releaseGplay {
def signingGplayPropFile = new File(System.properties['user.home'], ".appconfig/${packageName}/signing-gplay.properties")
Properties signingPropsGplay = new Properties()
if (signingGplayPropFile.canRead()) signingPropsGplay.load(new FileInputStream(signingGplayPropFile))
String keyStorePathGplay = System.getenv("STORE_PATH") ?: signingPropsGplay["release.storePath"]
File keyStoreGplay = keyStorePathGplay ? new File(keyStorePathGplay) : null
if (keyStoreGplay?.canRead()) {
storeFile keyStoreGplay
storePassword System.getenv("STORE_PASSWORD") ?: signingPropsGplay['release.storePassword']
keyAlias System.getenv("KEY_ALIAS") ?: signingPropsGplay['release.keyAlias']
keyPassword System.getenv("KEY_PASSWORD") ?: signingPropsGplay['release.keyPassword']
}
}
}
flavorDimensions "version"
productFlavors {
foss {
signingConfig signingConfigs.releaseFoss
}
gplay {
signingConfig signingConfigs.releaseGplay
}
}
Properties bugsnagProps = new Properties()
def bugsnagPropsFile = new File(System.properties['user.home'], ".appconfig/${packageName}/bugsnag.properties")
if (bugsnagPropsFile.canRead()) bugsnagProps.load(new FileInputStream(bugsnagPropsFile))
String bugSnagApiKey = System.getenv("BUGSNAG_API_KEY") ?: bugsnagProps.getProperty("bugsnag.apikey", "")
buildTypes {
def proguardRulesRelease = fileTree(dir: "../proguard", include: ["*.pro"]).asList().toArray()
debug {
@@ -62,10 +91,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
proguardFiles proguardRulesRelease
proguardFiles 'proguard-rules-debug.pro'
manifestPlaceholders = [bugsnagApiKey: bugsnagProps.getProperty("bugsnag.apikey", "")]
manifestPlaceholders = [bugsnagApiKey: bugSnagApiKey]
}
release {
signingConfig signingConfigs.release
beta {
lintOptions {
abortOnError true
fatal 'StopShip'
@@ -74,17 +102,18 @@ android {
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
proguardFiles proguardRulesRelease
manifestPlaceholders = [bugsnagApiKey: bugsnagProps.getProperty("bugsnag.apikey", "")]
manifestPlaceholders = [bugsnagApiKey: bugSnagApiKey]
}
}
flavorDimensions "version"
productFlavors {
gplay {
}
foss {
release {
lintOptions {
abortOnError true
fatal 'StopShip'
}
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
proguardFiles proguardRulesRelease
manifestPlaceholders = [bugsnagApiKey: bugSnagApiKey]
}
}
@@ -40,7 +40,7 @@ class UpgradeControlFoss @Inject constructor(
upgradedAt = Instant.now(),
reason = FossUpgrade.Reason.DONATED
)
webpageTool.open("https://github.com/d4rken/capod")
webpageTool.open("https://github.com/d4rken-org/capod")
Toast.makeText(activity, R.string.general_thank_you_label, Toast.LENGTH_SHORT).show()
}
setNegativeButton(R.string.foss_upgrade_alreadydonated_label) { _, _ ->
@@ -6,10 +6,34 @@ import eu.darken.capod.BuildConfig
// Can't be const because that prevents them from being mocked in tests
@Suppress("MayBeConstant")
object BuildConfigWrap {
val FLAVOR: String = BuildConfig.FLAVOR
val BUILD_TYPE: String = BuildConfig.BUILD_TYPE
val DEBUG: Boolean = BuildConfig.DEBUG
val BUILD_TYPE: BuildType = when (val typ = BuildConfig.BUILD_TYPE) {
"debug" -> BuildType.DEV
"beta" -> BuildType.BETA
"release" -> BuildType.RELEASE
else -> throw IllegalArgumentException("Unknown buildtype: $typ")
}
enum class BuildType {
DEV,
BETA,
RELEASE,
;
}
val FLAVOR: Flavor = when (val flav = BuildConfig.FLAVOR) {
"gplay" -> Flavor.GPLAY
"foss" -> Flavor.FOSS
else -> throw IllegalStateException("Unknown flavor: $flav")
}
enum class Flavor {
GPLAY,
FOSS,
;
}
val APPLICATION_ID = BuildConfig.APPLICATION_ID
val VERSION_CODE: Long = BuildConfig.VERSION_CODE.toLong()
@@ -1,5 +1,5 @@
package eu.darken.capod.common
object PrivacyPolicy {
const val URL = "https://raw.githubusercontent.com/d4rken/capod-public/main/PRIVACY_POLICY.md"
const val URL = "https://raw.githubusercontent.com/d4rken-org/capod/main/PRIVACY_POLICY.md"
}
@@ -28,12 +28,12 @@ class AutoReporting @Inject constructor(
) {
fun setup() {
val isEnabled = debugSettings.isAutoReportEnabled.value
val isEnabled = debugSettings.isAutoReportingEnabled.value
log(TAG) { "setup(): isEnabled=$isEnabled" }
try {
val bugsnagConfig = Configuration.load(context).apply {
if (debugSettings.isAutoReportEnabled.value) {
if (debugSettings.isAutoReportingEnabled.value) {
Logging.install(bugsnagLogger.get())
setUser(installId.id, null, null)
autoTrackSessions = true
@@ -4,6 +4,7 @@ import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import eu.darken.capod.common.BuildConfigWrap
import eu.darken.capod.common.preferences.PreferenceStoreMapper
import eu.darken.capod.common.preferences.Settings
import eu.darken.capod.common.preferences.createFlowPreference
@@ -17,8 +18,11 @@ class DebugSettings @Inject constructor(
override val preferences: SharedPreferences = context.getSharedPreferences("settings_debug", Context.MODE_PRIVATE)
val isAutoReportEnabled = preferences.createFlowPreference("debug.bugreport.automatic.enabled", true)
val isAutoReportingEnabled = preferences.createFlowPreference(
key = "debug.bugreport.automatic.enabled",
// Reporting is opt-out for gplay, and opt-in for github builds
defaultValue = BuildConfigWrap.FLAVOR == BuildConfigWrap.Flavor.GPLAY
)
val isDebugModeEnabled = preferences.createFlowPreference("debug.mode.enabled", false)
val showFakeData = preferences.createFlowPreference("debug.fakedata.enabled", false)
@@ -32,7 +32,7 @@ class BugsnagErrorHandler @Inject constructor(
context.tryFormattedSignature()?.let { event.addMetadata(tab, "signatures", it) }
}
return debugSettings.isAutoReportEnabled.value && !BuildConfigWrap.DEBUG
return debugSettings.isAutoReportingEnabled.value && !BuildConfigWrap.DEBUG
}
companion object {
@@ -90,7 +90,7 @@ class RecorderModule @Inject constructor(
private fun createRecordingFilePath() = File(
File(context.cacheDir, "debug/logs"),
"bb_logfile_${System.currentTimeMillis()}.log"
"capod_logfile_${System.currentTimeMillis()}.log"
)
suspend fun startRecorder(): File {
@@ -123,6 +123,6 @@ class RecorderModule @Inject constructor(
companion object {
internal val TAG = logTag("Debug", "Log", "Recorder", "Module")
private const val FORCE_FILE = "bb_force_debug_run"
private const val FORCE_FILE = "capod_force_debug_run"
}
}
@@ -67,6 +67,6 @@ class GeneralSettings @Inject constructor(
showAll,
minimumSignalQuality,
mainDeviceAddress,
debugSettings.isAutoReportEnabled,
debugSettings.isAutoReportingEnabled,
)
}
@@ -34,6 +34,7 @@ class DebugSettingsFragment : PreferenceFragment2() {
vm.toggleRecorder()
true
}
super.onViewCreated(view, savedInstanceState)
}
@@ -3,10 +3,15 @@ package eu.darken.capod.main.ui.settings.general.debug
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.debug.autoreport.DebugSettings
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.debug.recording.core.RecorderModule
import eu.darken.capod.common.uix.ViewModel3
import eu.darken.capod.main.core.GeneralSettings
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
@HiltViewModel
@@ -14,10 +19,24 @@ class DebugSettingsFragmentVM @Inject constructor(
private val handle: SavedStateHandle,
dispatcherProvider: DispatcherProvider,
private val recorderModule: RecorderModule,
private val generalSettings: GeneralSettings,
private val debugSettings: DebugSettings,
) : ViewModel3(dispatcherProvider) {
val state = recorderModule.state.asLiveData2()
init {
debugSettings.showUnfiltered.flow
.distinctUntilChanged()
.onEach { showUnfiltered ->
if (showUnfiltered) {
log(TAG) { "Enabling 'show all' due to debug setting 'show unfiltered' enabled" }
generalSettings.showAll.value = true
}
}
.launchInViewModel()
}
fun toggleRecorder() = launch {
if (recorderModule.state.first().isRecording) {
recorderModule.stopRecorder()
@@ -15,9 +15,9 @@ import javax.inject.Inject
@HiltViewModel
class SupportFragmentVM @Inject constructor(
private val handle: SavedStateHandle,
private val dispatcherProvider: DispatcherProvider,
private val emailTool: EmailTool,
private val installId: InstallId,
private val dispatcherProvider: DispatcherProvider,
) : ViewModel3(dispatcherProvider) {
val emailEvent = SingleLiveEvent<Intent>()
@@ -6,5 +6,5 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M20.38,8.53C20.54,8.13 21.06,6.54 20.21,4.39C20.21,4.39 18.9,4 15.91,6C14.66,5.67 13.33,5.62 12,5.62C10.68,5.62 9.34,5.67 8.09,6C5.1,3.97 3.79,4.39 3.79,4.39C2.94,6.54 3.46,8.13 3.63,8.53C2.61,9.62 2,11 2,12.72C2,19.16 6.16,20.61 12,20.61C17.79,20.61 22,19.16 22,12.72C22,11 21.39,9.62 20.38,8.53M12,19.38C7.88,19.38 4.53,19.19 4.53,15.19C4.53,14.24 5,13.34 5.8,12.61C7.14,11.38 9.43,12.03 12,12.03C14.59,12.03 16.85,11.38 18.2,12.61C19,13.34 19.5,14.23 19.5,15.19C19.5,19.18 16.13,19.38 12,19.38M8.86,13.12C8.04,13.12 7.36,14.12 7.36,15.34C7.36,16.57 8.04,17.58 8.86,17.58C9.69,17.58 10.36,16.58 10.36,15.34C10.36,14.11 9.69,13.12 8.86,13.12M15.14,13.12C14.31,13.12 13.64,14.11 13.64,15.34C13.64,16.58 14.31,17.58 15.14,17.58C15.96,17.58 16.64,16.58 16.64,15.34C16.64,14.11 16,13.12 15.14,13.12Z" />
android:pathData="M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z" />
</vector>
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M20.38,8.53C20.54,8.13 21.06,6.54 20.21,4.39C20.21,4.39 18.9,4 15.91,6C14.66,5.67 13.33,5.62 12,5.62C10.68,5.62 9.34,5.67 8.09,6C5.1,3.97 3.79,4.39 3.79,4.39C2.94,6.54 3.46,8.13 3.63,8.53C2.61,9.62 2,11 2,12.72C2,19.16 6.16,20.61 12,20.61C17.79,20.61 22,19.16 22,12.72C22,11 21.39,9.62 20.38,8.53M12,19.38C7.88,19.38 4.53,19.19 4.53,15.19C4.53,14.24 5,13.34 5.8,12.61C7.14,11.38 9.43,12.03 12,12.03C14.59,12.03 16.85,11.38 18.2,12.61C19,13.34 19.5,14.23 19.5,15.19C19.5,19.18 16.13,19.38 12,19.38M8.86,13.12C8.04,13.12 7.36,14.12 7.36,15.34C7.36,16.57 8.04,17.58 8.86,17.58C9.69,17.58 10.36,16.58 10.36,15.34C10.36,14.11 9.69,13.12 8.86,13.12M15.14,13.12C14.31,13.12 13.64,14.11 13.64,15.34C13.64,16.58 14.31,17.58 15.14,17.58C15.96,17.58 16.64,16.58 16.64,15.34C16.64,14.11 16,13.12 15.14,13.12Z" />
</vector>
@@ -18,12 +18,12 @@
<ImageView
android:id="@+id/pod_left_icon"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_airpod_left_24" />
<TextView
android:id="@+id/pod_left_label"
style="@style/TextAppearance.Compat.Notification.Title"
style="@style/PodInfoItemText.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -31,12 +31,12 @@
<ImageView
android:id="@+id/pod_left_charging"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
android:id="@+id/pod_left_ear"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -52,12 +52,12 @@
<ImageView
android:id="@+id/pod_case_icon"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_airpod_case_24" />
<TextView
android:id="@+id/pod_case_label"
style="@style/TextAppearance.Compat.Notification.Title"
style="@style/PodInfoItemText.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -65,7 +65,7 @@
<ImageView
android:id="@+id/pod_case_charging"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_power_24" />
</LinearLayout>
@@ -81,12 +81,12 @@
<ImageView
android:id="@+id/pod_right_icon"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_airpod_right_24" />
<TextView
android:id="@+id/pod_right_label"
style="@style/TextAppearance.Compat.Notification.Title"
style="@style/PodInfoItemText.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -94,12 +94,12 @@
<ImageView
android:id="@+id/pod_right_charging"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
android:id="@+id/pod_right_ear"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -7,7 +7,7 @@
<TextView
android:id="@+id/headphones_label"
style="@style/TextAppearance.Compat.Notification.Title"
style="@style/PodInfoItemText.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
@@ -21,12 +21,12 @@
<ImageView
android:id="@+id/headphones_battery_icon"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_battery_unknown_24" />
<TextView
android:id="@+id/headphones_battery_label"
style="@style/TextAppearance.Compat.Notification.Title"
style="@style/PodInfoItemText.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -35,12 +35,12 @@
<ImageView
android:id="@+id/headphones_charging"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_power_24" />
<ImageView
android:id="@+id/headphones_worn"
style="@style/PodInfoItemIcon"
style="@style/PodInfoItemIcon.Notification"
android:src="@drawable/ic_baseline_hearing_24" />
</LinearLayout>
@@ -6,7 +6,7 @@
<TextView
android:id="@+id/device"
style="@style/TextAppearance.Compat.Notification.Title"
style="@style/PodInfoItemText.Notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
+1 -1
View File
@@ -135,5 +135,5 @@
<string name="settings_compatibility_mode_label">Kompatibilitätsmodus</string>
<string name="settings_compatibility_mode_description">Deaktivieren Sie Optimierungen, um die Kompatibilität zu verbessern. Versuchen Sie dies, wenn Sie keine Daten sehen.</string>
<string name="translators_thanks_title">Übersetzer</string>
<string name="translators_thanks_description" comment="translators_thanks_description&#10;&#10;You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings&gt;Acknowledgements&gt;Thank you section.&#10;&#10;Separate names by semicolons and an optional email may be included in brackets, example:&#10;&#10;darken(darken@darken.eu);John Doe(john@example.com)&#10;&#10;&quot;darken&quot; is just a placeholder and does not have to be kept if/when you add yours.&#10;&#10;Be nice to each other!">darken</string>
<string name="translators_thanks_description" comment="translators_thanks_description&#10;&#10;You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings&gt;Acknowledgements&gt;Thank you section.&#10;&#10;Separate names by semicolons and an optional email may be included in brackets, example:&#10;&#10;darken(darken@darken.eu);John Doe(john@example.com)&#10;&#10;&quot;darken&quot; is just a placeholder and does not have to be kept if/when you add yours.&#10;&#10;Be nice to each other!">Gamechanger181</string>
</resources>
+10
View File
@@ -134,4 +134,14 @@
<string name="permission_required_title">Izin berikut diperlukan:</string>
<string name="settings_compatibility_mode_label">Mode kompatibilitas</string>
<string name="settings_compatibility_mode_description">Nonaktifkan pengoptimalan untuk meningkatkan kompatibilitas. Coba ini jika anda tidak melihat data apa pun.</string>
<string name="translators_thanks_title">Penerjemah</string>
<string name="translators_thanks_description" comment="translators_thanks_description&#10;&#10;You can voluntarily add your name here to have it displayed in the app. It will be shown in the Settings&gt;Acknowledgements&gt;Thank you section.&#10;&#10;Separate names by semicolons and an optional email may be included in brackets, example:&#10;&#10;darken(darken@darken.eu);John Doe(john@example.com)&#10;&#10;&quot;darken&quot; is just a placeholder and does not have to be kept if/when you add yours.&#10;&#10;Be nice to each other!">nama anda dapat ditambahkan sebagai relawan di sini dan ditampilkan di aplikasi. Itu akan ditampilkan pada bagian Pengaturan>Penghargaan>Terima kasih
Pisahkan nama dengan titik koma dan email opsional dapat dimasukkan dalam tanda kurung, contoh:
𝓼𝓾𝓵𝓽𝓪𝓷 𝓱𝓪𝓶𝓴𝓪(sultanhamka@gmail.com); John Doe(john@example.com)
\"𝓼𝓾𝓵𝓽𝓪𝓷 𝓱𝓪𝓶𝓴𝓪\" hanyalah pengganti dan tidak harus disimpan jika/ketika anda menambahkan milik anda.
Bersikap baik satu sama lain!</string>
</resources>
+11 -1
View File
@@ -7,7 +7,17 @@
<item name="android:layout_marginEnd">8dp</item>
</style>
<style name="PodInfoItemIcon">
<style name="PodInfoItemIcon.Notification" parent="TextAppearance.Compat.Notification.Title">
<item name="android:layout_height">20dp</item>
<item name="android:layout_width">20dp</item>
</style>
<style name="PodInfoItemText.Notification" parent="TextAppearance.Compat.Notification.Title">
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>
<style name="PodInfoItemIcon" parent="TextAppearance.MaterialComponents.Body2">
<item name="android:layout_height">20dp</item>
<item name="android:layout_width">20dp</item>
</style>
@@ -50,13 +50,6 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/settings_category_other_label">
<CheckBoxPreference
android:icon="@drawable/ic_spider_thread_onsurface"
android:key="debug.bugreport.automatic.enabled"
android:summary="@string/settings_debug_autoreports_description"
android:title="@string/settings_debug_autoreports_label" />
<Preference
android:fragment="eu.darken.capod.main.ui.settings.general.debug.DebugSettingsFragment"
android:icon="@drawable/ic_baseline_bug_report_24"
+1 -1
View File
@@ -27,7 +27,7 @@
app:summary="v?.?.?">
<intent
android:action="android.intent.action.VIEW"
android:data="https://github.com/d4rken/capod-public/releases/latest" />
android:data="https://github.com/d4rken-org/capod/releases/latest" />
</Preference>
<Preference
+7 -1
View File
@@ -8,7 +8,7 @@
android:title="@string/issue_tracker_label">
<intent
android:action="android.intent.action.VIEW"
android:data="https://github.com/d4rken/capod-public/issues" />
android:data="https://github.com/d4rken-org/capod/issues" />
</Preference>
<Preference
android:icon="@drawable/ic_discord_onsurface"
@@ -30,5 +30,11 @@
android:key="support.installid"
android:summary="@string/settings_support_installid_desc"
android:title="@string/settings_support_installid_label" />
<CheckBoxPreference
android:icon="@drawable/ic_spider_thread_onsurface"
android:key="debug.bugreport.automatic.enabled"
android:summary="@string/settings_debug_autoreports_description"
android:title="@string/settings_debug_autoreports_label" />
</PreferenceCategory>
</PreferenceScreen>
+1 -1
View File
@@ -8,7 +8,7 @@ buildscript {
'version' : [
'major': 1,
'minor': 3,
'patch': 10,
'patch': 13,
'build': 0,
],
]
+2 -2
View File
@@ -1,2 +1,2 @@
json_key_file "~/.fastlaneconfig/androiddev-console-darken_development-4f6965ff0eda.json" # Path to the json secret file - Follow https://github.com/fastlane/supply#setup to get one
package_name "eu.darken.capod" # e.g. com.krausefx.app
json_key_file "~/.appconfig/eu.darken.capod/gplay-capod-ci_api.json"
package_name "eu.darken.capod"
+21 -9
View File
@@ -11,7 +11,7 @@
# This is the minimum version number required.
# Update this, if you use features of a newer version
fastlane_version "2.204.3"
fastlane_version "2.175.0"
default_platform :android
@@ -21,17 +21,29 @@ platform :android do
end
lane :beta do
ensure_git_branch(branch: 'dev')
git_pull
gradle(task: 'clean assembleRelease')
supply(track: 'beta')
gradle(task: 'clean assembleGplayBeta')
sh "bash ./remove_unsupported_languages.sh"
supply(
track: 'beta',
skip_upload_changelogs: 'false',
skip_upload_images: 'true',
skip_upload_screenshots: 'true',
skip_upload_aab: 'true',
skip_upload_metadata: 'true',
)
end
lane :production do
ensure_git_branch(branch: 'master')
git_pull
gradle(task: 'clean assembleRelease')
supply(track: 'rollout', rollout: '0.1')
gradle(task: 'clean assembleGplayRelease')
sh "bash ./remove_unsupported_languages.sh"
supply(
track: 'beta',
skip_upload_changelogs: 'false',
skip_upload_images: 'true',
skip_upload_screenshots: 'true',
skip_upload_aab: 'true',
skip_upload_metadata: 'true',
)
end
lane :listing_only do
+1
View File
@@ -11,5 +11,6 @@ rm -rv ./metadata/android/ku-TR
rm -rv ./metadata/android/kmr-TR
rm -rv ./metadata/android/ur-IN
rm -rv ./metadata/android/zu
rm -rv ./metadata/android/si-LK
find ./metadata/android -empty -type d -delete
exit 0
-10
View File
@@ -1,10 +0,0 @@
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=/home/darken/Android/sdk