diff --git a/composeApp/src/commonMain/composeResources/values/strings-common.xml b/composeApp/src/commonMain/composeResources/values/strings-common.xml index 13b6f99d7..26ecd5749 100644 --- a/composeApp/src/commonMain/composeResources/values/strings-common.xml +++ b/composeApp/src/commonMain/composeResources/values/strings-common.xml @@ -9,6 +9,7 @@ Estimated time left: Stopping test… Finishing the currently pending tests, please wait… + Proxy in use OONI Tests OONI Run Links Run finished. Tap to view results. @@ -231,7 +232,7 @@ OONI Probe cannot run automatically without battery optimization. Do you want to try again? - Last updated %1$s + Last updated %1$s Back refresh Measurement diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt index a7fb12a22..41680a8cf 100644 --- a/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt +++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt @@ -57,6 +57,7 @@ import org.ooni.probe.domain.GetBootstrapTestDescriptors import org.ooni.probe.domain.GetDefaultTestDescriptors import org.ooni.probe.domain.GetEnginePreferences import org.ooni.probe.domain.GetFirstRun +import org.ooni.probe.domain.GetProxySettings import org.ooni.probe.domain.GetResult import org.ooni.probe.domain.GetResults import org.ooni.probe.domain.GetSettings @@ -238,7 +239,10 @@ class Dependencies( } val getCurrentTestState get() = testStateManager::observeState private val getDefaultTestDescriptors by lazy { GetDefaultTestDescriptors() } - private val getEnginePreferences by lazy { GetEnginePreferences(preferenceRepository) } + private val getProxySettings by lazy { GetProxySettings(preferenceRepository) } + private val getEnginePreferences by lazy { + GetEnginePreferences(preferencesRepository = preferenceRepository, getProxySettings = getProxySettings::invoke) + } private val getFirstRun by lazy { GetFirstRun(preferenceRepository) } private val getResults by lazy { GetResults( @@ -453,6 +457,7 @@ class Dependencies( observeTestRunState = testStateManager.observeState(), observeTestRunErrors = testStateManager.observeErrors(), cancelTestRun = testStateManager::cancelTestRun, + getProxySettings = getProxySettings::invoke, ) fun runViewModel(onBack: () -> Unit) = diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetEnginePreferences.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetEnginePreferences.kt index 10382902c..4781305f6 100644 --- a/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetEnginePreferences.kt +++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetEnginePreferences.kt @@ -11,6 +11,7 @@ import kotlin.time.Duration.Companion.seconds class GetEnginePreferences( private val preferencesRepository: PreferenceRepository, + private val getProxySettings: suspend () -> ProxySettings, ) { suspend operator fun invoke() = EnginePreferences( @@ -26,11 +27,7 @@ class GetEnginePreferences( } else { null }, - proxy = ProxySettings.newProxySettings( - protocol = getValueForKey(SettingsKey.PROXY_PROTOCOL) as? String, - hostname = getValueForKey(SettingsKey.PROXY_HOSTNAME) as? String, - port = getValueForKey(SettingsKey.PROXY_PORT) as? String, - ).getProxyString(), + proxy = getProxySettings().getProxyString(), ) private suspend fun getEnabledCategories(): List { diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetProxySettings.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetProxySettings.kt new file mode 100644 index 000000000..b5fb6fb05 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/domain/GetProxySettings.kt @@ -0,0 +1,19 @@ +package org.ooni.probe.domain + +import kotlinx.coroutines.flow.first +import org.ooni.probe.data.models.ProxySettings +import org.ooni.probe.data.models.SettingsKey +import org.ooni.probe.data.repositories.PreferenceRepository + +class GetProxySettings( + private val preferencesRepository: PreferenceRepository, +) { + suspend operator fun invoke() = + ProxySettings.newProxySettings( + protocol = getValueForKey(SettingsKey.PROXY_PROTOCOL) as? String, + hostname = getValueForKey(SettingsKey.PROXY_HOSTNAME) as? String, + port = getValueForKey(SettingsKey.PROXY_PORT) as? String, + ) + + private suspend fun getValueForKey(settingsKey: SettingsKey) = preferencesRepository.getValueByKey(settingsKey).first() +} diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningScreen.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningScreen.kt index f9f829943..d2d2bdff4 100644 --- a/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningScreen.kt @@ -13,6 +13,8 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.AssistChip +import androidx.compose.material3.AssistChipDefaults import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -33,6 +35,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import ooniprobe.composeapp.generated.resources.Dashboard_Running_EstimatedTimeLeft +import ooniprobe.composeapp.generated.resources.Dashboard_Running_ProxyInUse import ooniprobe.composeapp.generated.resources.Dashboard_Running_Running import ooniprobe.composeapp.generated.resources.Dashboard_Running_Stopping_Notice import ooniprobe.composeapp.generated.resources.Dashboard_Running_Stopping_Title @@ -40,6 +43,7 @@ import ooniprobe.composeapp.generated.resources.Notification_StopTest import ooniprobe.composeapp.generated.resources.Res import ooniprobe.composeapp.generated.resources.back import ooniprobe.composeapp.generated.resources.ooni_empty_state +import ooniprobe.composeapp.generated.resources.test_circumvention import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource import org.ooni.probe.data.models.TestRunState @@ -80,7 +84,7 @@ fun RunningScreen( ) when (state.testRunState) { - is TestRunState.Running -> TestRunning(state.testRunState, onEvent) + is TestRunState.Running -> TestRunning(state.hasProxy, state.testRunState, onEvent) TestRunState.Stopping -> TestStopping() else -> Unit } @@ -95,6 +99,7 @@ fun RunningScreen( @Composable private fun TestRunning( + hasProxy: Boolean, state: TestRunState.Running, onEvent: (RunningViewModel.Event) -> Unit, ) { @@ -120,6 +125,32 @@ private fun TestRunning( style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, ) + if (hasProxy) { + AssistChip( + onClick = { }, + label = { + Text( + text = stringResource(Res.string.Dashboard_Running_ProxyInUse), + style = MaterialTheme.typography.bodyLarge, + ) + }, + leadingIcon = { + Icon( + painter = painterResource(Res.drawable.test_circumvention), + contentDescription = null, + modifier = Modifier.size(AssistChipDefaults.IconSize), + tint = MaterialTheme.customColors.onDescriptor, + ) + }, + colors = AssistChipDefaults.assistChipColors( + labelColor = MaterialTheme.customColors.onDescriptor, + ), + border = AssistChipDefaults.assistChipBorder( + enabled = true, + borderColor = MaterialTheme.customColors.onDescriptor, + ), + ) + } } } diff --git a/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningViewModel.kt b/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningViewModel.kt index fdbd44a57..85e4441ff 100644 --- a/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningViewModel.kt +++ b/composeApp/src/commonMain/kotlin/org/ooni/probe/ui/running/RunningViewModel.kt @@ -10,9 +10,10 @@ import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.ooni.probe.data.models.ProxySettings import org.ooni.probe.data.models.TestRunError import org.ooni.probe.data.models.TestRunState -import org.ooni.probe.ui.dashboard.DashboardViewModel.Event class RunningViewModel( onBack: () -> Unit, @@ -20,6 +21,7 @@ class RunningViewModel( observeTestRunState: Flow, observeTestRunErrors: Flow, cancelTestRun: () -> Unit, + getProxySettings: suspend () -> ProxySettings, ) : ViewModel() { private val events = MutableSharedFlow(extraBufferCapacity = 1) @@ -27,6 +29,10 @@ class RunningViewModel( val state = _state.asStateFlow() init { + viewModelScope.launch { + val proxy = getProxySettings().getProxyString() + _state.update { it.copy(hasProxy = proxy.isNotEmpty()) } + } observeTestRunState .onEach { testRunState -> if (testRunState is TestRunState.Idle) { @@ -72,6 +78,7 @@ class RunningViewModel( data class State( val testRunState: TestRunState? = null, val testRunErrors: List = emptyList(), + val hasProxy: Boolean = false, ) sealed interface Event {