Skip to content

Commit df2730b

Browse files
committed
Merge branch 'dependency-updates'
2 parents 2143479 + 6e2ad2d commit df2730b

File tree

10 files changed

+798
-600
lines changed

10 files changed

+798
-600
lines changed

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomTextField.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package net.mullvad.mullvadvpn.compose.textfield
22

3-
import android.text.TextUtils
43
import androidx.compose.foundation.layout.Row
54
import androidx.compose.foundation.layout.fillMaxWidth
65
import androidx.compose.foundation.layout.padding
@@ -30,6 +29,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
3029
import androidx.compose.ui.text.input.KeyboardType
3130
import androidx.compose.ui.text.input.TextFieldValue
3231
import androidx.compose.ui.text.input.VisualTransformation
32+
import androidx.core.text.isDigitsOnly
3333
import net.mullvad.mullvadvpn.constant.EMPTY_STRING
3434
import net.mullvad.mullvadvpn.constant.NEWLINE_STRING
3535
import net.mullvad.mullvadvpn.lib.theme.Dimens
@@ -87,8 +87,7 @@ fun CustomTextField(
8787

8888
if (stringChangedSinceLastInvocation) {
8989
val isValidInput =
90-
if (isDigitsOnlyAllowed) TextUtils.isDigitsOnly(newTextFieldValueState.text)
91-
else true
90+
if (isDigitsOnlyAllowed) newTextFieldValueState.text.isDigitsOnly() else true
9291
if (newTextFieldValueState.text.length <= maxCharLength && isValidInput) {
9392
// Remove any newline chars added by enter key clicks
9493
onValueChanged(

android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.activity.compose.setContent
99
import androidx.activity.enableEdgeToEdge
1010
import androidx.activity.result.contract.ActivityResultContracts
1111
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
12+
import androidx.core.util.Consumer
1213
import androidx.lifecycle.Lifecycle
1314
import androidx.lifecycle.lifecycleScope
1415
import androidx.lifecycle.repeatOnLifecycle
@@ -158,7 +159,7 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent {
158159
callbackFlow<Intent> {
159160
send(intent)
160161

161-
val listener: (Intent) -> Unit = { trySend(it) }
162+
val listener = Consumer<Intent> { intent -> trySend(intent) }
162163

163164
addOnNewIntentListener(listener)
164165

android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AppInfoViewModel.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.viewmodel
22

33
import android.content.res.Resources
44
import android.net.Uri
5+
import androidx.core.net.toUri
56
import androidx.lifecycle.ViewModel
67
import androidx.lifecycle.viewModelScope
78
import kotlinx.coroutines.channels.Channel
@@ -51,7 +52,7 @@ class AppInfoViewModel(
5152
} else {
5253
resources.getString(R.string.download_url)
5354
}
54-
_uiSideEffect.send(AppInfoSideEffect.OpenUri(Uri.parse(uri)))
55+
_uiSideEffect.send(AppInfoSideEffect.OpenUri(uri.toUri()))
5556
}
5657
}
5758

android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.viewmodel
22

33
import android.content.res.Resources
44
import android.net.Uri
5+
import androidx.core.net.toUri
56
import androidx.lifecycle.ViewModel
67
import androidx.lifecycle.viewModelScope
78
import kotlinx.coroutines.FlowPreview
@@ -190,7 +191,7 @@ class ConnectViewModel(
190191
} else {
191192
resources.getString(R.string.download_url)
192193
}
193-
_uiSideEffect.send(UiSideEffect.OpenUri(Uri.parse(uri)))
194+
_uiSideEffect.send(UiSideEffect.OpenUri(uri.toUri()))
194195
}
195196

196197
fun dismissNewDeviceNotification() {

android/buildSrc/src/main/kotlin/Versions.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Versions {
66
const val targetSdkVersion = 35
77
const val ndkVersion = "27.2.12479018"
88

9-
const val junitJupiter = "5.11.4"
10-
const val junit5Android = "1.6.0"
11-
const val junit5Plugin = "1.11.3.0"
9+
const val junitJupiter = "5.12.0"
10+
const val junit5Android = "1.7.0"
11+
const val junit5Plugin = "1.12.0.0"
1212
}

android/config/lint-baseline.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
id="InvalidPackage"
66
message="Invalid package reference in library; not included in Android: `javax.naming.directory`. Referenced from `io.grpc.internal.JndiResourceResolverFactory.JndiRecordFetcher`.">
77
<location
8-
file="../../../../.gradle/caches/modules-2/files-2.1/io.grpc/grpc-core/1.69.1/d9f6383e1903af6e9502e7c1c8e4fbe28a236321/grpc-core-1.69.1.jar"/>
8+
file="*/caches/modules-2/files-2.1/io.grpc/grpc-core/1.71.0/a7cd1e546cd5518dc6a919e5469712af99fe13b0/grpc-core-1.71.0.jar"/>
99
</issue>
1010

1111
<issue
1212
id="InvalidPackage"
1313
message="Invalid package reference in library; not included in Android: `javax.naming`. Referenced from `io.grpc.internal.JndiResourceResolverFactory.JndiRecordFetcher`.">
1414
<location
15-
file="../../../../.gradle/caches/modules-2/files-2.1/io.grpc/grpc-core/1.69.1/d9f6383e1903af6e9502e7c1c8e4fbe28a236321/grpc-core-1.69.1.jar"/>
15+
file="*/caches/modules-2/files-2.1/io.grpc/grpc-core/1.71.0/a7cd1e546cd5518dc6a919e5469712af99fe13b0/grpc-core-1.71.0.jar"/>
1616
</issue>
1717

1818
<issue

android/gradle/libs.versions.toml

+8-9
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
# The android-gradle-aapt plugin version must be in sync with the android plugin version.
44
# Required for Gradle metadata verification to work properly, see:
55
# https://github.com/gradle/gradle/issues/19228
6-
android-gradle-plugin = "8.8.2"
7-
android-gradle-aapt = "12006047"
6+
android-gradle-plugin = "8.9.0"
7+
android-gradle-aapt = "12782657"
88
android-billingclient = "7.1.1"
99
android-volley = "1.2.1"
1010

1111
# AndroidX
1212
androidx-activitycompose = "1.10.1"
1313
androidx-appcompat = "1.7.0"
1414
androidx-ktx = "1.15.0"
15-
androidx-credentials = "1.3.0"
15+
androidx-credentials = "1.5.0"
1616
androidx-coresplashscreen = "1.1.0-rc01"
1717
androidx-datastore = "1.1.3"
1818
androidx-espresso = "3.6.1"
@@ -28,12 +28,12 @@ arrow = "2.0.1"
2828

2929
# Compose
3030
compose = "1.7.8"
31-
compose-destinations = "2.1.0-beta16"
31+
compose-destinations = "2.1.0"
3232
compose-constraintlayout = "1.1.1"
3333
compose-material3 = "1.3.1"
3434

3535
# Update suppression for 'InvalidPackage' in config/lint.xml
36-
grpc = "1.70.0"
36+
grpc = "1.71.0"
3737
grpc-kotlin = "1.4.1"
3838
grpc-kotlin-jar = "1.4.1:jdk8@jar"
3939

@@ -49,13 +49,13 @@ ktor = "3.0.3"
4949
# Bump kotlin and kotlin-ksp together, find matching release here:
5050
# https://github.com/google/ksp/releases
5151
kotlin = "2.1.10"
52-
kotlin-ksp = "2.1.10-1.0.30"
52+
kotlin-ksp = "2.1.10-1.0.31"
5353
kotlinx = "1.10.1"
5454
kotlinx-serialization = "2.1.10"
5555

5656
# Protobuf
5757
protobuf-gradle-plugin = "0.9.4"
58-
protobuf = "4.29.3"
58+
protobuf = "4.30.0"
5959

6060
# Rust Android Gradle
6161
rust-android-gradle = "0.9.6"
@@ -70,8 +70,7 @@ konsist = "0.17.3"
7070
ktfmt = "0.22.0"
7171
leakcanary = "2.14"
7272

73-
# 1.13.16 is broken with value classes: https://github.com/mockk/mockk/issues/1333
74-
mockk = "1.13.14"
73+
mockk = "1.13.17"
7574
mockwebserver = "4.12.0"
7675
play-publisher = "3.12.1"
7776
turbine = "1.2.0"

android/gradle/verification-keyring.keys

+113
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,52 @@ yzHzAhsMAAoJEA2opewC0R6tNKgAnigkHDCNu7Owm8x01E9+aL73JmDXAKCj7ROh
524524
-----END PGP PUBLIC KEY BLOCK-----
525525

526526

527+
pub 0F9FE62F88E938D8
528+
uid Brad Corso <bcorso@google.com>
529+
530+
sub BF6D15D3F1BF7BCF
531+
-----BEGIN PGP PUBLIC KEY BLOCK-----
532+
533+
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
569+
=Cl60
570+
-----END PGP PUBLIC KEY BLOCK-----
571+
572+
527573
pub 1427500BB1D27520
528574
uid ExoQuery <ExoQueryUser@gmail.com>
529575

@@ -3888,6 +3934,35 @@ rLn7t3piwid4fiWe5/Q9pYtn0jOsRBGzxQEs2XV/i7EQXT8kcqKGKmZWtUC7b92G
38883934
-----END PGP PUBLIC KEY BLOCK-----
38893935

38903936

3937+
pub C3BAB45F4AF71FAB
3938+
uid Yang Song <songya@google.com>
3939+
3940+
sub 34FEB51E33761BEA
3941+
-----BEGIN PGP PUBLIC KEY BLOCK-----
3942+
3943+
mQENBFkeN88BCAC4rvR3Dc6nDYhbXUC5IQ6SJWvV98+tvZ117J/VD07el7dicryY
3944+
H3OAWl62iLjHJFP/+AEra1plpiWbPioDlzjOWC2AJjUCtqVLHdyVbY0Gv3sSRZXJ
3945+
3H7CyGO1QbT79m4Gwk9vX5si3aBTzJNqYF6Kn1C386ZSZd6l618YSPUzJRXi1mst
3946+
rP2iV1hP+kydcFxB0+F8/IjzK9kngtp/k1z2x0tbIRTnUYnvS/GNbLHlVzrxvA1S
3947+
izbVLBzeuzmSyqT7xy6dPjsLEIoSK3cyR9x5tzmcSEA3dMN36N7j+mbqVI25Md0p
3948+
gd3vgIqGXQsRSezG1Kj5pQglPKl2Jufx5CEPABEBAAG0HVlhbmcgU29uZyA8c29u
3949+
Z3lhQGdvb2dsZS5jb20+uQENBFkeN88BCAChDNcKrhc2DHhIBmGvPvua+JiR3bAD
3950+
4pQZbMfisr70ZFHox7mVxTGGK7UDY4TpgeaWElWY0FJuQmnfP90Z4z+0Aqn24OoI
3951+
XyddFzt5JF1jCT79QX95t0KBhmPgqQssCNHfz6tpQSgK3NRaVJSjtgaTaVu6zJ++
3952+
ZJj772LQt0hqzcjMlpOaX2Jkdj8hDhsw3PZiCO4Hq52pIS987sPQRdbT+Tv6V4WO
3953+
Z7cuWqQIdfWOQwxVn3MAIIL3l9a4iMKIAWuj3kHxaHZ3gLj/51b/nlh3chDzhGbo
3954+
YpZWk1pmlCXFZnctoRO9Tk25bKRUgTJJP8sKgAsNK37n8zGAzUc3yXhRABEBAAGJ
3955+
AR8EGAECAAkFAlkeN88CGwwACgkQw7q0X0r3H6tJqgf/ZXG41Egf1gHv2d2c4hYI
3956+
xFFKhVJFZI0EfMq7ZCPZXrjphtgTrLLUYyxaRoW8dRstf/sNyb+yiZr8PGyKmk+6
3957+
LutzHStJFyk+h9b/sRKWzKnAnUzxzMggfFChMsMdwrmd4nmy6II+A0bjxM0eee4A
3958+
vEyd9/q8LNswtqaVJf7Az2HADvPUxxqcrtFvUFvD1GuTNYaSEKsZcr/EAmP8zq6L
3959+
vXKCmVnnIiP5JwBYMOfBqnsG6r504vpfmhfJBycCsyZlJbVjV0sL9514Ph7MJysI
3960+
uwCK4i39LRwL4i3O2PDZgv5Oal/V0cfrEEfJD4px/gfmZF2LRkpMS+qZrRJ2Nu7K
3961+
6g==
3962+
=jgaB
3963+
-----END PGP PUBLIC KEY BLOCK-----
3964+
3965+
38913966
pub C727D053C4481CF5
38923967
sub 29E792953D515FC5
38933968
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -5037,6 +5112,44 @@ TSkgKFVzZWQgdG8gc2lnbiBKRE9NIFBhY2thZ2VzKSA8amRvbUB0dWlzLm5ldD4=
50375112
-----END PGP PUBLIC KEY BLOCK-----
50385113

50395114

5115+
pub EB095DA7D2F6AC0E
5116+
uid TensorFlow Authors <tensorflow-sonatype-authors@google.com>
5117+
5118+
sub 603D72C90616CD6B
5119+
-----BEGIN PGP PUBLIC KEY BLOCK-----
5120+
5121+
mQGNBGBm/LQBDADMr/VPcTvE6k3wEYxq5kZusnDCDTsI6RK51d4oMwaRc3Z0jtZ0
5122+
CfyWocZBok4rMbZAVnE3Q8pMyikGGUnc8ZsWoPEmJyCpw/2Orj0QqZhIgYMQ31Uq
5123+
tiGZF/G4w9phLIkFgU9BLGYjRNM69R0oE/Tj8mjguvnKzYM3GjkY6nDsgWCM5TJX
5124+
01k4sdLs0dVg86m4keq+SeS9uEwnINZTh6kQUKsW6aHvvPXze/UPoaZqxgXDjF+F
5125+
JrPwW8yDllkbzpbo53ulz1TL5RsIH3daUwxXG3ciovUXG/b2ZRuWjtH7Gn/AvCNL
5126+
0RXdHK3A2I23zCooOE+we2D45QUHm/vcmvsnbxOU7Tslm2DsnYxBjf5dAl2yZn+J
5127+
FSrV91Bbd5ZXi1UkkGjBzAgbHDwdMvL9K6fTO9NwjXyBpiHy6ukIOObn9uIgDSSa
5128+
xPnqgeykSv+RZEea8ML4BSif5RJYlmILEzJhH4rtX9X+t8BZv+ZoaN6p/qYg4/2+
5129+
XfSUPmCJjlUaIUUAEQEAAbQ7VGVuc29yRmxvdyBBdXRob3JzIDx0ZW5zb3JmbG93
5130+
LXNvbmF0eXBlLWF1dGhvcnNAZ29vZ2xlLmNvbT65AY0EYGb8tAEMALbsrC+JdcC4
5131+
wyIL2v/pg++nHpMUbueLO82DpIf/OzSGerT5D5cP8PpuwhKIbq8drEEj6wpSaGjK
5132+
sZT4EQppo+SUFRAu/faZLyWW/kMLJQ+ez/OC2J7Yqqa/p5pker4A5WcWokWujlVJ
5133+
ZVE2MA6R3EPDKHF2p3uIgHmvfWnMS+tMzopj3mj1SvbV2UNZyj1SFrOkUmJ2ueBR
5134+
WZ9Ll3xuEMfMRAF2HXFI+aBIeCRbRHD/ueWFVqKX4vsyEMMCeyWjumWYR3KODqQs
5135+
E2rgf4V9klXUoo1d9jvSIR1zt8TyIvuUQv4sB64Rd5HsTS5X1VjJ2/0Vgu0TkF3V
5136+
BCuGEBi8u/nRXe5SkOYG1KAIbqljpx8mkgMjZRRrptxUeaK6GndHikuY85Np+FDD
5137+
zQwKKO8hItXHQq8pAyXm9RkA+rnEMfqKi5HNThsKlYyVNxQ0I/8r0gjyprLfZUhk
5138+
tyR/ZemnNN9w29qgD5FMZ4cNsTeCx5NiKKL5+UmbtSFMx/P4vh4aXwARAQABiQG2
5139+
BBgBCgAgFiEEdEDx99J7rBFflT1V6wldp9L2rA4FAmBm/LQCGwwACgkQ6wldp9L2
5140+
rA5EgQv/dXw1tFelPKUcFuhxa7gJ6v9LkNoCEq5g5aSc7IEjuh0EH4aNU/+7rmIZ
5141+
wRslOHcSBeBvQPhIYdosIQfdCcwjS7LU1urnkljCvuIbwaX8d5Am7NqMbtM/GR66
5142+
MRPSO3uV6g0DmswDZ3i0WSeUgK4NXRRmL3gUZcoxOeQpg0Mo+fGiZDGywACa3azJ
5143+
BWR8G3gSjrN6YdM5+Tb0gQ1D/AN8JVF7ksknl2AlCI9pOEOsyaHZ4T++or36btHm
5144+
Z+FJw9LCPGHaCTrDSoA0Tun0fZBBIf1xmNPNgdQHerTtp3mtTCFRdBiIH4d3s3d2
5145+
HBuEYqdLqiD6+8saU5lRAPMFb6VoPPsGNv8by7h7WQ+fWyuCpUPZvuFuVobq7K3V
5146+
H0iNhLlzae8WMDUVX3pQKZrDjlqjjaloOJXoq8ZFlDM+1wwKwz7nouEJPFReP9Mn
5147+
xjlUofFR0KyGrs6qzaeC22AvbIotX6sUExVRjz4b+lro3f3lLlHlEWWyoKRyH54g
5148+
1y4mk1Mn
5149+
=iteQ
5150+
-----END PGP PUBLIC KEY BLOCK-----
5151+
5152+
50405153
pub EC5BCE97B4DEFA96
50415154
uid Martin Grotzke <mg@fsfe.org>
50425155

0 commit comments

Comments
 (0)