summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-02-26 14:58:25 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-02-26 14:58:25 +0100
commit5ba686d1ac45509cba636d717bb6729865105cf3 (patch)
treee21ad8d6ca30a8ca6a02313c9b4cc786370dc91e /android
parent5025db74b34cfb3536c43f89f3407ffc0d97ae73 (diff)
parent38c4791b414538962f6a8ab958aecd09414f33f6 (diff)
downloadmullvadvpn-5ba686d1ac45509cba636d717bb6729865105cf3.tar.xz
mullvadvpn-5ba686d1ac45509cba636d717bb6729865105cf3.zip
Merge branch 'remove-jodatime-droid-898'
Diffstat (limited to 'android')
-rw-r--r--android/app/build.gradle.kts1
-rw-r--r--android/app/proguard-rules.pro6
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt17
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt5
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/ResourcesExtensions.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt9
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DevicePreviewData.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/provider/MullvadFileProvider.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/DateExtensions.kt15
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt5
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt5
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt33
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt2
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt29
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceNotificationUseCaseTest.kt4
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt14
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt8
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt6
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt6
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt6
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt6
-rw-r--r--android/gradle/libs.versions.toml2
-rw-r--r--android/gradle/verification-metadata.xml5
-rw-r--r--android/lib/common/build.gradle.kts1
-rw-r--r--android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt14
-rw-r--r--android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/DateExtensions.kt20
-rw-r--r--android/lib/daemon-grpc/build.gradle.kts1
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt11
-rw-r--r--android/lib/model/build.gradle.kts1
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/AccountData.kt4
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Device.kt4
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Notification.kt2
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/RedeemVoucherSuccess.kt4
-rw-r--r--android/lib/shared/build.gradle.kts1
-rw-r--r--android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/AccountRepository.kt4
-rw-r--r--android/service/build.gradle.kts1
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryAndroidNotification.kt12
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryConstant.kt8
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryNotificationProvider.kt4
-rw-r--r--android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryTicker.kt22
-rw-r--r--android/test/e2e/build.gradle.kts1
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt10
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt28
-rw-r--r--android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/NanoSecondsTimestampSerializer.kt14
-rw-r--r--android/test/mockapi/build.gradle.kts1
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt8
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt4
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt8
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt4
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt15
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt4
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt15
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt10
64 files changed, 244 insertions, 233 deletions
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 4a78a198a2..ec59d0a5d3 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -399,7 +399,6 @@ dependencies {
implementation(libs.compose.destinations)
ksp(libs.compose.destinations.ksp)
- implementation(libs.jodatime)
implementation(libs.kermit)
implementation(libs.koin)
implementation(libs.koin.android)
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
index b72bed1d05..94c8f48bda 100644
--- a/android/app/proguard-rules.pro
+++ b/android/app/proguard-rules.pro
@@ -13,12 +13,6 @@
-keep class java.net.InetSocketAddress { *; }
-keep class java.util.ArrayList { *; }
-# Joda Time
--dontwarn org.joda.convert.**
--dontwarn org.joda.time.**
--keep class org.joda.time.** { *; }
--keep interface org.joda.time.** { *; }
-
# grpc
-keep class io.grpc.okhttp.OkHttpChannelBuilder { *; }
-keep class mullvad_daemon.management_interface.** { *; }
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt
index 0cdc8b8fe7..f1a81d4d91 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt
@@ -10,6 +10,9 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
import io.mockk.verify
+import java.time.Duration
+import java.time.Instant
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension
import net.mullvad.mullvadvpn.compose.setContentWithTheme
import net.mullvad.mullvadvpn.compose.state.ConnectUiState
@@ -30,8 +33,6 @@ import net.mullvad.mullvadvpn.lib.model.TunnelEndpoint
import net.mullvad.mullvadvpn.lib.model.TunnelState
import net.mullvad.mullvadvpn.repository.InAppNotification
import net.mullvad.mullvadvpn.ui.VersionInfo
-import org.joda.time.DateTime
-import org.joda.time.Duration
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -556,7 +557,7 @@ class ConnectScreenTest {
fun testAccountExpiredNotification() {
composeExtension.use {
// Arrange
- val expiryDate = DateTime(2020, 11, 11, 10, 10)
+ val expiryDate = ZonedDateTime.parse("2020-11-11T10:10Z")
initScreen(
state =
ConnectUiState(
@@ -567,7 +568,9 @@ class ConnectScreenTest {
deviceName = "",
daysLeftUntilExpiry = null,
inAppNotification =
- InAppNotification.AccountExpiry(Duration(DateTime.now(), expiryDate)),
+ InAppNotification.AccountExpiry(
+ Duration.between(Instant.now(), expiryDate)
+ ),
isPlayBuild = false,
)
)
@@ -612,7 +615,7 @@ class ConnectScreenTest {
composeExtension.use {
// Arrange
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
- val expiryDate = DateTime(2020, 11, 11, 10, 10)
+ val expiryDate = ZonedDateTime.parse("2020-11-11T10:10Z")
initScreen(
onManageAccountClick = mockedClickHandler,
state =
@@ -624,7 +627,9 @@ class ConnectScreenTest {
deviceName = "",
daysLeftUntilExpiry = null,
inAppNotification =
- InAppNotification.AccountExpiry(Duration(DateTime.now(), expiryDate)),
+ InAppNotification.AccountExpiry(
+ Duration.between(Instant.now(), expiryDate)
+ ),
isPlayBuild = false,
),
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt
index 3d591bafba..29fa7415bb 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt
@@ -78,7 +78,7 @@ fun ScaffoldWithTopBarAndDeviceName(
isIconAndLogoVisible: Boolean = true,
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
deviceName: String?,
- timeLeft: Int?,
+ timeLeft: Long?,
content: @Composable (PaddingValues) -> Unit,
) {
Scaffold(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt
index 91cb49ae53..e7a58d998b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt
@@ -332,7 +332,7 @@ fun MullvadTopBarWithDeviceName(
iconTintColor: Color,
isIconAndLogoVisible: Boolean = true,
deviceName: String?,
- daysLeftUntilExpiry: Int?,
+ daysLeftUntilExpiry: Long?,
) {
Column {
MullvadTopBar(
@@ -383,8 +383,8 @@ fun MullvadTopBarWithDeviceName(
if (daysLeftUntilExpiry >= 0) {
pluralStringResource(
id = R.plurals.days,
- daysLeftUntilExpiry,
- daysLeftUntilExpiry,
+ daysLeftUntilExpiry.toInt(),
+ daysLeftUntilExpiry.toInt(),
)
} else {
stringResource(id = R.string.out_of_time)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt
index f15a054b7d..4f527a94c5 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt
@@ -30,6 +30,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
+import java.time.Duration
import net.mullvad.mullvadvpn.compose.component.MullvadTopBar
import net.mullvad.mullvadvpn.compose.test.NOTIFICATION_BANNER
import net.mullvad.mullvadvpn.compose.test.NOTIFICATION_BANNER_ACTION
@@ -43,7 +44,6 @@ import net.mullvad.mullvadvpn.lib.theme.color.warning
import net.mullvad.mullvadvpn.repository.InAppNotification
import net.mullvad.mullvadvpn.ui.VersionInfo
import net.mullvad.mullvadvpn.ui.notification.StatusLevel
-import org.joda.time.Duration
@Preview
@Composable
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
index a9859c318a..93b29e5185 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
@@ -29,6 +29,7 @@ import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
+import java.util.concurrent.TimeUnit
import net.mullvad.mullvadvpn.BuildConfig
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
@@ -46,7 +47,6 @@ import net.mullvad.mullvadvpn.lib.model.RedeemVoucherError
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.viewmodel.VoucherDialogViewModel
-import org.joda.time.DateTimeConstants
import org.koin.androidx.compose.koinViewModel
@Preview(device = Devices.TV_720p)
@@ -157,9 +157,10 @@ fun RedeemVoucherDialog(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
+ TimeUnit.DAYS.toSeconds(1)
if (state.voucherState is VoucherDialogState.Success) {
val days: Int =
- (state.voucherState.addedTime / DateTimeConstants.SECONDS_PER_DAY).toInt()
+ (state.voucherState.addedTime / TimeUnit.DAYS.toSeconds(1)).toInt()
val message =
stringResource(
R.string.added_to_your_account,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/ResourcesExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/ResourcesExtensions.kt
index 9611897e76..28459c9a5d 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/ResourcesExtensions.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/ResourcesExtensions.kt
@@ -1,16 +1,16 @@
package net.mullvad.mullvadvpn.compose.extensions
import android.content.res.Resources
+import java.time.Duration
import net.mullvad.mullvadvpn.R
-import org.joda.time.Duration
private const val DAYS_IN_STANDARD_YEAR = 365
fun Resources.getExpiryQuantityString(accountExpiry: Duration): String {
- val days = accountExpiry.standardDays.toInt()
- val years = (accountExpiry.standardDays / DAYS_IN_STANDARD_YEAR).toInt()
+ val days = accountExpiry.toDays().toInt()
+ val years = (accountExpiry.toDays() / DAYS_IN_STANDARD_YEAR).toInt()
- return if (accountExpiry.millis <= 0) {
+ return if (accountExpiry.toMillis() <= 0) {
getString(R.string.out_of_time)
} else if (years > 1) {
getRemainingText(this, R.plurals.years_left, years)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt
index c15e8b2a53..f40d0697ab 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt
@@ -1,6 +1,8 @@
package net.mullvad.mullvadvpn.compose.preview
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
import net.mullvad.mullvadvpn.compose.state.PaymentState
import net.mullvad.mullvadvpn.lib.model.AccountNumber
import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct
@@ -8,7 +10,6 @@ import net.mullvad.mullvadvpn.lib.payment.model.PaymentStatus
import net.mullvad.mullvadvpn.lib.payment.model.ProductId
import net.mullvad.mullvadvpn.lib.payment.model.ProductPrice
import net.mullvad.mullvadvpn.viewmodel.AccountUiState
-import org.joda.time.DateTime
class AccountUiStatePreviewParameterProvider : PreviewParameterProvider<AccountUiState> {
override val values =
@@ -16,7 +17,11 @@ class AccountUiStatePreviewParameterProvider : PreviewParameterProvider<AccountU
AccountUiState(
deviceName = "Test Name",
accountNumber = AccountNumber("1234123412341234"),
- accountExpiry = DateTime.parse("2050-12-01"),
+ accountExpiry =
+ ZonedDateTime.parse(
+ "2050-12-01T00:00:00.000Z",
+ DateTimeFormatter.ISO_ZONED_DATE_TIME,
+ ),
showSitePayment = true,
billingPaymentState =
PaymentState.PaymentAvailable(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DevicePreviewData.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DevicePreviewData.kt
index b87974d18b..82bf05ba64 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DevicePreviewData.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DevicePreviewData.kt
@@ -1,9 +1,10 @@
package net.mullvad.mullvadvpn.compose.preview
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
import net.mullvad.mullvadvpn.compose.state.DeviceItemUiState
import net.mullvad.mullvadvpn.lib.model.Device
import net.mullvad.mullvadvpn.lib.model.DeviceId
-import org.joda.time.DateTime
internal object DevicePreviewData {
fun generateDevices(count: Int) =
@@ -16,10 +17,11 @@ internal object DevicePreviewData {
Device(
id = DeviceId.fromString(id),
name = name ?: "Device $index-${id.take(DEVICE_SUFFIX_LENGTH)}",
- creationDate = DEVICE_CREATION_DATE.plusMonths(index),
+ creationDate = DEVICE_CREATION_DATE.plusMonths(index.toLong()),
)
}
private const val DEVICE_SUFFIX_LENGTH = 4
private const val UUID = "12345678-1234-5678-1234-567812345678"
-private val DEVICE_CREATION_DATE = DateTime.parse("2024-05-27")
+private val DEVICE_CREATION_DATE =
+ ZonedDateTime.parse("2024-05-27T00:00+00:00", DateTimeFormatter.ISO_ZONED_DATE_TIME)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt
index ddfb535faf..bd3d8b8bc5 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt
@@ -38,6 +38,7 @@ import com.ramcosta.composedestinations.generated.destinations.VerificationPendi
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.NavResult
import com.ramcosta.composedestinations.result.ResultRecipient
+import java.time.ZonedDateTime
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.button.ExternalButton
@@ -57,13 +58,12 @@ import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle
import net.mullvad.mullvadvpn.compose.util.SecureScreenWhileInView
import net.mullvad.mullvadvpn.compose.util.createCopyToClipboardHandle
import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately
+import net.mullvad.mullvadvpn.lib.common.util.toExpiryDateString
import net.mullvad.mullvadvpn.lib.payment.model.ProductId
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
-import net.mullvad.mullvadvpn.util.toExpiryDateString
import net.mullvad.mullvadvpn.viewmodel.AccountUiState
import net.mullvad.mullvadvpn.viewmodel.AccountViewModel
-import org.joda.time.DateTime
import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class)
@@ -256,7 +256,7 @@ private fun AccountNumberRow(accountNumber: String, onCopyAccountNumber: (String
}
@Composable
-private fun PaidUntilRow(accountExpiry: DateTime?) {
+private fun PaidUntilRow(accountExpiry: ZonedDateTime?) {
Column(modifier = Modifier.fillMaxWidth()) {
Text(
style = MaterialTheme.typography.labelMedium,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt
index 34ac8d98b7..0a9504f46c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt
@@ -56,6 +56,7 @@ import net.mullvad.mullvadvpn.compose.state.DeviceListUiState
import net.mullvad.mullvadvpn.compose.transitions.DefaultTransition
import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle
import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately
+import net.mullvad.mullvadvpn.lib.common.util.formatDate
import net.mullvad.mullvadvpn.lib.model.AccountNumber
import net.mullvad.mullvadvpn.lib.model.Device
import net.mullvad.mullvadvpn.lib.model.DeviceId
@@ -64,7 +65,6 @@ import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.selected
import net.mullvad.mullvadvpn.lib.theme.typeface.listItemSubText
import net.mullvad.mullvadvpn.lib.theme.typeface.listItemText
-import net.mullvad.mullvadvpn.util.formatDate
import net.mullvad.mullvadvpn.viewmodel.DeviceListSideEffect
import net.mullvad.mullvadvpn.viewmodel.DeviceListViewModel
import org.koin.androidx.compose.koinViewModel
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt
index 98b5219785..4e17b6918b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt
@@ -11,7 +11,7 @@ data class ConnectUiState(
val showLocation: Boolean,
val inAppNotification: InAppNotification?,
val deviceName: String?,
- val daysLeftUntilExpiry: Int?,
+ val daysLeftUntilExpiry: Long?,
val isPlayBuild: Boolean,
) {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/provider/MullvadFileProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/provider/MullvadFileProvider.kt
index 729fe5f2c2..b070f7c646 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/provider/MullvadFileProvider.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/provider/MullvadFileProvider.kt
@@ -5,9 +5,9 @@ import android.content.Intent
import android.net.Uri
import androidx.core.content.FileProvider
import java.io.File
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
import net.mullvad.mullvadvpn.R
-import org.joda.time.DateTime
-import org.joda.time.format.ISODateTimeFormat
// https://developer.android.com/reference/androidx/core/content/FileProvider
// From link: It is possible to use FileProvider directly instead of extending it. However, this is
@@ -51,6 +51,6 @@ fun Context.createCacheFile(directory: ProviderCacheDirectory, fileName: String)
}
fun createShareLogFileName(): String {
- val datetime = ISODateTimeFormat.basicOrdinalDateTimeNoMillis().print(DateTime.now())
+ val datetime = DateTimeFormatter.ofPattern("yyyyDDD'T'HHmmssZ").format(ZonedDateTime.now())
return "mullvad_log-${datetime}.txt"
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt
index 0fcee60bed..0e3e004f0b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt
@@ -1,5 +1,6 @@
package net.mullvad.mullvadvpn.repository
+import java.time.Duration
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
@@ -12,7 +13,6 @@ import net.mullvad.mullvadvpn.usecase.NewChangelogNotificationUseCase
import net.mullvad.mullvadvpn.usecase.NewDeviceNotificationUseCase
import net.mullvad.mullvadvpn.usecase.TunnelStateNotificationUseCase
import net.mullvad.mullvadvpn.usecase.VersionNotificationUseCase
-import org.joda.time.Duration
enum class StatusLevel {
Error,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt
index 8fd97dc63d..081c632255 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt
@@ -14,11 +14,11 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import net.mullvad.mullvadvpn.lib.common.util.millisFromNow
import net.mullvad.mullvadvpn.lib.model.ErrorStateCause
import net.mullvad.mullvadvpn.lib.model.TunnelState
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy
-import org.joda.time.DateTime
class OutOfTimeUseCase(
private val connectionProxy: ConnectionProxy,
@@ -60,7 +60,7 @@ class OutOfTimeUseCase(
.flatMapLatest {
if (it != null) {
flow {
- val millisUntilExpiry = it.expiryDate.millis - DateTime.now().millis
+ val millisUntilExpiry = it.expiryDate.millisFromNow()
if (millisUntilExpiry > 0) {
emit(false)
delay(millisUntilExpiry)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/DateExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/DateExtensions.kt
deleted file mode 100644
index e11434257a..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/DateExtensions.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.mullvad.mullvadvpn.util
-
-import java.text.DateFormat
-import kotlin.time.Duration.Companion.milliseconds
-import kotlin.time.DurationUnit
-import org.joda.time.DateTime
-import org.joda.time.format.ISODateTimeFormat
-
-fun DateTime.formatDate(): String = ISODateTimeFormat.date().print(this)
-
-fun DateTime.toExpiryDateString(): String =
- DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(this.toDate())
-
-fun DateTime.daysFromNow() =
- (toInstant().millis - DateTime.now().toInstant().millis).milliseconds.toInt(DurationUnit.DAYS)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt
index 8297375ee3..8dd4253553 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModel.kt
@@ -3,6 +3,7 @@ package net.mullvad.mullvadvpn.viewmodel
import android.app.Activity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import java.time.ZonedDateTime
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -27,7 +28,6 @@ import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
import net.mullvad.mullvadvpn.util.isSuccess
import net.mullvad.mullvadvpn.util.toPaymentState
-import org.joda.time.DateTime
class AccountViewModel(
private val accountRepository: AccountRepository,
@@ -155,7 +155,7 @@ class AccountViewModel(
data class AccountUiState(
val deviceName: String?,
val accountNumber: AccountNumber?,
- val accountExpiry: DateTime?,
+ val accountExpiry: ZonedDateTime?,
val showSitePayment: Boolean,
val billingPaymentState: PaymentState? = null,
val showLogoutLoading: Boolean = false,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt
index 6e8b3f9009..d505c44179 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt
@@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.state.ConnectUiState
+import net.mullvad.mullvadvpn.lib.common.util.daysFromNow
import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect
import net.mullvad.mullvadvpn.lib.model.ConnectError
import net.mullvad.mullvadvpn.lib.model.DeviceState
@@ -34,7 +35,6 @@ import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
import net.mullvad.mullvadvpn.usecase.SelectedLocationTitleUseCase
import net.mullvad.mullvadvpn.util.combine
-import net.mullvad.mullvadvpn.util.daysFromNow
import net.mullvad.mullvadvpn.util.isSuccess
import net.mullvad.mullvadvpn.util.withPrev
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt
index 25a8a47da3..088b5f3ae2 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt
@@ -24,6 +24,7 @@ import net.mullvad.mullvadvpn.compose.state.LoginState.Idle
import net.mullvad.mullvadvpn.compose.state.LoginState.Loading
import net.mullvad.mullvadvpn.compose.state.LoginState.Success
import net.mullvad.mullvadvpn.compose.state.LoginUiState
+import net.mullvad.mullvadvpn.lib.common.util.isBeforeNowInstant
import net.mullvad.mullvadvpn.lib.model.AccountNumber
import net.mullvad.mullvadvpn.lib.model.LoginAccountError
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
@@ -137,7 +138,9 @@ class LoginViewModel(
viewModelScope.launch(dispatcher) {
// Find if user is out of time
val isOutOfTimeDeferred = async {
- accountRepository.accountData.mapNotNull { it?.expiryDate?.isBeforeNow }.first()
+ accountRepository.accountData
+ .mapNotNull { it?.expiryDate?.isBeforeNowInstant() }
+ .first()
}
// Always show successful login for some time.
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt
index 0ed85c94cd..fe0acd83c1 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/SplashViewModel.kt
@@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.selects.onTimeout
import kotlinx.coroutines.selects.select
import net.mullvad.mullvadvpn.constant.ACCOUNT_EXPIRY_TIMEOUT_MS
+import net.mullvad.mullvadvpn.lib.common.util.isBeforeNowInstant
import net.mullvad.mullvadvpn.lib.model.DeviceState
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
@@ -72,7 +73,7 @@ class SplashViewModel(
onTimeout(ACCOUNT_EXPIRY_TIMEOUT_MS) { null }
}
- return if (accountData != null && accountData.expiryDate.isBeforeNow) {
+ return if (accountData != null && accountData.expiryDate.isBeforeNowInstant()) {
SplashUiSideEffect.NavigateToOutOfTime
} else {
SplashUiSideEffect.NavigateToConnect
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt
index 67e0f7a54d..0e91390262 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt
@@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.compose.state.WelcomeUiState
+import net.mullvad.mullvadvpn.lib.common.util.isAfterNowInstant
import net.mullvad.mullvadvpn.lib.model.WebsiteAuthToken
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy
@@ -66,7 +67,7 @@ class WelcomeViewModel(
private fun hasAddedTimeEffect() =
accountRepository.accountData
.filterNotNull()
- .filter { it.expiryDate.minusHours(MIN_HOURS_PAST_ACCOUNT_EXPIRY).isAfterNow }
+ .filter { it.expiryDate.minusHours(MIN_HOURS_PAST_ACCOUNT_EXPIRY).isAfterNowInstant() }
.onEach { paymentUseCase.resetPurchaseResult() }
.map { UiSideEffect.OpenConnectScreen }
@@ -125,6 +126,6 @@ class WelcomeViewModel(
}
companion object {
- private const val MIN_HOURS_PAST_ACCOUNT_EXPIRY = 20
+ private const val MIN_HOURS_PAST_ACCOUNT_EXPIRY: Long = 20
}
}
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt
index d830f407ab..9a3672515d 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/AccountExpiryNotificationProviderTest.kt
@@ -5,6 +5,8 @@ import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
+import java.time.Duration
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.minutes
@@ -25,8 +27,6 @@ import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD
import net.mullvad.mullvadvpn.service.notifications.accountexpiry.AccountExpiryNotificationProvider
-import org.joda.time.DateTime
-import org.joda.time.Duration
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -80,7 +80,9 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should emit notification if expiry time is shorter than expiry warning threshold`() =
runTest {
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
+ setExpiry(
+ ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1)
+ )
provider.notifications.test {
assertTrue(awaitItem() is Notify)
expectNoEvents()
@@ -90,7 +92,7 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should emit cancel notification if user account is new`() = runTest {
isNewDevice.value = true
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
+ setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
provider.notifications.test {
assertTrue(awaitItem() is Cancel)
expectNoEvents()
@@ -100,7 +102,7 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should emit cancel notification if user account is logged out`() = runTest {
setIsLoggedIn(false)
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
+ setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
provider.notifications.test {
assertTrue(awaitItem() is Cancel)
expectNoEvents()
@@ -117,7 +119,7 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should emit zero duration notification when remaining time runs out`() = runTest {
- setExpiry(DateTime.now().plus(Duration.standardSeconds(60)))
+ setExpiry(ZonedDateTime.now().plus(Duration.ofSeconds(60)))
provider.notifications.test {
assertTrue(awaitItem() is Notify)
expectNoEvents()
@@ -135,7 +137,10 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should emit notification when update interval is passed`() = runTest {
setExpiry(
- DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1).plusHours(1)
+ ZonedDateTime.now()
+ .plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD)
+ .minusDays(1)
+ .plusHours(1)
)
provider.notifications.test {
assertTrue(awaitItem() is Notify)
@@ -152,12 +157,14 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should cancel existing notification if more time is added to account`() = runTest {
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
+ setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
provider.notifications.test {
assertTrue(awaitItem() is Notify)
expectNoEvents()
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).plusDays(1))
+ setExpiry(
+ ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).plusDays(1)
+ )
assertTrue(awaitItem() is Cancel)
expectNoEvents()
}
@@ -165,12 +172,14 @@ class AccountExpiryNotificationProviderTest {
@Test
fun `should not cancel existing notification if too little time is added`() = runTest {
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
+ setExpiry(ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusDays(1))
provider.notifications.test {
assertTrue(awaitItem() is Notify)
expectNoEvents()
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusHours(1))
+ setExpiry(
+ ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).minusHours(1)
+ )
assertTrue(awaitItem() is Notify)
expectNoEvents()
}
@@ -184,7 +193,7 @@ class AccountExpiryNotificationProviderTest {
is Notify -> awaitItem.value
}
- private fun setExpiry(expiryDateTime: DateTime): DateTime {
+ private fun setExpiry(expiryDateTime: ZonedDateTime): ZonedDateTime {
val expiry = AccountData(mockk(relaxed = true), expiryDateTime)
accountData.value = expiry
return expiryDateTime
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt
index c8b27f2e6f..9db14ad914 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt
@@ -5,6 +5,7 @@ import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
+import java.time.Duration
import kotlin.test.assertEquals
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -21,7 +22,6 @@ import net.mullvad.mullvadvpn.usecase.NewChangelogNotificationUseCase
import net.mullvad.mullvadvpn.usecase.NewDeviceNotificationUseCase
import net.mullvad.mullvadvpn.usecase.TunnelStateNotificationUseCase
import net.mullvad.mullvadvpn.usecase.VersionNotificationUseCase
-import org.joda.time.Duration
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt
index 316d12addd..68b29790ac 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/AccountExpiryInAppNotificationUseCaseTest.kt
@@ -7,6 +7,8 @@ import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
+import java.time.Duration
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds
@@ -19,8 +21,6 @@ import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.repository.InAppNotification
import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD
import net.mullvad.mullvadvpn.service.notifications.accountexpiry.ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL
-import org.joda.time.DateTime
-import org.joda.time.Duration
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -33,7 +33,7 @@ class AccountExpiryInAppNotificationUseCaseTest {
private lateinit var accountExpiryInAppNotificationUseCase:
AccountExpiryInAppNotificationUseCase
- private lateinit var notificationThreshold: DateTime
+ private lateinit var notificationThreshold: ZonedDateTime
@BeforeEach
fun setup() {
@@ -45,7 +45,7 @@ class AccountExpiryInAppNotificationUseCaseTest {
accountExpiryInAppNotificationUseCase =
AccountExpiryInAppNotificationUseCase(accountRepository)
- notificationThreshold = DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD)
+ notificationThreshold = ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD)
}
@AfterEach
@@ -102,7 +102,7 @@ class AccountExpiryInAppNotificationUseCaseTest {
// Set expiry to to be in the final update interval.
val inLastUpdate =
- DateTime.now()
+ ZonedDateTime.now()
.plus(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL)
.minusSeconds(1)
val expiry = setExpiry(inLastUpdate)
@@ -113,34 +113,37 @@ class AccountExpiryInAppNotificationUseCaseTest {
expectNoEvents()
// Advance past the delay before the while loop:
- advanceTimeBy(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL.millis)
+ advanceTimeBy(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL.toMillis())
// Advance past the delay after the while loop:
- advanceTimeBy(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL.millis)
+ advanceTimeBy(ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL.toMillis())
assertEquals(Duration.ZERO, getExpiryNotificationDuration(expectMostRecentItem()))
expectNoEvents()
// Make sure we reset the list of notifications emitted when new time is added
- setExpiry(DateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).plusDays(1))
+ setExpiry(
+ ZonedDateTime.now().plus(ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD).plusDays(1)
+ )
assertEquals(emptyList(), expectMostRecentItem())
}
}
- private fun setExpiry(expiryDateTime: DateTime): DateTime {
+ private fun setExpiry(expiryDateTime: ZonedDateTime): ZonedDateTime {
val expiry = AccountData(mockk(relaxed = true), expiryDateTime)
accountExpiry.value = expiry
return expiryDateTime
}
// Assert that we got a single AccountExpiry notification and that the expiry duration is within
- // the expected range (checking exact duration value is not possible since we use DateTime.now)
+ // the expected range (checking exact duration value is not possible since we use
+ // ZonedDateTime.now)
private fun assertExpiryNotificationDuration(
- expiry: DateTime,
+ expiry: ZonedDateTime,
notifications: List<InAppNotification>,
) {
val notificationDuration = getExpiryNotificationDuration(notifications)
- val expiresFromNow = Duration(DateTime.now(), expiry)
+ val expiresFromNow = Duration.between(ZonedDateTime.now(), expiry)
assertTrue(expiresFromNow <= notificationDuration)
- assertTrue(expiresFromNow.plus(Duration.standardSeconds(5)) > notificationDuration)
+ assertTrue(expiresFromNow.plus(Duration.ofSeconds(5)) > notificationDuration)
}
private fun getExpiryNotificationDuration(notifications: List<InAppNotification>): Duration {
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceNotificationUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceNotificationUseCaseTest.kt
index 32cc48f2c5..2c97ea36a1 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceNotificationUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/NewDeviceNotificationUseCaseTest.kt
@@ -5,6 +5,7 @@ import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.unmockkAll
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlinx.coroutines.flow.MutableStateFlow
@@ -18,7 +19,6 @@ import net.mullvad.mullvadvpn.lib.model.DeviceState
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
import net.mullvad.mullvadvpn.repository.InAppNotification
import net.mullvad.mullvadvpn.repository.NewDeviceRepository
-import org.joda.time.DateTime
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -35,7 +35,7 @@ class NewDeviceNotificationUseCaseTest {
Device(
id = DeviceId.fromString(UUID),
name = deviceName,
- creationDate = DateTime.now(),
+ creationDate = ZonedDateTime.now(),
),
)
)
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt
index f8ecefbffd..4fd3ba08d1 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCaseTest.kt
@@ -4,6 +4,7 @@ import app.cash.turbine.test
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.minutes
@@ -26,7 +27,6 @@ import net.mullvad.mullvadvpn.lib.model.ErrorStateCause
import net.mullvad.mullvadvpn.lib.model.TunnelState
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy
-import org.joda.time.DateTime
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -91,7 +91,7 @@ class OutOfTimeUseCaseTest {
scope.runTest {
// Arrange
val expiredAccountExpiry =
- AccountData(mockk(relaxed = true), DateTime.now().plusDays(1))
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(1))
val tunnelStateChanges =
listOf(
TunnelState.Disconnected(),
@@ -120,7 +120,7 @@ class OutOfTimeUseCaseTest {
scope.runTest {
// Arrange
val expiredAccountExpiry =
- AccountData(mockk(relaxed = true), DateTime.now().minusDays(1))
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().minusDays(1))
// Act, Assert
outOfTimeUseCase.isOutOfTime.test {
assertEquals(null, awaitItem())
@@ -134,7 +134,7 @@ class OutOfTimeUseCaseTest {
scope.runTest {
// Arrange
val notExpiredAccountExpiry =
- AccountData(mockk(relaxed = true), DateTime.now().plusDays(1))
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(1))
// Act, Assert
outOfTimeUseCase.isOutOfTime.test {
@@ -149,7 +149,7 @@ class OutOfTimeUseCaseTest {
scope.runTest {
// Arrange
val expiredAccountExpiry =
- AccountData(mockk(relaxed = true), DateTime.now().plusSeconds(100))
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusSeconds(100))
// Act, Assert
outOfTimeUseCase.isOutOfTime.test {
// Initial event
@@ -173,7 +173,7 @@ class OutOfTimeUseCaseTest {
scope.runTest {
// Arrange
val initialAccountExpiry =
- AccountData(mockk(relaxed = true), DateTime.now().plusSeconds(100))
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusSeconds(100))
val updatedExpiry =
AccountData(mockk(relaxed = true), initialAccountExpiry.expiryDate.plusDays(30))
@@ -203,7 +203,7 @@ class OutOfTimeUseCaseTest {
scope.runTest {
// Arrange
val initialAccountExpiry =
- AccountData(mockk(relaxed = true), DateTime.now().plusSeconds(100))
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusSeconds(100))
val updatedExpiry =
AccountData(mockk(relaxed = true), initialAccountExpiry.expiryDate.plusDays(30))
// Act, Assert
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
index 0a9d2f36f9..74a6bbd414 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/AccountViewModelTest.kt
@@ -9,6 +9,7 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkAll
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlinx.coroutines.flow.MutableStateFlow
@@ -28,7 +29,6 @@ import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
-import org.joda.time.DateTime
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -42,7 +42,11 @@ class AccountViewModelTest {
private val mockPaymentUseCase: PaymentUseCase = mockk(relaxed = true)
private val dummyDevice =
- Device(id = DeviceId.fromString(UUID), name = "fake_name", creationDate = DateTime.now())
+ Device(
+ id = DeviceId.fromString(UUID),
+ name = "fake_name",
+ creationDate = ZonedDateTime.now(),
+ )
private val dummyAccountNumber: AccountNumber = AccountNumber(DUMMY_DEVICE_NAME)
private val deviceState: MutableStateFlow<DeviceState?> =
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
index 1a80597066..a2be07e0a6 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModelTest.kt
@@ -11,6 +11,7 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
+import java.time.ZonedDateTime
import kotlin.test.assertIs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -29,7 +30,6 @@ import net.mullvad.mullvadvpn.lib.model.AccountNumber
import net.mullvad.mullvadvpn.lib.model.LoginAccountError
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.usecase.InternetAvailableUseCase
-import org.joda.time.DateTime
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -133,7 +133,9 @@ class LoginViewModelTest {
val sideEffects = loginViewModel.uiSideEffect.testIn(backgroundScope)
coEvery { mockedAccountRepository.login(any()) } returns Unit.right()
coEvery { mockedAccountRepository.accountData } returns
- MutableStateFlow(AccountData(mockk(relaxed = true), DateTime.now().plusDays(3)))
+ MutableStateFlow(
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(3))
+ )
// Act, Assert
uiStates.skipDefaultItem()
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
index 6c1ff9e1a2..bfaed10629 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/OutOfTimeViewModelTest.kt
@@ -31,8 +31,6 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
-import org.joda.time.DateTime
-import org.joda.time.ReadableInstant
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -132,10 +130,6 @@ class OutOfTimeViewModelTest {
@Test
fun `when OutOfTimeUseCase returns false uiSideEffect should emit OpenConnectScreen`() =
runTest {
- // Arrange
- val mockExpiryDate: DateTime = mockk()
- every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true
-
// Act, Assert
viewModel.uiSideEffect.test {
outOfTimeFlow.value = false
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt
index 3bd96de3cb..e5ae99d872 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VoucherDialogViewModelTest.kt
@@ -8,6 +8,7 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertTrue
@@ -18,7 +19,6 @@ import net.mullvad.mullvadvpn.lib.model.RedeemVoucherError
import net.mullvad.mullvadvpn.lib.model.RedeemVoucherSuccess
import net.mullvad.mullvadvpn.lib.model.VoucherCode
import net.mullvad.mullvadvpn.lib.shared.VoucherRepository
-import org.joda.time.DateTime
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -50,7 +50,7 @@ class VoucherDialogViewModelTest {
// Arrange
val timeAdded = 0L
- val newExpiry = DateTime()
+ val newExpiry = ZonedDateTime.now()
coEvery { mockVoucherRepository.submitVoucher(parsedVoucher) } returns
RedeemVoucherSuccess(timeAdded, newExpiry).right()
@@ -89,7 +89,7 @@ class VoucherDialogViewModelTest {
every { mockVoucherSubmission.timeAdded } returns 0
coEvery {
mockVoucherRepository.submitVoucher(VoucherCode.fromString(voucher).getOrNull()!!)
- } returns RedeemVoucherSuccess(0, DateTime()).right()
+ } returns RedeemVoucherSuccess(0, ZonedDateTime.now()).right()
// Act, Assert
viewModel.uiState.test {
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
index 3fe3804b8b..b2b59ba69e 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt
@@ -9,6 +9,7 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkAll
+import java.time.ZonedDateTime
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlinx.coroutines.cancel
@@ -32,7 +33,6 @@ import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
-import org.joda.time.DateTime
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -146,7 +146,9 @@ class WelcomeViewModelTest {
@Test
fun `when user has added time then uiSideEffect should emit OpenConnectScreen`() = runTest {
// Arrange
- accountExpiryStateFlow.emit(AccountData(mockk(relaxed = true), DateTime().plusDays(1)))
+ accountExpiryStateFlow.emit(
+ AccountData(mockk(relaxed = true), ZonedDateTime.now().plusDays(1))
+ )
// Act, Assert
viewModel.uiSideEffect.test {
diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml
index da2a4b6c54..401c5681f7 100644
--- a/android/gradle/libs.versions.toml
+++ b/android/gradle/libs.versions.toml
@@ -64,7 +64,6 @@ commonsvalidator = "1.9.0"
# Upgrading to 12.0.1 results in task failing, DROID-1517
dependency-versions = "0.52.0"
detekt = "1.23.7"
-jodatime = "2.13.1"
kermit = "2.0.5"
konsist = "0.17.3"
ktfmt = "0.22.0"
@@ -160,7 +159,6 @@ mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockk" }
# Misc
commons-validator = { module = "commons-validator:commons-validator", version.ref = "commonsvalidator" }
-jodatime = { module = "joda-time:joda-time", version.ref = "jodatime" }
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
konsist = { module = "com.lemonappdev:konsist", version.ref = "konsist" }
leakCanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }
diff --git a/android/gradle/verification-metadata.xml b/android/gradle/verification-metadata.xml
index af78ab4c0d..b11716d5a9 100644
--- a/android/gradle/verification-metadata.xml
+++ b/android/gradle/verification-metadata.xml
@@ -4749,11 +4749,6 @@
<sha256 value="91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff" origin="Generated by Gradle"/>
</artifact>
</component>
- <component group="joda-time" name="joda-time" version="2.13.1">
- <artifact name="joda-time-2.13.1.jar">
- <sha256 value="a9be47b46390f7a6dabacc7c055b4feb6fb8f2225477a7270a8233b296e26677" origin="Generated by Gradle"/>
- </artifact>
- </component>
<component group="junit" name="junit" version="4.13.2">
<artifact name="junit-4.13.2.jar">
<sha256 value="8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3" origin="Generated by Gradle"/>
diff --git a/android/lib/common/build.gradle.kts b/android/lib/common/build.gradle.kts
index c8554b52c7..24468d9815 100644
--- a/android/lib/common/build.gradle.kts
+++ b/android/lib/common/build.gradle.kts
@@ -34,7 +34,6 @@ dependencies {
implementation(libs.arrow)
implementation(libs.androidx.appcompat)
- implementation(libs.jodatime)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kermit)
diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt
index 536fea3d24..e34bfa582e 100644
--- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt
+++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt
@@ -1,22 +1,8 @@
package net.mullvad.mullvadvpn.lib.common.util
-import org.joda.time.DateTime
-import org.joda.time.format.DateTimeFormat
-
-private const val EXPIRY_FORMAT = "YYYY-MM-dd HH:mm:ss z"
private const val BIG_DOT_CHAR = "●"
private const val SPACE_CHAR = ' '
-fun String.parseAsDateTime(): DateTime? {
- return try {
- DateTime.parse(this, DateTimeFormat.forPattern(EXPIRY_FORMAT))
- } catch (ex: IllegalArgumentException) {
- null
- } catch (ex: UnsupportedOperationException) {
- null
- }
-}
-
fun String.groupWithSpaces(groupCharSize: Int = 4): String {
return fold(StringBuilder()) { formattedText, nextDigit ->
if ((formattedText.length % (groupCharSize + 1)) == groupCharSize) {
diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/DateExtensions.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/DateExtensions.kt
new file mode 100644
index 0000000000..74fe9d6ba0
--- /dev/null
+++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/DateExtensions.kt
@@ -0,0 +1,20 @@
+package net.mullvad.mullvadvpn.lib.common.util
+
+import java.time.Duration
+import java.time.Instant
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
+
+fun ZonedDateTime.formatDate(): String = DateTimeFormatter.ISO_LOCAL_DATE.format(this)
+
+fun ZonedDateTime.toExpiryDateString(): String =
+ DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).format(this)
+
+fun ZonedDateTime.millisFromNow(): Long = Duration.between(ZonedDateTime.now(), this).toMillis()
+
+fun ZonedDateTime.daysFromNow(): Long = Duration.between(ZonedDateTime.now(), this).toDays()
+
+fun ZonedDateTime.isBeforeNowInstant(): Boolean = toInstant().isBefore(Instant.now())
+
+fun ZonedDateTime.isAfterNowInstant(): Boolean = toInstant().isAfter(Instant.now())
diff --git a/android/lib/daemon-grpc/build.gradle.kts b/android/lib/daemon-grpc/build.gradle.kts
index 60e2073843..f3b8799f95 100644
--- a/android/lib/daemon-grpc/build.gradle.kts
+++ b/android/lib/daemon-grpc/build.gradle.kts
@@ -63,7 +63,6 @@ dependencies {
implementation(projects.lib.model)
implementation(projects.lib.talpid)
- implementation(libs.jodatime)
implementation(libs.kermit)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
index fe4cf11881..717bf401f4 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
@@ -5,6 +5,8 @@ package net.mullvad.mullvadvpn.lib.daemon.grpc.mapper
import io.grpc.ConnectivityState
import java.net.InetAddress
import java.net.InetSocketAddress
+import java.time.Instant
+import java.time.ZoneId
import java.util.UUID
import mullvad_daemon.management_interface.ManagementInterface
import net.mullvad.mullvadvpn.lib.daemon.grpc.GrpcConnectivityState
@@ -72,7 +74,6 @@ import net.mullvad.mullvadvpn.lib.model.WireguardConstraints
import net.mullvad.mullvadvpn.lib.model.WireguardEndpointData
import net.mullvad.mullvadvpn.lib.model.WireguardRelayEndpointData
import net.mullvad.mullvadvpn.lib.model.WireguardTunnelOptions
-import org.joda.time.Instant
internal fun ManagementInterface.TunnelState.toDomain(): TunnelState =
when (stateCase!!) {
@@ -570,8 +571,10 @@ internal fun ManagementInterface.Relay.toDomain(
} else false,
)
+private fun Instant.atDefaultZone() = atZone(ZoneId.systemDefault())
+
internal fun ManagementInterface.Device.toDomain(): Device =
- Device(DeviceId.fromString(id), name, Instant.ofEpochSecond(created.seconds).toDateTime())
+ Device(DeviceId.fromString(id), name, Instant.ofEpochSecond(created.seconds).atDefaultZone())
internal fun ManagementInterface.DeviceState.toDomain(): DeviceState =
when (state) {
@@ -587,13 +590,13 @@ internal fun ManagementInterface.DeviceState.toDomain(): DeviceState =
internal fun ManagementInterface.AccountData.toDomain(): AccountData =
AccountData(
AccountId(UUID.fromString(id)),
- expiryDate = Instant.ofEpochSecond(expiry.seconds).toDateTime(),
+ expiryDate = Instant.ofEpochSecond(expiry.seconds).atDefaultZone(),
)
internal fun ManagementInterface.VoucherSubmission.toDomain(): RedeemVoucherSuccess =
RedeemVoucherSuccess(
timeAdded = secondsAdded,
- newExpiryDate = Instant.ofEpochSecond(newExpiry.seconds).toDateTime(),
+ newExpiryDate = Instant.ofEpochSecond(newExpiry.seconds).atDefaultZone(),
)
internal fun ManagementInterface.SplitTunnelSettings.toDomain(): SplitTunnelSettings =
diff --git a/android/lib/model/build.gradle.kts b/android/lib/model/build.gradle.kts
index c961dcc32f..f83ff3d5d4 100644
--- a/android/lib/model/build.gradle.kts
+++ b/android/lib/model/build.gradle.kts
@@ -35,7 +35,6 @@ android {
}
dependencies {
- implementation(libs.jodatime)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.arrow)
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/AccountData.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/AccountData.kt
index 8a4182b2e5..b1746e1bcc 100644
--- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/AccountData.kt
+++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/AccountData.kt
@@ -1,5 +1,5 @@
package net.mullvad.mullvadvpn.lib.model
-import org.joda.time.DateTime
+import java.time.ZonedDateTime
-data class AccountData(val id: AccountId, val expiryDate: DateTime)
+data class AccountData(val id: AccountId, val expiryDate: ZonedDateTime)
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Device.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Device.kt
index e8303f0eca..3eb92f2f8f 100644
--- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Device.kt
+++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Device.kt
@@ -1,12 +1,12 @@
package net.mullvad.mullvadvpn.lib.model
import android.os.Parcelable
+import java.time.ZonedDateTime
import kotlinx.parcelize.Parcelize
import net.mullvad.mullvadvpn.lib.model.extensions.startCase
-import org.joda.time.DateTime
@Parcelize
-data class Device(val id: DeviceId, private val name: String, val creationDate: DateTime) :
+data class Device(val id: DeviceId, private val name: String, val creationDate: ZonedDateTime) :
Parcelable {
fun displayName(): String = name.startCase()
}
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Notification.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Notification.kt
index acb8d74907..6b073988a3 100644
--- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Notification.kt
+++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Notification.kt
@@ -1,6 +1,6 @@
package net.mullvad.mullvadvpn.lib.model
-import org.joda.time.Duration
+import java.time.Duration
sealed interface Notification {
val actions: List<NotificationAction>
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/RedeemVoucherSuccess.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/RedeemVoucherSuccess.kt
index 9c81042b8c..53fa414047 100644
--- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/RedeemVoucherSuccess.kt
+++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/RedeemVoucherSuccess.kt
@@ -1,5 +1,5 @@
package net.mullvad.mullvadvpn.lib.model
-import org.joda.time.DateTime
+import java.time.ZonedDateTime
-data class RedeemVoucherSuccess(val timeAdded: Long, val newExpiryDate: DateTime)
+data class RedeemVoucherSuccess(val timeAdded: Long, val newExpiryDate: ZonedDateTime)
diff --git a/android/lib/shared/build.gradle.kts b/android/lib/shared/build.gradle.kts
index 4be82a9eb2..7e2730a9e9 100644
--- a/android/lib/shared/build.gradle.kts
+++ b/android/lib/shared/build.gradle.kts
@@ -41,7 +41,6 @@ dependencies {
implementation(libs.kermit)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.android)
- implementation(libs.jodatime)
testImplementation(libs.kotlin.test)
testImplementation(libs.kotlinx.coroutines.test)
diff --git a/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/AccountRepository.kt b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/AccountRepository.kt
index f6b146ecd3..a0edc2faa6 100644
--- a/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/AccountRepository.kt
+++ b/android/lib/shared/src/main/kotlin/net/mullvad/mullvadvpn/lib/shared/AccountRepository.kt
@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.lib.shared
import arrow.core.Either
import arrow.core.raise.nullable
+import java.time.ZonedDateTime
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -21,7 +22,6 @@ import net.mullvad.mullvadvpn.lib.model.CreateAccountError
import net.mullvad.mullvadvpn.lib.model.DeviceState
import net.mullvad.mullvadvpn.lib.model.LoginAccountError
import net.mullvad.mullvadvpn.lib.model.WebsiteAuthToken
-import org.joda.time.DateTime
class AccountRepository(
private val managementService: ManagementService,
@@ -87,7 +87,7 @@ class AccountRepository(
suspend fun getWebsiteAuthToken(): WebsiteAuthToken? =
managementService.getWebsiteAuthToken().getOrNull()
- internal suspend fun onVoucherRedeemed(newExpiry: DateTime) {
+ internal suspend fun onVoucherRedeemed(newExpiry: ZonedDateTime) {
accountData.value?.copy(expiryDate = newExpiry)?.let { _mutableAccountDataCache.emit(it) }
}
}
diff --git a/android/service/build.gradle.kts b/android/service/build.gradle.kts
index 8c9f0034cb..7fd560aa43 100644
--- a/android/service/build.gradle.kts
+++ b/android/service/build.gradle.kts
@@ -79,5 +79,4 @@ dependencies {
implementation(libs.koin.android)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.android)
- implementation(libs.jodatime)
}
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryAndroidNotification.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryAndroidNotification.kt
index db9ee92ae7..a61561c8cc 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryAndroidNotification.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryAndroidNotification.kt
@@ -5,12 +5,12 @@ import android.content.Context
import android.content.Intent
import android.content.res.Resources
import androidx.core.app.NotificationCompat
+import java.time.Duration
import net.mullvad.mullvadvpn.lib.common.constant.MAIN_ACTIVITY_CLASS
import net.mullvad.mullvadvpn.lib.common.util.SdkUtils
import net.mullvad.mullvadvpn.lib.common.util.createAccountUri
import net.mullvad.mullvadvpn.lib.model.Notification
import net.mullvad.mullvadvpn.service.R
-import org.joda.time.Duration
internal fun Notification.AccountExpiry.toNotification(context: Context) =
NotificationCompat.Builder(context, channelId.value)
@@ -40,19 +40,19 @@ private fun Notification.AccountExpiry.contentIntent(context: Context): PendingI
private fun Resources.contentTitle(remainingTime: Duration): String =
when {
- remainingTime.isShorterThan(Duration.ZERO) || remainingTime == Duration.ZERO -> {
+ remainingTime <= Duration.ZERO -> {
getString(R.string.account_credit_has_expired)
}
- remainingTime.standardDays >= 1 -> {
+ remainingTime.toDays() >= 1 -> {
getRemainingText(
R.plurals.account_credit_expires_in_days,
- remainingTime.standardDays.toInt(),
+ remainingTime.toDays().toInt(),
)
}
- remainingTime.standardHours >= 1 -> {
+ remainingTime.toHours() >= 1 -> {
getRemainingText(
R.plurals.account_credit_expires_in_hours,
- remainingTime.standardHours.toInt(),
+ remainingTime.toHours().toInt(),
)
}
else -> getString(R.string.account_credit_expires_in_a_few_minutes)
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryConstant.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryConstant.kt
index 32190968b9..4ee9c6a533 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryConstant.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryConstant.kt
@@ -2,10 +2,10 @@
package net.mullvad.mullvadvpn.service.notifications.accountexpiry
+import java.time.Duration
import kotlin.time.Duration.Companion.seconds
-import org.joda.time.Duration
val ACCOUNT_EXPIRY_POLL_INTERVAL = 15.seconds
-val ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL: Duration = Duration.standardDays(1)
-val ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_UPDATE_INTERVAL: Duration = Duration.standardDays(1)
-val ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD: Duration = Duration.standardDays(3)
+val ACCOUNT_EXPIRY_IN_APP_NOTIFICATION_UPDATE_INTERVAL: Duration = Duration.ofDays(1)
+val ACCOUNT_EXPIRY_SYSTEM_NOTIFICATION_UPDATE_INTERVAL: Duration = Duration.ofDays(1)
+val ACCOUNT_EXPIRY_CLOSE_TO_EXPIRY_THRESHOLD: Duration = Duration.ofDays(3)
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryNotificationProvider.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryNotificationProvider.kt
index b513b490e0..be0141c3f4 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryNotificationProvider.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryNotificationProvider.kt
@@ -1,5 +1,6 @@
package net.mullvad.mullvadvpn.service.notifications.accountexpiry
+import java.time.ZonedDateTime
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -16,7 +17,6 @@ import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.DeviceRepository
import net.mullvad.mullvadvpn.service.constant.IS_PLAY_BUILD
import net.mullvad.mullvadvpn.service.notifications.NotificationProvider
-import org.joda.time.DateTime
class AccountExpiryNotificationProvider(
private val channelId: NotificationChannelId,
@@ -45,7 +45,7 @@ class AccountExpiryNotificationProvider(
}
private fun accountExpiryNotificationFlow(
- expiryDate: DateTime
+ expiryDate: ZonedDateTime
): Flow<NotificationUpdate<Notification.AccountExpiry>> =
AccountExpiryTicker.tickerFlow(
expiry = expiryDate,
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryTicker.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryTicker.kt
index 6add0a372a..cd872eee18 100644
--- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryTicker.kt
+++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/accountexpiry/AccountExpiryTicker.kt
@@ -1,10 +1,12 @@
package net.mullvad.mullvadvpn.service.notifications.accountexpiry
+import java.time.Duration
+import java.time.Instant
+import java.time.ZonedDateTime
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
-import org.joda.time.DateTime
-import org.joda.time.Duration
+import net.mullvad.mullvadvpn.lib.common.util.millisFromNow
sealed interface AccountExpiryTicker {
data object NotWithinThreshold : AccountExpiryTicker
@@ -13,9 +15,9 @@ sealed interface AccountExpiryTicker {
companion object {
fun tickerFlow(
- expiry: DateTime,
+ expiry: ZonedDateTime,
tickStart: Duration,
- updateInterval: (expiry: DateTime) -> Duration,
+ updateInterval: (expiry: ZonedDateTime) -> Duration,
): Flow<AccountExpiryTicker> = flow {
expiry.millisFromNow().let { expiryMillis ->
if (expiryMillis <= 0) {
@@ -23,20 +25,20 @@ sealed interface AccountExpiryTicker {
emit(Tick(Duration.ZERO))
return@flow
}
- if (expiryMillis > tickStart.millis) {
+ if (expiryMillis > tickStart.toMillis()) {
// Emit NotWithinThreshold if no expiry notification should be provided.
emit(NotWithinThreshold)
// Delay until the time we should start emitting.
- delay(expiryMillis - tickStart.millis + 1)
+ delay(expiryMillis - tickStart.toMillis() + 1)
}
}
- var currentUpdateInterval = updateInterval(expiry).millis
+ var currentUpdateInterval = updateInterval(expiry).toMillis()
do {
- emit(Tick(Duration(DateTime.now(), expiry)))
+ emit(Tick(Duration.between(Instant.now(), expiry)))
delay(millisUntilNextUpdate(expiry.millisFromNow(), currentUpdateInterval))
- currentUpdateInterval = updateInterval(expiry).millis
+ currentUpdateInterval = updateInterval(expiry).toMillis()
} while (hasAnotherEmission(expiry.millisFromNow(), currentUpdateInterval))
// We may have remaining time if the update interval wasn't a multiple of the remaining
@@ -67,5 +69,3 @@ private fun calculateDelaysNeeded(
millisUntilExpiry: Long,
currentUpdateIntervalMillis: Long,
): Long = millisUntilExpiry.coerceAtLeast(0) / currentUpdateIntervalMillis
-
-private fun DateTime.millisFromNow(): Long = Duration(DateTime.now(), this).millis
diff --git a/android/test/e2e/build.gradle.kts b/android/test/e2e/build.gradle.kts
index 3f4244cde7..8bcc45ab77 100644
--- a/android/test/e2e/build.gradle.kts
+++ b/android/test/e2e/build.gradle.kts
@@ -155,7 +155,6 @@ dependencies {
implementation(libs.ktor.client.cio)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.content.negotiation)
- implementation(libs.jodatime)
androidTestUtil(libs.androidx.test.orchestrator)
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt
index 5c788e5710..cd6b2b855e 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Packet.kt
@@ -1,23 +1,25 @@
package net.mullvad.mullvadvpn.test.e2e.router.packetCapture
+import java.time.ZonedDateTime
import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import net.mullvad.mullvadvpn.test.e2e.serializer.PacketSerializer
-import org.joda.time.DateTime
@Serializable(with = PacketSerializer::class)
sealed interface Packet {
- @SerialName("timestamp") val date: DateTime
+ @SerialName("timestamp") val date: ZonedDateTime
val fromPeer: Boolean
}
@Serializable
-data class RxPacket(@SerialName("timestamp") @Contextual override val date: DateTime) : Packet {
+data class RxPacket(@SerialName("timestamp") @Contextual override val date: ZonedDateTime) :
+ Packet {
@SerialName("from_peer") override val fromPeer: Boolean = false
}
@Serializable
-data class TxPacket(@SerialName("timestamp") @Contextual override val date: DateTime) : Packet {
+data class TxPacket(@SerialName("timestamp") @Contextual override val date: ZonedDateTime) :
+ Packet {
@SerialName("from_peer") override val fromPeer: Boolean = true
}
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt
index 564d0e25cb..68eb2783cc 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/router/packetCapture/Stream.kt
@@ -1,11 +1,11 @@
package net.mullvad.mullvadvpn.test.e2e.router.packetCapture
+import java.time.Duration
+import java.time.ZonedDateTime
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.mullvad.mullvadvpn.test.e2e.router.NetworkingProtocol
-import org.joda.time.DateTime
-import org.joda.time.Interval
@Serializable
data class Stream(
@@ -18,24 +18,26 @@ data class Stream(
@Transient val sourceHost = Host.fromString(sourceAddressAndPort)
@Transient val destinationHost = Host.fromString(destinationAddressAndPort)
- @Transient private val startDate: DateTime = packets.first().date
- @Transient private val endDate: DateTime = packets.last().date
- @Transient private val txStartDate: DateTime? = txPackets().firstOrNull()?.date
- @Transient private val txEndDate: DateTime? = txPackets().lastOrNull()?.date
- @Transient private val rxStartDate: DateTime? = rxPackets().firstOrNull()?.date
- @Transient private val rxEndDate: DateTime? = rxPackets().lastOrNull()?.date
+ @Transient private val startDate: ZonedDateTime = packets.first().date
+ @Transient private val endDate: ZonedDateTime = packets.last().date
+ @Transient private val txStartDate: ZonedDateTime? = txPackets().firstOrNull()?.date
+ @Transient private val txEndDate: ZonedDateTime? = txPackets().lastOrNull()?.date
+ @Transient private val rxStartDate: ZonedDateTime? = rxPackets().firstOrNull()?.date
+ @Transient private val rxEndDate: ZonedDateTime? = rxPackets().lastOrNull()?.date
- @Transient val interval = Interval(startDate, endDate)
+ @Transient val interval = Duration.between(startDate, endDate)
fun txPackets(): List<TxPacket> = packets.filterIsInstance<TxPacket>()
fun rxPackets(): List<RxPacket> = packets.filterIsInstance<RxPacket>()
- fun txInterval(): Interval? =
- if (txStartDate != null && txEndDate != null) Interval(txStartDate, txEndDate) else null
+ fun txInterval(): Duration? =
+ if (txStartDate != null && txEndDate != null) Duration.between(txStartDate, txEndDate)
+ else null
- fun rxInterval(): Interval? =
- if (rxStartDate != null && rxEndDate != null) Interval(rxStartDate, rxEndDate) else null
+ fun rxInterval(): Duration? =
+ if (rxStartDate != null && rxEndDate != null) Duration.between(rxStartDate, rxEndDate)
+ else null
init {
require(packets.isNotEmpty()) { "Stream must contain at least one packet" }
diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/NanoSecondsTimestampSerializer.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/NanoSecondsTimestampSerializer.kt
index d49ca6017d..26d5f05f5b 100644
--- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/NanoSecondsTimestampSerializer.kt
+++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/serializer/NanoSecondsTimestampSerializer.kt
@@ -1,23 +1,25 @@
package net.mullvad.mullvadvpn.test.e2e.serializer
+import java.time.Instant
+import java.time.ZoneId
+import java.time.ZonedDateTime
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
-import org.joda.time.DateTime
-object NanoSecondsTimestampSerializer : KSerializer<DateTime> {
+object NanoSecondsTimestampSerializer : KSerializer<ZonedDateTime> {
override val descriptor: SerialDescriptor =
- PrimitiveSerialDescriptor("DateTime", PrimitiveKind.LONG)
+ PrimitiveSerialDescriptor("ZonedDateTime", PrimitiveKind.LONG)
- override fun deserialize(decoder: Decoder): DateTime {
+ override fun deserialize(decoder: Decoder): ZonedDateTime {
val long = decoder.decodeLong()
- return DateTime(long / 1000)
+ return ZonedDateTime.ofInstant(Instant.ofEpochMilli(long / 1000), ZoneId.systemDefault())
}
- override fun serialize(encoder: Encoder, value: DateTime) {
+ override fun serialize(encoder: Encoder, value: ZonedDateTime) {
throw NotImplementedError("Only interested in deserialization")
}
}
diff --git a/android/test/mockapi/build.gradle.kts b/android/test/mockapi/build.gradle.kts
index a224b8c53f..f0310107ac 100644
--- a/android/test/mockapi/build.gradle.kts
+++ b/android/test/mockapi/build.gradle.kts
@@ -72,7 +72,6 @@ dependencies {
implementation(libs.androidx.test.rules)
implementation(libs.androidx.test.uiautomator)
implementation(libs.kermit)
- implementation(libs.jodatime)
implementation(Dependencies.junitJupiterApi)
implementation(Dependencies.junit5AndroidTestExtensions)
implementation(Dependencies.junit5AndroidTestRunner)
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt
index 2fe829841c..d89313fc45 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountExpiryMockApiTest.kt
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
@@ -8,8 +9,7 @@ import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
-import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero
-import net.mullvad.mullvadvpn.util.toExpiryDateString
+import net.mullvad.mullvadvpn.test.mockapi.util.toExpiryDateString
import org.junit.jupiter.api.Test
class AccountExpiryMockApiTest : MockApiTest() {
@@ -18,7 +18,7 @@ class AccountExpiryMockApiTest : MockApiTest() {
fun testAccountExpiryDateUpdated() {
// Arrange
val validAccountNumber = "1234123412341234"
- val oldAccountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1)
+ val oldAccountExpiry = ZonedDateTime.now().plusMonths(1)
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
accountExpiry = oldAccountExpiry
@@ -52,7 +52,7 @@ class AccountExpiryMockApiTest : MockApiTest() {
fun testAccountTimeExpiredWhileUsingTheAppShouldShowOutOfTimeScreen() {
// Arrange
val validAccountNumber = "1234123412341234"
- val oldAccountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1)
+ val oldAccountExpiry = ZonedDateTime.now().plusMonths(1)
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
accountExpiry = oldAccountExpiry
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt
index 7d4639019a..deb63c89b4 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/AccountHistoryMockApiTest.kt
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.compose.test.LOGIN_INPUT_TEST_TAG
import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
@@ -9,7 +10,6 @@ import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
-import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
@@ -21,7 +21,7 @@ class AccountHistoryMockApiTest : MockApiTest() {
val validAccountNumber = "1234123412341234"
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
- accountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1)
+ accountExpiry = ZonedDateTime.now().plusMonths(1)
devices = DEFAULT_DEVICE_LIST.toMutableMap()
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt
index f13e5070e2..5feee8abd8 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt
@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.compose.test.LOGIN_TITLE_TEST_TAG
import net.mullvad.mullvadvpn.test.common.constant.DEFAULT_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
@@ -10,7 +11,6 @@ import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShow
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
-import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
@@ -21,7 +21,7 @@ class LoginMockApiTest : MockApiTest() {
val validAccountNumber = "1234123412341234"
apiDispatcher.apply {
expectedAccountNumber = null
- accountExpiry = currentUtcTimeWithOffsetZero().plusDays(1)
+ accountExpiry = ZonedDateTime.now().plusDays(1)
}
app.launch(endpoint)
@@ -47,7 +47,7 @@ class LoginMockApiTest : MockApiTest() {
val validAccountNumber = "1234123412341234"
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
- accountExpiry = currentUtcTimeWithOffsetZero().plusDays(1)
+ accountExpiry = ZonedDateTime.now().plusDays(1)
devices = DEFAULT_DEVICE_LIST.toMutableMap()
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
@@ -70,7 +70,7 @@ class LoginMockApiTest : MockApiTest() {
val validAccountNumber = "1234123412341234"
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
- accountExpiry = currentUtcTimeWithOffsetZero().minusDays(1)
+ accountExpiry = ZonedDateTime.now().minusDays(1)
devices = DEFAULT_DEVICE_LIST.toMutableMap()
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt
index 3df42ac0ce..da41d41066 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
@@ -8,7 +9,6 @@ import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout
import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2
-import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
@@ -20,7 +20,7 @@ class LogoutMockApiTest : MockApiTest() {
val validAccountNumber = "1234123412341234"
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
- accountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1)
+ accountExpiry = ZonedDateTime.now().plusMonths(1)
devices = DEFAULT_DEVICE_LIST.toMutableMap()
devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt
index e230152efe..f99cb48a06 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.test.mockapi
import co.touchlab.kermit.Logger
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.test.mockapi.constant.ACCOUNT_URL_PATH
import net.mullvad.mullvadvpn.test.mockapi.constant.AUTH_TOKEN_URL_PATH
import net.mullvad.mullvadvpn.test.mockapi.constant.CREATE_ACCOUNT_URL_PATH
@@ -10,20 +11,18 @@ import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_1
import net.mullvad.mullvadvpn.test.mockapi.util.accessTokenJsonResponse
import net.mullvad.mullvadvpn.test.mockapi.util.accountCreationJson
import net.mullvad.mullvadvpn.test.mockapi.util.accountInfoJson
-import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero
import net.mullvad.mullvadvpn.test.mockapi.util.deviceJson
import net.mullvad.mullvadvpn.test.mockapi.util.tooManyDevicesJsonResponse
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest
import okio.Buffer
-import org.joda.time.DateTime
import org.json.JSONArray
class MockApiDispatcher : Dispatcher() {
var expectedAccountNumber: String? = null
- var accountExpiry: DateTime? = null
+ var accountExpiry: ZonedDateTime? = null
var devices: MutableMap<String, String>? = null
private val canAddDevices: Boolean
get() = (devices?.size ?: 0) < 5
@@ -84,7 +83,7 @@ class MockApiDispatcher : Dispatcher() {
.setBody(
accessTokenJsonResponse(
accessToken = DUMMY_ACCESS_TOKEN,
- expiry = currentUtcTimeWithOffsetZero().plusDays(1),
+ expiry = ZonedDateTime.now().plusDays(1),
)
.toString()
)
@@ -115,7 +114,7 @@ class MockApiDispatcher : Dispatcher() {
id = deviceId,
name = devices!![deviceId]!!, // Should always exist
publicKey = cachedKey,
- creationDate = currentUtcTimeWithOffsetZero().minusDays(1),
+ creationDate = ZonedDateTime.now().minusDays(1),
)
.toString()
)
@@ -136,7 +135,7 @@ class MockApiDispatcher : Dispatcher() {
id = devicePendingToGetCreated!!.first,
name = devicePendingToGetCreated!!.second,
publicKey = newKey,
- creationDate = currentUtcTimeWithOffsetZero().minusDays(1),
+ creationDate = ZonedDateTime.now().minusDays(1),
)
.toString()
)
@@ -158,7 +157,7 @@ class MockApiDispatcher : Dispatcher() {
id = entry.key,
name = entry.value,
publicKey = cachedKey,
- creationDate = currentUtcTimeWithOffsetZero().minusDays(index + 1),
+ creationDate = ZonedDateTime.now().minusDays((index + 1).toLong()),
)
)
}
@@ -174,7 +173,7 @@ class MockApiDispatcher : Dispatcher() {
.setBody(
accountCreationJson(
id = DUMMY_ID_1,
- expiry = DateTime(),
+ expiry = ZonedDateTime.now(),
accountNumber = expectedAccountNumber,
)
.toString()
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt
index bde2a8f4dd..19674815c1 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.test.mockapi
import androidx.test.uiautomator.By
+import java.time.ZonedDateTime
import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer
import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove
import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown
@@ -17,7 +18,6 @@ import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_3
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_4
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_5
import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_6
-import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero
import org.junit.jupiter.api.Test
class TooManyDevicesMockApiTest : MockApiTest() {
@@ -27,7 +27,7 @@ class TooManyDevicesMockApiTest : MockApiTest() {
val validAccountNumber = "1234123412341234"
apiDispatcher.apply {
expectedAccountNumber = validAccountNumber
- accountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1)
+ accountExpiry = ZonedDateTime.now().plusMonths(1)
devices =
mutableMapOf(
DUMMY_ID_1 to DUMMY_DEVICE_NAME_1,
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt
index 81042f70d2..330fc15a81 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt
@@ -1,13 +1,14 @@
package net.mullvad.mullvadvpn.test.mockapi.util
-import org.joda.time.DateTime
-import org.joda.time.DateTimeZone
-import org.joda.time.format.DateTimeFormat
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
private const val STRICT_ISO8601_AND_RFC3339_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZZ"
-fun currentUtcTimeWithOffsetZero() = DateTime.now(DateTimeZone.forOffsetHours(0))
-
-fun DateTime.formatStrictlyAccordingToIso8601AndRfc3339(): String {
- return toString(DateTimeFormat.forPattern(STRICT_ISO8601_AND_RFC3339_PATTERN))
+fun ZonedDateTime.formatStrictlyAccordingToIso8601AndRfc3339(): String {
+ return DateTimeFormatter.ofPattern(STRICT_ISO8601_AND_RFC3339_PATTERN).format(this)
}
+
+fun ZonedDateTime.toExpiryDateString(): String =
+ DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).format(this)
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt
index 2de385c7f8..a0e21d55ca 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt
@@ -1,9 +1,9 @@
package net.mullvad.mullvadvpn.test.mockapi.util
-import org.joda.time.DateTime
+import java.time.ZonedDateTime
import org.json.JSONObject
-fun accountInfoJson(id: String, expiry: DateTime) =
+fun accountInfoJson(id: String, expiry: ZonedDateTime) =
JSONObject().apply {
put("id", id)
put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339())
@@ -11,10 +11,10 @@ fun accountInfoJson(id: String, expiry: DateTime) =
put("can_add_devices", true)
}
-fun accountCreationJson(id: String, accountNumber: String, expiry: DateTime) =
+fun accountCreationJson(id: String, accountNumber: String, expiry: ZonedDateTime) =
accountInfoJson(id, expiry).apply { put("number", accountNumber) }
-fun deviceJson(id: String, name: String, publicKey: String, creationDate: DateTime) =
+fun deviceJson(id: String, name: String, publicKey: String, creationDate: ZonedDateTime) =
JSONObject().apply {
put("id", id)
put("name", name)
@@ -25,7 +25,7 @@ fun deviceJson(id: String, name: String, publicKey: String, creationDate: DateTi
put("ipv6_address", "fc00::1/128")
}
-fun accessTokenJsonResponse(accessToken: String, expiry: DateTime) =
+fun accessTokenJsonResponse(accessToken: String, expiry: ZonedDateTime) =
JSONObject().apply {
put("access_token", accessToken)
put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339())