diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 000000000..e7f4b7717
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,20 @@
+name: Linting
+
+on:
+ pull_request:
+
+jobs:
+ analyse:
+ name: Analyse
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - uses: actions/setup-java@v4
+ with:
+ distribution: 'zulu'
+ java-version: '17'
+
+ - run: ./gradlew lint
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 000000000..5ef567ec5
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,43 @@
+#https://github.com/marketplace/actions/android-emulator-runner
+name: Test
+on:
+ pull_request:
+
+jobs:
+ test:
+ timeout-minutes: 45
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+
+ - uses: actions/setup-java@v4
+ with:
+ distribution: 'adopt'
+ java-version: '17'
+
+ - name: Enable KVM group perms
+ run: |
+ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
+ sudo udevadm control --reload-rules
+ sudo udevadm trigger --name-match=kvm
+
+ - uses: gradle/actions/setup-gradle@v3
+
+ - name: run tests
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ arch: x86_64
+ api-level: 34
+ script: ./gradlew connectedWithMapsWithAnalyticsForPlayDebugAndroidTest
+ env:
+ API_LEVEL: 34
+
+ - name: Archive
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: code-coverage-report
+ path: build/reports/androidTests/
+ retention-days: 7
+
diff --git a/android/build.gradle b/android/build.gradle
index 3378ffb18..8b78b0483 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -5,7 +5,6 @@ apply plugin: 'kotlin-kapt'
apply plugin: 'de.mobilej.unmock'
repositories {
- jcenter()
mavenCentral()
google()
maven { url 'https://www.jitpack.io' }
@@ -13,12 +12,12 @@ repositories {
android {
- compileSdkVersion 33
+ compileSdkVersion 35
defaultConfig {
versionCode 373
versionName "3.7.3"
- minSdkVersion 14
+ minSdkVersion 23
targetSdkVersion 33
applicationId "org.ligi.passandroid"
namespace "org.ligi.passandroid"
@@ -90,6 +89,7 @@ android {
warning 'MissingTranslation'
warning 'InvalidPackage'
disable "NullSafeMutableLiveData"
+ baseline file("lint-baseline.xml")
}
buildTypes {
@@ -106,15 +106,17 @@ android {
buildFeatures {
viewBinding true
+ buildConfig true
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = JavaVersion.VERSION_1_8.toString()
+ jvmTarget = JavaVersion.VERSION_17.toString()
}
+ namespace 'org.ligi.passandroid'
}
dependencies {
@@ -180,7 +182,7 @@ dependencies {
implementation 'com.larswerkman:HoloColorPicker:1.5'
implementation 'com.google.code.findbugs:jsr305:3.0.2'
- implementation 'com.squareup.okio:okio:3.3.0'
+ implementation 'com.squareup.okio:okio:3.6.0'
implementation 'com.squareup.moshi:moshi:1.15.0'
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.15.0"
diff --git a/android/lint-baseline.xml b/android/lint-baseline.xml
new file mode 100644
index 000000000..2aa688377
--- /dev/null
+++ b/android/lint-baseline.xml
@@ -0,0 +1,5043 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/src/debug/AndroidManifest.xml b/android/src/debug/AndroidManifest.xml
index 7da48e7e9..3280118c3 100644
--- a/android/src/debug/AndroidManifest.xml
+++ b/android/src/debug/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/android/src/main/java/org/ligi/passandroid/ui/PassListActivity.kt b/android/src/main/java/org/ligi/passandroid/ui/PassListActivity.kt
index 2ca88a392..64ef7bcca 100644
--- a/android/src/main/java/org/ligi/passandroid/ui/PassListActivity.kt
+++ b/android/src/main/java/org/ligi/passandroid/ui/PassListActivity.kt
@@ -12,9 +12,13 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View.GONE
import android.view.View.VISIBLE
+import android.view.ViewGroup
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.core.view.GravityCompat
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.viewpager.widget.ViewPager
import com.google.android.material.snackbar.Snackbar
diff --git a/android/src/main/java/org/ligi/passandroid/ui/PassViewActivity.kt b/android/src/main/java/org/ligi/passandroid/ui/PassViewActivity.kt
index cfa2cb0e5..36d18be5f 100644
--- a/android/src/main/java/org/ligi/passandroid/ui/PassViewActivity.kt
+++ b/android/src/main/java/org/ligi/passandroid/ui/PassViewActivity.kt
@@ -34,7 +34,7 @@ class PassViewActivity : PassViewActivityBase() {
}
disableRotation()
- setContentView(R.layout.activity_pass_view)
+ setContentView(R.layout.activity_pass_view_base)
pagerAdapter = CollectionPagerAdapter(this, PassStoreProjection(passStore,
passStore.classifier.getTopic(currentPass, ""),
diff --git a/android/src/main/java/org/ligi/passandroid/ui/PreferenceActivity.kt b/android/src/main/java/org/ligi/passandroid/ui/PreferenceActivity.kt
index a6fd059fd..d3adb20e9 100644
--- a/android/src/main/java/org/ligi/passandroid/ui/PreferenceActivity.kt
+++ b/android/src/main/java/org/ligi/passandroid/ui/PreferenceActivity.kt
@@ -1,9 +1,17 @@
package org.ligi.passandroid.ui
import android.annotation.SuppressLint
+import android.content.Context
import android.os.Bundle
+import android.util.AttributeSet
+import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updateLayoutParams
import org.ligi.passandroid.R
class PreferenceActivity : AppCompatActivity() {
@@ -27,3 +35,5 @@ class PreferenceActivity : AppCompatActivity() {
}
}
+
+
diff --git a/android/src/main/java/org/ligi/passandroid/ui/PrefsFragment.kt b/android/src/main/java/org/ligi/passandroid/ui/PrefsFragment.kt
index 8faefdae2..51844d04d 100644
--- a/android/src/main/java/org/ligi/passandroid/ui/PrefsFragment.kt
+++ b/android/src/main/java/org/ligi/passandroid/ui/PrefsFragment.kt
@@ -1,16 +1,13 @@
package org.ligi.passandroid.ui
-import android.Manifest
import android.content.SharedPreferences
import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate
-import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_AUTO
import androidx.core.app.ActivityCompat
import androidx.preference.PreferenceFragmentCompat
import org.koin.android.ext.android.inject
import org.ligi.passandroid.R
import org.ligi.passandroid.model.Settings
-import permissions.dispatcher.ktx.constructPermissionsRequest
class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener {
@@ -26,7 +23,7 @@ class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPref
preferenceScreen.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this)
}
- override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
+ override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == getString(R.string.preference_key_nightmode)) {
@AppCompatDelegate.NightMode val nightMode = settings.getNightMode()
@@ -40,4 +37,5 @@ class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPref
setPreferencesFromResource(R.xml.preferences, rootKey)
}
+
}
diff --git a/android/src/main/res/layout/activity_help.xml b/android/src/main/res/layout/activity_help.xml
index 01f1839ae..96bd7842b 100644
--- a/android/src/main/res/layout/activity_help.xml
+++ b/android/src/main/res/layout/activity_help.xml
@@ -8,6 +8,7 @@
diff --git a/android/src/main/res/layout/activity_pass_view_base.xml b/android/src/main/res/layout/activity_pass_view_base.xml
index 667aedbac..d689487b2 100644
--- a/android/src/main/res/layout/activity_pass_view_base.xml
+++ b/android/src/main/res/layout/activity_pass_view_base.xml
@@ -1,4 +1,8 @@
+
@@ -29,3 +34,4 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
+
diff --git a/android/src/main/res/layout/pass_list.xml b/android/src/main/res/layout/pass_list.xml
index 1c7fb1224..37d95052a 100644
--- a/android/src/main/res/layout/pass_list.xml
+++ b/android/src/main/res/layout/pass_list.xml
@@ -14,6 +14,7 @@
diff --git a/android/src/withMaps/AndroidManifest.xml b/android/src/withMaps/AndroidManifest.xml
index 80489319e..ee6fe730b 100644
--- a/android/src/withMaps/AndroidManifest.xml
+++ b/android/src/withMaps/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
diff --git a/backend/build.gradle b/backend/build.gradle
index 1c1154134..fcbaefaae 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -22,6 +22,6 @@ dependencies {
implementation 'com.google.appengine:appengine-endpoints:1.9.86'
implementation 'com.google.appengine:appengine-endpoints-deps:1.9.83'
implementation 'javax.servlet:javax.servlet-api:4.0.1'
- implementation 'com.googlecode.objectify:objectify:6.0.7'
+ implementation 'com.googlecode.objectify:objectify:6.1.0'
implementation 'com.ganyo:gcm-server:1.1.0'
}
diff --git a/build.gradle b/build.gradle
index 649b28798..1742b8179 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.android.tools.build:gradle:7.4.2'
+ classpath 'com.android.tools.build:gradle:8.5.2'
classpath 'com.trevjonez.composer:plugin:1.0.0-rc08'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.47.0'
classpath 'com.github.bjoernq:unmockplugin:0.7.9'
diff --git a/gradle.properties b/gradle.properties
index 16d0a03e8..bb8369bfe 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,5 @@
android.enableJetifier=true
+android.nonFinalResIds=false
+android.nonTransitiveRClass=false
android.useAndroidX=true
-org.gradle.jvmargs=-Xms128m -Xmx1024m
\ No newline at end of file
+org.gradle.jvmargs=-Xms128m -Xmx2048m
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e8be595e3..bb6c19194 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists