From 627e1209419a1e80ec5fff1c9028c84a9fb49e8a Mon Sep 17 00:00:00 2001 From: ialokim <ialokim@mailbox.org> Date: Wed, 19 Jan 2022 11:34:28 +0100 Subject: [PATCH] allow manual testing of expiration and address review comments --- .../desktop/expiration/ExpirationBanner.kt | 53 ++++++++++++------- .../desktop/expiration/ExpirationUtils.kt | 49 +++++++++++++++-- .../briar/desktop/login/ErrorScreen.kt | 50 +++++++++-------- .../briar/desktop/login/ErrorSubViewModel.kt | 4 +- .../briar/desktop/login/StartupViewModel.kt | 4 +- .../briarproject/briar/desktop/theme/Theme.kt | 6 ++- .../briarproject/briar/desktop/ui/BriarUi.kt | 8 ++- .../briar/desktop/ui/Constants.kt | 1 - .../resources/strings/BriarDesktop.properties | 3 +- 9 files changed, 121 insertions(+), 57 deletions(-) diff --git a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt index 9205a0e520..17621db95c 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt @@ -1,3 +1,21 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + package org.briarproject.briar.desktop.expiration import androidx.compose.foundation.layout.Arrangement @@ -5,6 +23,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface @@ -20,14 +39,10 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.briarproject.briar.desktop.expiration.ExpirationUtils.getDaysLeft -import org.briarproject.briar.desktop.expiration.ExpirationUtils.isExpired +import org.briarproject.briar.desktop.expiration.ExpirationUtils.periodicallyCheckIfExpired import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nP import org.briarproject.briar.desktop.utils.PreviewUtils.preview -import kotlin.time.Duration.Companion.hours fun main() = preview { Column { @@ -39,20 +54,15 @@ fun main() = preview { fun ExpirationBanner(onExpired: () -> Unit) { var daysLeft by remember { mutableStateOf(0) } + var expired by remember { mutableStateOf(false) } LaunchedEffect(Unit) { - launch { - while (true) { - daysLeft = getDaysLeft() - if (isExpired()) { - onExpired() - break - } - delay(1.hours.inWholeMilliseconds) - } - } + periodicallyCheckIfExpired( + reportDaysLeft = { daysLeft = it }, + onExpired = { expired = true; onExpired() }, + ) } - ExpirationBanner(daysLeft) + if (!expired) ExpirationBanner(daysLeft) } @Composable @@ -63,11 +73,14 @@ fun ExpirationBanner( modifier = Modifier.fillMaxWidth() ) { Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(24.dp), verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(8.dp) + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp) ) { - Icon(Icons.Filled.Warning, i18n("warning")) - Text(i18nP("expiration.banner", daysLeft)) + Icon(Icons.Filled.Warning, i18n("warning"), Modifier.size(40.dp)) + Text( + text = "${i18nP("expiration.banner.part1", daysLeft)} ${i18n("expiration.banner.part2")}", + style = MaterialTheme.typography.body2 + ) } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt index 7a51a741e5..d9716edd92 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt @@ -1,12 +1,55 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + package org.briarproject.briar.desktop.expiration +import kotlinx.coroutines.delay import org.briarproject.briar.desktop.BuildData import java.time.Instant -import java.time.temporal.ChronoUnit +import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.hours +import kotlin.time.Duration.Companion.milliseconds object ExpirationUtils { - fun getDaysLeft() = 90 - ChronoUnit.DAYS.between(Instant.ofEpochMilli(BuildData.GIT_TIME), Instant.now()).toInt() + private val EXPIRE_AFTER = BuildData.GIT_TIME + 91.days.inWholeMilliseconds + private val CHECK_INTERVAL = 1.hours.inWholeMilliseconds + + // for testing uncomment the following instead + // private val EXPIRE_AFTER = Instant.now().toEpochMilli() + 10.seconds.inWholeMilliseconds + // private val CHECK_INTERVAL = 1.seconds.inWholeMilliseconds + + private fun getMillisLeft() = (EXPIRE_AFTER - Instant.now().toEpochMilli()).milliseconds + + private fun getDaysLeft() = getMillisLeft().inWholeDays.toInt() + + private fun isExpired() = getMillisLeft() <= 0.milliseconds - fun isExpired() = getDaysLeft() <= 0 + suspend fun periodicallyCheckIfExpired( + reportDaysLeft: (Int) -> Unit, + onExpired: () -> Unit, + ) { + while (true) { + if (isExpired()) { + onExpired() + break + } else reportDaysLeft(getDaysLeft()) + delay(CHECK_INTERVAL) + } + } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt index 871f581bf6..bad371c4c8 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt @@ -56,12 +56,9 @@ import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.PreviewUtils.preview fun main() = preview { - var error: ErrorSubViewModel.Error by remember { mutableStateOf(ErrorSubViewModel.ExpirationError) } + var error: ErrorSubViewModel.Error by remember { mutableStateOf(RegistrationSubViewModel.RegistrationError) } Row(horizontalArrangement = spacedBy(8.dp)) { - Button(onClick = { error = ErrorSubViewModel.ExpirationError }) { - Text("Expiration") - } Button(onClick = { error = RegistrationSubViewModel.RegistrationError }) { Text("Registration") } @@ -82,10 +79,34 @@ fun ErrorScreen(viewHolder: ErrorSubViewModel) = @Composable fun ErrorScreen( error: ErrorSubViewModel.Error, - onBackButton: () -> Unit, + onBackButton: (() -> Unit)?, +) { + val text = when (error) { + is RegistrationSubViewModel.RegistrationError -> i18n("startup.failed.registration") + is StartupViewModel.StartingError -> { + when (error.error) { + CLOCK_ERROR -> i18n("startup.failed.clock_error") + DB_ERROR -> i18n("startup.failed.db_error") + DATA_TOO_OLD_ERROR -> i18n("startup.failed.data_too_old_error") + DATA_TOO_NEW_ERROR -> i18n("startup.failed.data_too_new_error") + SERVICE_ERROR -> i18n("startup.failed.service_error") + else -> "" + } + } + } + + ErrorScreen(text, onBackButton) +} + +@Composable +fun ErrorScreen( + text: String, + onBackButton: (() -> Unit)? = null, ) = Surface { - IconButton(onClick = onBackButton) { - Icon(Icons.Filled.ArrowBack, i18n("back")) + if (onBackButton != null) { + IconButton(onClick = onBackButton) { + Icon(Icons.Filled.ArrowBack, i18n("back")) + } } Column( @@ -101,21 +122,6 @@ fun ErrorScreen( ) Text(i18n("sorry"), style = MaterialTheme.typography.h5) - - val text = when (error) { - is ErrorSubViewModel.ExpirationError -> i18n("startup.failed.expired") - is RegistrationSubViewModel.RegistrationError -> i18n("startup.failed.registration") - is StartupViewModel.StartingError -> { - when (error.error) { - CLOCK_ERROR -> i18n("startup.failed.clock_error") - DB_ERROR -> i18n("startup.failed.db_error") - DATA_TOO_OLD_ERROR -> i18n("startup.failed.data_too_old_error") - DATA_TOO_NEW_ERROR -> i18n("startup.failed.data_too_new_error") - SERVICE_ERROR -> i18n("startup.failed.service_error") - else -> "" - } - } - } Text( text = text, style = MaterialTheme.typography.body1, diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt index e4129ebdea..07a2acc9d3 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt @@ -21,9 +21,7 @@ package org.briarproject.briar.desktop.login class ErrorSubViewModel( private val viewModel: StartupViewModel, val error: Error, - val onBackButton: () -> Unit, + val onBackButton: (() -> Unit)?, ) : StartupViewModel.SubViewModel { sealed interface Error - - object ExpirationError : Error } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt index 8cd391466f..247d7451da 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt @@ -30,7 +30,6 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent -import org.briarproject.briar.desktop.expiration.ExpirationUtils.isExpired import org.briarproject.briar.desktop.threading.BriarExecutors import org.briarproject.briar.desktop.viewmodel.EventListenerDbViewModel import org.briarproject.briar.desktop.viewmodel.asState @@ -62,8 +61,7 @@ constructor( val currentSubViewModel = _currentSubViewModel.asState() private fun decideSubViewModel(): SubViewModel = - if (isExpired()) makeError(ErrorSubViewModel.ExpirationError) - else if (accountManager.accountExists()) makeLogin() + if (accountManager.accountExists()) makeLogin() else makeRegistration() private fun makeLogin() = LoginSubViewModel( diff --git a/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt b/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt index 1cc47ade5a..1f2f74cfef 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt @@ -48,11 +48,12 @@ val DarkColors = darkColors( secondary = Lime500, background = materialDarkBg, surface = materialDarkBg, + error = briarError, onPrimary = Color.White, onSecondary = Color.White, onBackground = Color.White, onSurface = Color.White, - error = briarError + onError = Color.White, ) val LightColors = lightColors( primary = Blue500, @@ -60,11 +61,12 @@ val LightColors = lightColors( secondary = Lime300, background = Color.White, surface = Color.White, + error = briarError, onPrimary = Color.White, onSecondary = Color.Black, onBackground = Color.Black, onSurface = Color.Black, - error = briarError + onError = Color.White, ) @Composable diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt index ffafaaf8c2..cbd5c1f1af 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt @@ -39,9 +39,11 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RU import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent import org.briarproject.briar.desktop.DesktopFeatureFlags import org.briarproject.briar.desktop.expiration.ExpirationBanner +import org.briarproject.briar.desktop.login.ErrorScreen import org.briarproject.briar.desktop.login.StartupScreen import org.briarproject.briar.desktop.settings.SettingsViewModel import org.briarproject.briar.desktop.theme.BriarTheme +import org.briarproject.briar.desktop.ui.Screen.EXPIRED import org.briarproject.briar.desktop.ui.Screen.MAIN import org.briarproject.briar.desktop.ui.Screen.STARTUP import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @@ -54,7 +56,8 @@ import javax.inject.Singleton enum class Screen { STARTUP, - MAIN + MAIN, + EXPIRED, } interface BriarUi { @@ -119,10 +122,11 @@ constructor( val settingsViewModel: SettingsViewModel = viewModel() BriarTheme(isDarkTheme = settingsViewModel.isDarkMode.value) { Column(Modifier.fillMaxSize()) { - ExpirationBanner(onExpired = { screenState = STARTUP }) + ExpirationBanner { screenState = EXPIRED; stop() } when (screenState) { STARTUP -> StartupScreen() MAIN -> MainScreen(settingsViewModel) + EXPIRED -> ErrorScreen(i18n("startup.failed.expired")) } } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt index 67c1b749c3..d860f80b8f 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt @@ -21,7 +21,6 @@ package org.briarproject.briar.desktop.ui import androidx.compose.ui.unit.dp object Constants { - val BANNER_HEIGHT = 24.dp val HEADER_SIZE = 56.dp val COLUMN_WIDTH = 275.dp val STARTUP_FIELDS_WIDTH = 400.dp diff --git a/src/main/resources/strings/BriarDesktop.properties b/src/main/resources/strings/BriarDesktop.properties index d5ae8d74ef..5c4135d127 100644 --- a/src/main/resources/strings/BriarDesktop.properties +++ b/src/main/resources/strings/BriarDesktop.properties @@ -154,7 +154,8 @@ startup.database.creating=Creating Account... startup.database.opening=Decrypting Database... startup.database.migrating=Upgrading Database... startup.database.compacting=Compacting Database... -expiration.banner={0, plural, one {This is a test version of Briar that will expire in {0} day. Please update to a newer version in time.} other {This is a test version of Briar that will expire in {0} days. Please update to a newer version in time.}} +expiration.banner.part1={0, plural, =0 {This is a test version of Briar that will expire today.} one {This is a test version of Briar that will expire tomorrow.} other {This is a test version of Briar that will expire in {0} days.}} +expiration.banner.part2=Please update to a newer version in time. # Settings settings.title=Settings -- GitLab