diff --git a/app/build.gradle b/app/build.gradle
index caa723a8a..43592c3ea 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -39,7 +39,7 @@ android {
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
minSdkVersion 23
//noinspection ExpiredTargetSdkVersion
- targetSdkVersion 29
+ targetSdkVersion 30
/*
The Android Testing Support Library collects analytics to continuously improve the testing
experience. More specifically, it uploads a hash of the package name of the application
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java b/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java
index 5f6ada3ad..0d9097ebd 100644
--- a/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java
+++ b/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java
@@ -219,28 +219,9 @@ public class MainActivityEspressoTest {
onView(withText(R.string.main_menu__updates)).check(matches(isDisplayed()));
}
- @LargeTest
- @Test
- public void startSwap() {
- if (!BuildConfig.FLAVOR.startsWith("full")) {
- return;
- }
- ViewInteraction nearbyBottonNavButton = onView(
- allOf(withText(R.string.main_menu__swap_nearby), isDisplayed()));
- nearbyBottonNavButton.perform(click());
- ViewInteraction findPeopleButton = onView(
- allOf(withId(R.id.find_people_button), withText(R.string.nearby_splash__find_people_button),
- isDisplayed()));
- findPeopleButton.perform(click());
- onView(withText(R.string.swap_send_fdroid)).check(matches(isDisplayed()));
- }
-
@LargeTest
@Test
public void showCategories() {
- if (!BuildConfig.FLAVOR.startsWith("full")) {
- return;
- }
onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
onView(allOf(withText(R.string.main_menu__categories), isDisplayed())).perform(click());
onView(allOf(withId(R.id.swipe_to_refresh), isDisplayed()))
@@ -264,9 +245,6 @@ public class MainActivityEspressoTest {
@LargeTest
@Test
public void showLatest() {
- if (!BuildConfig.FLAVOR.startsWith("full")) {
- return;
- }
onView(Matchers.instanceOf(StatusBanner.class)).check(matches(not(isDisplayed())));
onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click());
@@ -289,9 +267,6 @@ public class MainActivityEspressoTest {
public void showSearch() {
onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
onView(withId(R.id.fab_search)).check(doesNotExist());
- if (!BuildConfig.FLAVOR.startsWith("full")) {
- return;
- }
onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click());
onView(allOf(withId(R.id.fab_search), isDisplayed())).perform(click());
onView(withId(R.id.sort)).check(matches(isDisplayed()));
@@ -300,4 +275,4 @@ public class MainActivityEspressoTest {
.perform(typeText("test"));
onView(allOf(withId(R.id.sort), isDisplayed())).perform(click());
}
-}
\ No newline at end of file
+}
diff --git a/app/src/androidTest/proguard-rules.pro b/app/src/androidTest/proguard-rules.pro
index 6331efee6..4f9d494bc 100644
--- a/app/src/androidTest/proguard-rules.pro
+++ b/app/src/androidTest/proguard-rules.pro
@@ -1,6 +1,7 @@
-dontoptimize
-dontwarn
-dontobfuscate
+-dontshrink
-dontwarn android.test.**
-dontwarn android.support.test.**
diff --git a/app/src/androidTestFull/java/org/fdroid/fdroid/MainActivityEspressoTestFull.java b/app/src/androidTestFull/java/org/fdroid/fdroid/MainActivityEspressoTestFull.java
new file mode 100644
index 000000000..56ab7e5f4
--- /dev/null
+++ b/app/src/androidTestFull/java/org/fdroid/fdroid/MainActivityEspressoTestFull.java
@@ -0,0 +1,303 @@
+package org.fdroid.fdroid;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.swipeDown;
+import static androidx.test.espresso.action.ViewActions.swipeLeft;
+import static androidx.test.espresso.action.ViewActions.swipeRight;
+import static androidx.test.espresso.action.ViewActions.swipeUp;
+import static androidx.test.espresso.action.ViewActions.typeText;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Build;
+import android.util.Log;
+
+import androidx.core.content.ContextCompat;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.espresso.IdlingPolicies;
+import androidx.test.espresso.ViewInteraction;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.rule.GrantPermissionRule;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject;
+import androidx.test.uiautomator.UiObjectNotFoundException;
+import androidx.test.uiautomator.UiSelector;
+
+import org.fdroid.fdroid.views.StatusBanner;
+import org.fdroid.fdroid.views.main.MainActivity;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class MainActivityEspressoTestFull {
+ public static final String TAG = "MainActivityEspressoTestFull";
+
+ /**
+ * Emulators older than {@code android-25} seem to fail at running Espresso tests.
+ *
+ * ARM emulators are too slow to run these tests in a useful way. The sad
+ * thing is that it would probably work if Android didn't put up the ANR
+ * "Process system isn't responding" on boot each time. There seems to be no
+ * way to increase the ANR timeout.
+ */
+ private static boolean canRunEspresso() {
+ if (Build.VERSION.SDK_INT < 25
+ || Build.SUPPORTED_ABIS[0].startsWith("arm") && isEmulator()) {
+ Log.e(TAG, "SKIPPING TEST: ARM emulators are too slow to run these tests in a useful way");
+ return false;
+ }
+ return true;
+ }
+
+ @BeforeClass
+ public static void classSetUp() {
+ IdlingPolicies.setIdlingResourceTimeout(10, TimeUnit.MINUTES);
+ IdlingPolicies.setMasterPolicyTimeout(10, TimeUnit.MINUTES);
+ if (!canRunEspresso()) {
+ return;
+ }
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ try {
+ UiDevice.getInstance(instrumentation)
+ .executeShellCommand("pm grant "
+ + instrumentation.getTargetContext().getPackageName()
+ + " android.permission.SET_ANIMATION_SCALE");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ SystemAnimations.disableAll(ApplicationProvider.getApplicationContext());
+
+ // dismiss the ANR or any other system dialogs that might be there
+ UiObject button = new UiObject(new UiSelector().text("Wait").enabled(true));
+ try {
+ button.click();
+ } catch (UiObjectNotFoundException e) {
+ Log.d(TAG, e.getLocalizedMessage());
+ }
+ new UiWatchers().registerAnrAndCrashWatchers();
+
+ Context context = instrumentation.getTargetContext();
+ ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
+ ActivityManager activityManager = ContextCompat.getSystemService(context, ActivityManager.class);
+ activityManager.getMemoryInfo(mi);
+ long percentAvail = mi.availMem / mi.totalMem;
+ Log.i(TAG, "RAM: " + mi.availMem + " / " + mi.totalMem + " = " + percentAvail);
+ }
+
+ @AfterClass
+ public static void classTearDown() {
+ SystemAnimations.enableAll(ApplicationProvider.getApplicationContext());
+ }
+
+ public static boolean isEmulator() {
+ return Build.FINGERPRINT.startsWith("generic")
+ || Build.FINGERPRINT.startsWith("unknown")
+ || Build.MODEL.contains("google_sdk")
+ || Build.MODEL.contains("Emulator")
+ || Build.MODEL.contains("Android SDK built for x86")
+ || Build.MANUFACTURER.contains("Genymotion")
+ || Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
+ || "google_sdk".equals(Build.PRODUCT);
+ }
+
+ @Before
+ public void setUp() {
+ assumeTrue(canRunEspresso());
+ }
+
+ /**
+ * Placate {@link android.os.StrictMode}
+ *
+ * @see Run finalizers before counting for StrictMode
+ */
+ @After
+ public void tearDown() {
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ }
+
+ @Rule
+ public ActivityTestRule activityTestRule =
+ new ActivityTestRule<>(MainActivity.class);
+
+ @Rule
+ public GrantPermissionRule accessCoarseLocationPermissionRule = GrantPermissionRule.grant(
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+
+ @Rule
+ public GrantPermissionRule readExternalStoragePermissionRule = GrantPermissionRule.grant(
+ Manifest.permission.READ_EXTERNAL_STORAGE);
+
+ @Test
+ public void bottomNavFlavorCheck() {
+ onView(withText(R.string.main_menu__updates)).check(matches(isDisplayed()));
+ onView(withText(R.string.menu_settings)).check(matches(isDisplayed()));
+ onView(withText("THIS SHOULD NOT SHOW UP ANYWHERE!!!")).check(doesNotExist());
+
+ assertTrue(BuildConfig.FLAVOR.startsWith("full") || BuildConfig.FLAVOR.startsWith("basic"));
+
+ if (BuildConfig.FLAVOR.startsWith("basic")) {
+ onView(withText(R.string.main_menu__latest_apps)).check(matches(isDisplayed()));
+ onView(withText(R.string.main_menu__categories)).check(doesNotExist());
+ onView(withText(R.string.main_menu__swap_nearby)).check(doesNotExist());
+ }
+
+ if (BuildConfig.FLAVOR.startsWith("full")) {
+ onView(withText(R.string.main_menu__latest_apps)).check(matches(isDisplayed()));
+ onView(withText(R.string.main_menu__categories)).check(matches(isDisplayed()));
+ onView(withText(R.string.main_menu__swap_nearby)).check(matches(isDisplayed()));
+ }
+ }
+
+ @LargeTest
+ @Test
+ public void showSettings() {
+ ViewInteraction settingsBottonNavButton = onView(
+ allOf(withText(R.string.menu_settings), isDisplayed()));
+ settingsBottonNavButton.perform(click());
+ onView(withText(R.string.preference_manage_installed_apps)).check(matches(isDisplayed()));
+ if (BuildConfig.FLAVOR.startsWith("basic") && BuildConfig.APPLICATION_ID.endsWith(".debug")) {
+ // TODO fix me by sorting out the flavor applicationId for debug builds in app/build.gradle
+ Log.i(TAG, "Skipping the remainder of showSettings test because it just crashes on basic .debug builds");
+ return;
+ }
+ ViewInteraction manageInstalledAppsButton = onView(
+ allOf(withText(R.string.preference_manage_installed_apps), isDisplayed()));
+ manageInstalledAppsButton.perform(click());
+ onView(withText(R.string.installed_apps__activity_title)).check(matches(isDisplayed()));
+ onView(withContentDescription(androidx.appcompat.R.string.abc_action_bar_up_description)).perform(click());
+
+ onView(withText(R.string.menu_manage)).perform(click());
+ onView(withContentDescription(androidx.appcompat.R.string.abc_action_bar_up_description)).perform(click());
+
+ manageInstalledAppsButton.perform(click());
+ onView(withText(R.string.installed_apps__activity_title)).check(matches(isDisplayed()));
+ onView(withContentDescription(androidx.appcompat.R.string.abc_action_bar_up_description)).perform(click());
+
+ onView(withText(R.string.menu_manage)).perform(click());
+ onView(withContentDescription(androidx.appcompat.R.string.abc_action_bar_up_description)).perform(click());
+
+ onView(withText(R.string.about_title)).perform(click());
+ onView(withId(R.id.version)).check(matches(isDisplayed()));
+ onView(withId(R.id.ok_button)).perform(click());
+
+ onView(withId(android.R.id.list_container)).perform(swipeUp()).perform(swipeUp()).perform(swipeUp());
+ }
+
+ @LargeTest
+ @Test
+ public void showUpdates() {
+ ViewInteraction updatesBottonNavButton = onView(allOf(withText(R.string.main_menu__updates), isDisplayed()));
+ updatesBottonNavButton.perform(click());
+ onView(withText(R.string.main_menu__updates)).check(matches(isDisplayed()));
+ }
+
+ @LargeTest
+ @Test
+ public void startSwap() {
+ if (!BuildConfig.FLAVOR.startsWith("full")) {
+ return;
+ }
+ ViewInteraction nearbyBottonNavButton = onView(
+ allOf(withText(R.string.main_menu__swap_nearby), isDisplayed()));
+ nearbyBottonNavButton.perform(click());
+ ViewInteraction findPeopleButton = onView(
+ allOf(withId(R.id.find_people_button), withText(R.string.nearby_splash__find_people_button),
+ isDisplayed()));
+ findPeopleButton.perform(click());
+ onView(withText(R.string.swap_send_fdroid)).check(matches(isDisplayed()));
+ }
+
+ @LargeTest
+ @Test
+ public void showCategories() {
+ if (!BuildConfig.FLAVOR.startsWith("full")) {
+ return;
+ }
+ onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
+ onView(allOf(withText(R.string.main_menu__categories), isDisplayed())).perform(click());
+ onView(allOf(withId(R.id.swipe_to_refresh), isDisplayed()))
+ .perform(swipeDown())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeDown())
+ .perform(swipeDown())
+ .perform(swipeRight())
+ .perform(swipeLeft())
+ .perform(swipeLeft())
+ .perform(swipeLeft())
+ .perform(swipeLeft())
+ .perform(click());
+ }
+
+ @LargeTest
+ @Test
+ public void showLatest() {
+ if (!BuildConfig.FLAVOR.startsWith("full")) {
+ return;
+ }
+ onView(Matchers.instanceOf(StatusBanner.class)).check(matches(not(isDisplayed())));
+ onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
+ onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click());
+ onView(allOf(withId(R.id.swipe_to_refresh), isDisplayed()))
+ .perform(swipeDown())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeUp())
+ .perform(swipeDown())
+ .perform(swipeUp())
+ .perform(swipeDown())
+ .perform(swipeDown())
+ .perform(swipeDown())
+ .perform(swipeDown())
+ .perform(click());
+ }
+
+ @LargeTest
+ @Test
+ public void showSearch() {
+ onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click());
+ onView(withId(R.id.fab_search)).check(doesNotExist());
+ if (!BuildConfig.FLAVOR.startsWith("full")) {
+ return;
+ }
+ onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click());
+ onView(allOf(withId(R.id.fab_search), isDisplayed())).perform(click());
+ onView(withId(R.id.sort)).check(matches(isDisplayed()));
+ onView(allOf(withId(R.id.search), isDisplayed()))
+ .perform(click())
+ .perform(typeText("test"));
+ onView(allOf(withId(R.id.sort), isDisplayed())).perform(click());
+ }
+}
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/nearby/BonjourManagerTest.java b/app/src/androidTestFull/java/org/fdroid/fdroid/nearby/BonjourManagerTest.java
similarity index 100%
rename from app/src/androidTest/java/org/fdroid/fdroid/nearby/BonjourManagerTest.java
rename to app/src/androidTestFull/java/org/fdroid/fdroid/nearby/BonjourManagerTest.java
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/nearby/LocalHTTPDManagerTest.java b/app/src/androidTestFull/java/org/fdroid/fdroid/nearby/LocalHTTPDManagerTest.java
similarity index 100%
rename from app/src/androidTest/java/org/fdroid/fdroid/nearby/LocalHTTPDManagerTest.java
rename to app/src/androidTestFull/java/org/fdroid/fdroid/nearby/LocalHTTPDManagerTest.java
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/nearby/PublicSourceDirProviderTest.java b/app/src/androidTestFull/java/org/fdroid/fdroid/nearby/PublicSourceDirProviderTest.java
similarity index 100%
rename from app/src/androidTest/java/org/fdroid/fdroid/nearby/PublicSourceDirProviderTest.java
rename to app/src/androidTestFull/java/org/fdroid/fdroid/nearby/PublicSourceDirProviderTest.java
diff --git a/app/src/androidTest/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java b/app/src/androidTestFull/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java
similarity index 100%
rename from app/src/androidTest/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java
rename to app/src/androidTestFull/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java
diff --git a/app/src/main/java/org/fdroid/fdroid/views/InstallHistoryActivity.java b/app/src/main/java/org/fdroid/fdroid/views/InstallHistoryActivity.java
index fcd97a71d..edf22e222 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/InstallHistoryActivity.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/InstallHistoryActivity.java
@@ -31,6 +31,7 @@ import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ShareCompat;
@@ -66,6 +67,7 @@ public class InstallHistoryActivity extends AppCompatActivity {
fdroidApp.setSecureWindow(this);
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
+ EdgeToEdge.enable(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_install_history);
diff --git a/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewayAddActivity.kt b/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewayAddActivity.kt
index 7a6336d61..5408e59ce 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewayAddActivity.kt
+++ b/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewayAddActivity.kt
@@ -3,6 +3,7 @@ package org.fdroid.fdroid.views
import android.net.Uri
import android.os.Bundle
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -46,6 +47,7 @@ import org.fdroid.fdroid.ui.theme.FDroidContent
class IpfsGatewayAddActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
+ enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent {
FDroidContent {
diff --git a/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewaySettingsActivity.kt b/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewaySettingsActivity.kt
index 887e1b983..1bc51d8d0 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewaySettingsActivity.kt
+++ b/app/src/main/java/org/fdroid/fdroid/views/IpfsGatewaySettingsActivity.kt
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -50,6 +51,7 @@ import org.fdroid.fdroid.ui.theme.FDroidContent
class IpfsGatewaySettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
+ enableEdgeToEdge()
super.onCreate(savedInstanceState)
val prefs = Preferences.get()
setContent {
diff --git a/app/src/main/java/org/fdroid/fdroid/views/repos/AddRepoActivity.kt b/app/src/main/java/org/fdroid/fdroid/views/repos/AddRepoActivity.kt
index 73e406a88..317e2b005 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/repos/AddRepoActivity.kt
+++ b/app/src/main/java/org/fdroid/fdroid/views/repos/AddRepoActivity.kt
@@ -8,6 +8,7 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.collectAsState
import androidx.core.content.ContextCompat
@@ -36,6 +37,7 @@ class AddRepoActivity : AppCompatActivity() {
private val repoManager: RepoManager get() = FDroidApp.getRepoManager(this)
override fun onCreate(savedInstanceState: Bundle?) {
+ enableEdgeToEdge()
super.onCreate(savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(STARTED) {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8c82f7a49..4902305b5 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -7,7 +7,7 @@ mavenPublish = "0.18.0"
jlleitschuhKtlint = "12.1.1"
kotlinxSerializationJson = "1.4.1" # 1.4.1 because https://github.com/Kotlin/kotlinx.serialization/issues/2231
-kotlinxCoroutinesTest = "1.7.3"
+kotlinxCoroutinesTest = "1.8.1"
ktor = "2.3.12"
okhttp = "4.12.0"
@@ -20,22 +20,22 @@ androidxAppcompat = "1.7.0"
androidxPreferenceKtx = "1.2.1"
androidxLifecycleLivedataKtx = "2.8.7"
androidxWork = "2.10.0"
-androidxRecyclerview = "1.3.2"
-androidxConstraintlayout = "2.2.0"
+androidxRecyclerview = "1.4.0"
+androidxConstraintlayout = "2.2.1"
androidxCardview = "1.0.0"
androidxPaletteKtx = "1.0.0"
androidxVectordrawable = "1.2.0"
androidxGridlayout = "1.0.0"
-androidxComposeBom = "2024.11.00"
-androidxActivityCompose = "1.9.3"
-accompanistThemeadapterMaterial = "0.30.1"
+androidxComposeBom = "2025.03.00"
+androidxActivityCompose = "1.10.1"
accompanistDrawablepainter = "0.36.0"
material = "1.12.0"
-zxingCore = "3.3.3" # newer version need minSdk 24 or library desugering
+#noinspection GradleDependency newer version need minSdk 24 or library desugering
+zxingCore = "3.3.3"
guardianprojectNetcipher = "2.2.0-alpha"
guardianprojectPanic = "1.0"
-acra = "5.11.3"
+acra = "5.12.0"
adapterdelegates4 = "4.3.2"
#noinspection GradleDependency Commons IO > 2.5 uses java.nio.file, which requires desugaring
commonsIo = "2.6"
@@ -43,7 +43,7 @@ commonsNet = "3.6"
bouncycastle = "1.71"
jmdns = "3.5.5"
nanohttpd = "2.3.1"
-guava = "32.1.3-android"
+guava = "33.3.1-android"
rxjava = "3.1.9"
rxandroid = "3.0.2"
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 1da9e1e3f..c8e784161 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -191,6 +191,11 @@
+
+
+
+
+
@@ -226,6 +231,11 @@
+
+
+
+
+
@@ -246,6 +256,11 @@
+
+
+
+
+
@@ -334,6 +349,11 @@
+
+
+
+
+
@@ -384,6 +404,11 @@
+
+
+
+
+
@@ -611,6 +636,11 @@
+
+
+
+
+
@@ -631,6 +661,11 @@
+
+
+
+
+
@@ -656,6 +691,11 @@
+
+
+
+
+
@@ -676,6 +716,11 @@
+
+
+
+
+
@@ -716,6 +761,11 @@
+
+
+
+
+
@@ -736,6 +786,11 @@
+
+
+
+
+
@@ -761,6 +816,11 @@
+
+
+
+
+
@@ -781,6 +841,11 @@
+
+
+
+
+
@@ -826,6 +891,11 @@
+
+
+
+
+
@@ -851,6 +921,11 @@
+
+
+
+
+
@@ -871,6 +946,11 @@
+
+
+
+
+
@@ -896,6 +976,11 @@
+
+
+
+
+
@@ -916,6 +1001,11 @@
+
+
+
+
+
@@ -941,6 +1031,11 @@
+
+
+
+
+
@@ -961,6 +1056,11 @@
+
+
+
+
+
@@ -1001,6 +1101,11 @@
+
+
+
+
+
@@ -1021,6 +1126,11 @@
+
+
+
+
+
@@ -1046,6 +1156,11 @@
+
+
+
+
+
@@ -1066,6 +1181,11 @@
+
+
+
+
+
@@ -1091,6 +1211,11 @@
+
+
+
+
+
@@ -1111,6 +1236,11 @@
+
+
+
+
+
@@ -1136,6 +1266,11 @@
+
+
+
+
+
@@ -1156,6 +1291,11 @@
+
+
+
+
+
@@ -1181,6 +1321,11 @@
+
+
+
+
+
@@ -1201,6 +1346,11 @@
+
+
+
+
+
@@ -1226,6 +1376,11 @@
+
+
+
+
+
@@ -1246,6 +1401,11 @@
+
+
+
+
+
@@ -1271,6 +1431,11 @@
+
+
+
+
+
@@ -1296,6 +1461,11 @@
+
+
+
+
+
@@ -1321,6 +1491,11 @@
+
+
+
+
+
@@ -1341,6 +1516,11 @@
+
+
+
+
+
@@ -1366,6 +1546,11 @@
+
+
+
+
+
@@ -1386,6 +1571,11 @@
+
+
+
+
+
@@ -1406,6 +1596,11 @@
+
+
+
+
+
@@ -1426,6 +1621,11 @@
+
+
+
+
+
@@ -1464,6 +1664,11 @@
+
+
+
+
+
@@ -1474,6 +1679,11 @@
+
+
+
+
+
@@ -1603,6 +1813,11 @@
+
+
+
+
+
@@ -2645,6 +2860,11 @@
+
+
+
+
+
@@ -3457,6 +3677,11 @@
+
+
+
+
+
@@ -3472,6 +3697,11 @@
+
+
+
+
+
@@ -3487,6 +3717,11 @@
+
+
+
+
+
@@ -6560,6 +6795,11 @@
+
+
+
+
+
@@ -6644,6 +6884,11 @@
+
+
+
+
+
@@ -6719,6 +6964,14 @@
+
+
+
+
+
+
+
+
@@ -6783,6 +7036,11 @@
+
+
+
+
+
@@ -10724,6 +10982,11 @@
+
+
+
+
+
@@ -12838,6 +13101,14 @@
+
+
+
+
+
+
+
+
@@ -13501,6 +13772,11 @@
+
+
+
+
+
@@ -13570,6 +13846,11 @@
+
+
+
+
+
@@ -13636,6 +13917,11 @@
+
+
+
+
+
@@ -13687,6 +13973,11 @@
+
+
+
+
+
@@ -13727,6 +14018,11 @@
+
+
+
+
+
@@ -13757,6 +14053,11 @@
+
+
+
+
+
@@ -13772,6 +14073,11 @@
+
+
+
+
+
@@ -13792,6 +14098,11 @@
+
+
+
+
+