Skip to content

Commit

Permalink
Merge pull request #69 from ooni/show-result
Browse files Browse the repository at this point in the history
Show result
  • Loading branch information
sdsantos authored Aug 20, 2024
2 parents fafe90f + a05a9b6 commit ada591a
Show file tree
Hide file tree
Showing 35 changed files with 575 additions and 200 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">

<path
android:fillColor="#FF000000"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z" />

</vector>
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
<resources>
<string name="run_tests">Run Test</string>
<string name="back">Back</string>
<string name="dashboard">Dashboard</string>
<string name="settings">Settings</string>

<string name="Dashboard_Tab_Label">Dashboard</string>
<string name="Dashboard_RunV2_Ooni_Title">OONI Tests</string>
<string name="Dashboard_RunV2_Title">OONI Run Links</string>

<string name="Dashboard_Running_Stopping_Title">Stopping test…</string>
<string name="Dashboard_Running_Stopping_Notice">Finishing the currently pending tests, please wait…</string>

<string name="OONIRun_Run">Run</string>
<string name="Notification_StopTest">Stop test</string>

<string name="Test_Websites_Fullname">Websites</string>
Expand All @@ -35,6 +32,7 @@
<string name="TestResults_UnknownASN">Unknown</string>
<string name="TestResults_NotAvailable">N/A</string>

<string name="Settings_Title">Settings</string>
<string name="Settings_Notifications_Label">Notifications</string>
<string name="Settings_Notifications_Enabled">Enabled</string>
<string name="Modal_EnableNotifications_Paragraph">Interested in running OONI Probe tests during emergent censorship events? Enable notifications to receive a message when we hear of internet censorship near you.</string>
Expand Down Expand Up @@ -131,5 +129,14 @@
<string name="CategoryCode_IGO_Description">Intergovernmental organizations including The United Nations</string>
<string name="CategoryCode_MISC_Description">Sites that haven\'t been categorized yet</string>

<string name="Snackbar_ResultsNotUploaded_Text">Not uploaded</string>

<string name="Modal_Error_CantDownloadURLs">Unable to download URL list. Please try again.</string>

<!-- New Strings -->
<string name="back">Back</string>
<plurals name="measurements_count">
<item quantity="one">%1$d measurement</item>
<item quantity="other">%1$d measurements</item>
</plurals>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,10 @@ class TaskEventMapper(
TaskEvent.MeasurementDone(index = value?.idx ?: 0)

"status.measurement_start" ->
value?.input?.ifEmpty { null }?.let { url ->
TaskEvent.MeasurementStart(
index = value.idx,
url = url,
)
} ?: run {
Logger.d("Task Event $key missing 'input'")
null
}
TaskEvent.MeasurementStart(
index = value?.idx ?: 0,
url = value?.input,
)

"status.measurement_submission" ->
TaskEvent.MeasurementSubmissionSuccessful(index = value?.idx ?: 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ sealed interface TaskEvent {

data class MeasurementStart(
val index: Int,
val url: String,
val url: String?,
) : TaskEvent

data class MeasurementSubmissionSuccessful(
Expand Down
29 changes: 16 additions & 13 deletions composeApp/src/commonMain/kotlin/org/ooni/engine/models/TestType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,22 @@ sealed class TestType {
}

companion object {
private val ALL_NAMED = listOf(
Dash,
FacebookMessenger,
HttpHeaderFieldManipulation,
HttpInvalidRequestLine,
Ndt,
Psiphon,
Signal,
Telegram,
Tor,
WebConnectivity,
Whatsapp,
)
// Lazy due to https://youtrack.jetbrains.com/issue/KT-8970/Object-is-uninitialized-null-when-accessed-from-static-context-ex.-companion-object-with-initialization-loop
private val ALL_NAMED by lazy {
listOf(
Dash,
FacebookMessenger,
HttpHeaderFieldManipulation,
HttpInvalidRequestLine,
Ndt,
Psiphon,
Signal,
Telegram,
Tor,
WebConnectivity,
Whatsapp,
)
}

fun fromName(name: String) = ALL_NAMED.firstOrNull { it.name == name } ?: Experimental(name)
}
Expand Down
16 changes: 11 additions & 5 deletions composeApp/src/commonMain/kotlin/org/ooni/probe/App.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.ooni.probe

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
Expand Down Expand Up @@ -37,11 +39,15 @@ fun App(dependencies: Dependencies) {
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) },
bottomBar = { BottomNavigationBar(navController) },
) {
Navigation(
navController = navController,
dependencies = dependencies,
)
) { paddingValues ->
Box(
modifier = Modifier.padding(bottom = paddingValues.calculateBottomPadding()),
) {
Navigation(
navController = navController,
dependencies = dependencies,
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ data class Descriptor(
}

val isExpired get() = expirationDate != null && expirationDate < LocalDateTime.now()

companion object {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ data class MeasurementModel(
val value: Long,
)

val idOrThrow get() = id ?: throw IllegalStateException("Id no available")

val logFilePath: Path
get() = logFilePath(resultId, test)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.ooni.probe.data.models

data class MeasurementWithUrl(
val measurement: MeasurementModel,
val url: UrlModel?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.ooni.probe.data.models

data class ResultItem(
val result: ResultModel,
val descriptor: Descriptor,
val network: NetworkModel?,
val measurements: List<MeasurementWithUrl>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package org.ooni.probe.data.models

data class ResultListItem(
val result: ResultModel,
val descriptor: Descriptor,
val network: NetworkModel?,
val measurementsCount: Long,
val allMeasurementsUploaded: Boolean,
) {
val idOrThrow get() = result.idOrThrow
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.ooni.probe.data.models

data class ResultWithNetworkAndAggregates(
val result: ResultModel,
val network: NetworkModel?,
val measurementsCount: Long,
val allMeasurementsUploaded: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import kotlinx.coroutines.withContext
import org.ooni.engine.models.TestType
import org.ooni.probe.Database
import org.ooni.probe.data.Measurement
import org.ooni.probe.data.SelectByResultIdWithUrl
import org.ooni.probe.data.Url
import org.ooni.probe.data.models.MeasurementModel
import org.ooni.probe.data.models.MeasurementWithUrl
import org.ooni.probe.data.models.ResultModel
import org.ooni.probe.data.models.UrlModel
import org.ooni.probe.shared.toEpoch
Expand All @@ -26,6 +29,13 @@ class MeasurementRepository(
.mapToList(backgroundDispatcher)
.map { list -> list.mapNotNull { it.toModel() } }

fun listByResultId(id: ResultModel.Id) =
database.measurementQueries
.selectByResultIdWithUrl(id.value)
.asFlow()
.mapToList(backgroundDispatcher)
.map { list -> list.mapNotNull { it.toModel() } }

suspend fun createOrUpdate(model: MeasurementModel): MeasurementModel.Id =
withContext(backgroundDispatcher) {
database.transactionWithResult {
Expand Down Expand Up @@ -76,4 +86,36 @@ class MeasurementRepository(
resultId = result_id?.let(ResultModel::Id) ?: return null,
)
}

private fun SelectByResultIdWithUrl.toModel(): MeasurementWithUrl? {
return MeasurementWithUrl(
measurement = Measurement(
id = id,
test_name = test_name,
start_time = start_time,
runtime = runtime,
is_done = is_done,
is_uploaded = is_uploaded,
is_failed = is_failed,
failure_msg = failure_msg,
is_upload_failed = is_upload_failed,
upload_failure_msg = upload_failure_msg,
is_rerun = is_rerun,
is_anomaly = is_anomaly,
report_id = report_id,
test_keys = test_keys,
rerun_network = rerun_network,
url_id = url_id,
result_id = result_id,
).toModel() ?: return null,
url = id_?.let { urlId ->
Url(
id = urlId,
url = url,
country_code = country_code,
category_code = category_code,
).toModel()
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.ooni.probe.data.repositories

import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
import app.cash.sqldelight.coroutines.mapToOneOrNull
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
Expand All @@ -10,10 +11,11 @@ import org.ooni.probe.Database
import org.ooni.probe.data.Network
import org.ooni.probe.data.Result
import org.ooni.probe.data.SelectAllWithNetwork
import org.ooni.probe.data.SelectByIdWithNetwork
import org.ooni.probe.data.models.InstalledTestDescriptorModel
import org.ooni.probe.data.models.NetworkModel
import org.ooni.probe.data.models.ResultListItem
import org.ooni.probe.data.models.ResultModel
import org.ooni.probe.data.models.ResultWithNetworkAndAggregates
import org.ooni.probe.shared.toEpoch
import org.ooni.probe.shared.toLocalDateTime

Expand All @@ -28,19 +30,19 @@ class ResultRepository(
.mapToList(backgroundDispatcher)
.map { list -> list.mapNotNull { it.toModel() } }

fun listWithNetwork(): Flow<List<ResultListItem>> =
fun listWithNetwork(): Flow<List<ResultWithNetworkAndAggregates>> =
database.resultQueries
.selectAllWithNetwork()
.asFlow()
.mapToList(backgroundDispatcher)
.map { list -> list.mapNotNull { it.toModel() } }

fun getById(resultId: ResultModel.Id): Flow<ResultModel?> =
fun getById(resultId: ResultModel.Id): Flow<Pair<ResultModel, NetworkModel?>?> =
database.resultQueries
.selectById(resultId.value)
.selectByIdWithNetwork(resultId.value)
.asFlow()
.mapToList(backgroundDispatcher)
.map { it.firstOrNull()?.toModel() }
.mapToOneOrNull(backgroundDispatcher)
.map { it?.toModel() }

suspend fun createOrUpdate(model: ResultModel): ResultModel.Id =
withContext(backgroundDispatcher) {
Expand Down Expand Up @@ -79,33 +81,59 @@ class ResultRepository(
)
}

private fun SelectAllWithNetwork.toModel(): ResultListItem? {
return ResultListItem(
result =
Result(
id = id,
test_group_name = test_group_name,
start_time = start_time,
is_viewed = is_viewed,
is_done = is_done,
data_usage_up = data_usage_up,
data_usage_down = data_usage_down,
failure_msg = failure_msg,
network_id = network_id,
descriptor_runId = descriptor_runId,
).toModel() ?: return null,
network =
id_?.let { networkId ->
Network(
id = networkId,
network_name = network_name,
ip = ip,
asn = asn,
country_code = country_code,
network_type = network_type,
).toModel()
},
private fun SelectAllWithNetwork.toModel(): ResultWithNetworkAndAggregates? {
return ResultWithNetworkAndAggregates(
result = Result(
id = id,
test_group_name = test_group_name,
start_time = start_time,
is_viewed = is_viewed,
is_done = is_done,
data_usage_up = data_usage_up,
data_usage_down = data_usage_down,
failure_msg = failure_msg,
network_id = network_id,
descriptor_runId = descriptor_runId,
).toModel() ?: return null,
network = id_?.let { networkId ->
Network(
id = networkId,
network_name = network_name,
ip = ip,
asn = asn,
country_code = country_code,
network_type = network_type,
).toModel()
},
measurementsCount = measurementsCount,
allMeasurementsUploaded = allMeasurementsUploaded,
)
}

private fun SelectByIdWithNetwork.toModel(): Pair<ResultModel, NetworkModel?>? {
return Pair(
Result(
id = id,
test_group_name = test_group_name,
start_time = start_time,
is_viewed = is_viewed,
is_done = is_done,
data_usage_up = data_usage_up,
data_usage_down = data_usage_down,
failure_msg = failure_msg,
network_id = network_id,
descriptor_runId = descriptor_runId,
).toModel() ?: return null,
id_?.let { networkId ->
Network(
id = networkId,
network_name = network_name,
ip = ip,
asn = asn,
country_code = country_code,
network_type = network_type,
).toModel()
},
)
}
}
Loading

0 comments on commit ada591a

Please sign in to comment.