Skip to content

Commit

Permalink
feat: add counts to summary cards
Browse files Browse the repository at this point in the history
  • Loading branch information
aanorbel committed Dec 12, 2024
1 parent 12d82a0 commit e66983c
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@
<string name="TestResults_NotAvailable">N/A</string>
<string name="TestResults_Summary_Performance_Hero_Upload">Upload</string>
<string name="TestResults_Summary_Performance_Hero_Download">Download</string>


<string name="TestResults_Summary_Websites_Hero_Tested_Singular">Tested</string>
<string name="TestResults_Summary_Websites_Hero_Blocked_Singular">Blocked</string>
<string name="TestResults_Summary_Websites_Hero_Reachable_Singular">Accessible</string>

<string name="Modal_ReRun_Title">Re-run test</string>
<string name="Modal_ReRun_Websites_Title">You are about to re-test %1$s websites.</string>
<string name="Modal_ReRun_Websites_Run">Run</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package org.ooni.probe.data.models

import kotlin.time.Duration.Companion.seconds

data class ResultCount(val total: Long, val failed: Long?, val succeeded: Long?)

data class ResultItem(
val result: ResultModel,
val descriptor: Descriptor,
val network: NetworkModel?,
val measurements: List<MeasurementWithUrl>,
val measurementCounts: ResultCount,
) {
val anyMeasurementMissingUpload =
result.isDone && measurements.any { it.measurement.isDoneAndMissingUpload }
Expand Down
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.mapToOneNotNull
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
Expand All @@ -13,6 +14,7 @@ import org.ooni.probe.data.Url
import org.ooni.probe.data.models.InstalledTestDescriptorModel
import org.ooni.probe.data.models.MeasurementModel
import org.ooni.probe.data.models.MeasurementWithUrl
import org.ooni.probe.data.models.ResultCount
import org.ooni.probe.data.models.ResultModel
import org.ooni.probe.data.models.UrlModel
import org.ooni.probe.shared.toEpoch
Expand Down Expand Up @@ -54,6 +56,12 @@ class MeasurementRepository(
.mapToList(backgroundContext)
.map { list -> list.mapNotNull { it.toModel() } }

fun countByResultId(resultId: ResultModel.Id): Flow<ResultCount> {
return database.measurementQueries.countByResultId(resultId.value).asFlow()
.mapToOneNotNull(backgroundContext)
.map { ResultCount(it.total_measurements, it.failed_measurements, it.ok_measurements) }
}

suspend fun createOrUpdate(model: MeasurementModel): MeasurementModel.Id =
withContext(backgroundContext) {
database.transactionWithResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ class Dependencies(
getResultById = resultRepository::getById,
getTestDescriptors = getTestDescriptors.invoke(),
getMeasurementsByResultId = measurementRepository::listByResultId,
countByResultId = measurementRepository::countByResultId,
)
}
private val clearStorage by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,30 @@ import kotlinx.coroutines.flow.combine
import org.ooni.probe.data.models.Descriptor
import org.ooni.probe.data.models.MeasurementWithUrl
import org.ooni.probe.data.models.NetworkModel
import org.ooni.probe.data.models.ResultCount
import org.ooni.probe.data.models.ResultItem
import org.ooni.probe.data.models.ResultModel

class GetResult(
private val getResultById: (ResultModel.Id) -> Flow<Pair<ResultModel, NetworkModel?>?>,
private val getTestDescriptors: Flow<List<Descriptor>>,
private val getMeasurementsByResultId: (ResultModel.Id) -> Flow<List<MeasurementWithUrl>>,
private val countByResultId: (ResultModel.Id) -> Flow<ResultCount>,
) {
operator fun invoke(resultId: ResultModel.Id): Flow<ResultItem?> =
combine(
getResultById(resultId),
getTestDescriptors,
getMeasurementsByResultId(resultId),
) { resultWithNetwork, descriptors, measurements ->
countByResultId(resultId),
) { resultWithNetwork, descriptors, measurements, measurementCounts ->
val result = resultWithNetwork?.first ?: return@combine null
ResultItem(
result = result,
descriptor = descriptors.forResult(result) ?: return@combine null,
network = resultWithNetwork.second,
measurements = measurements,
measurementCounts = measurementCounts,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
Expand All @@ -30,6 +32,7 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -50,7 +53,6 @@ import ooniprobe.composeapp.generated.resources.NetworkType_Vpn
import ooniprobe.composeapp.generated.resources.Res
import ooniprobe.composeapp.generated.resources.TestResults_NotAvailable
import ooniprobe.composeapp.generated.resources.TestResults_Overview_Hero_DataUsage
import ooniprobe.composeapp.generated.resources.TestResults_Overview_Hero_Tests
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Hero_Country
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Hero_DateAndTime
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Hero_Mobile
Expand All @@ -60,6 +62,9 @@ import ooniprobe.composeapp.generated.resources.TestResults_Summary_Hero_Runtime
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Hero_WiFi
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Performance_Hero_Download
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Performance_Hero_Upload
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Websites_Hero_Blocked_Singular
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Websites_Hero_Reachable_Singular
import ooniprobe.composeapp.generated.resources.TestResults_Summary_Websites_Hero_Tested_Singular
import ooniprobe.composeapp.generated.resources.ic_download
import ooniprobe.composeapp.generated.resources.ic_replay
import ooniprobe.composeapp.generated.resources.ic_upload
Expand Down Expand Up @@ -166,7 +171,7 @@ fun ResultScreen(

@Composable
private fun Summary(item: ResultItem) {
val pagerState = rememberPagerState(pageCount = { 2 })
val pagerState = rememberPagerState(pageCount = { 3 })
Box {
HorizontalPager(
state = pagerState,
Expand All @@ -176,8 +181,9 @@ private fun Summary(item: ResultItem) {
.defaultMinSize(minHeight = 128.dp),
) { page ->
when (page) {
0 -> SummaryDetails(item)
1 -> SummaryNetwork(item)
0 -> SummaryStats(item)
1 -> SummaryDetails(item)
2 -> SummaryNetwork(item)
}
}
Row(
Expand Down Expand Up @@ -210,21 +216,72 @@ private fun Summary(item: ResultItem) {
}

@Composable
private fun SummaryDetails(item: ResultItem) {
Column(Modifier.padding(horizontal = 16.dp)) {
val labelModifier = Modifier.weight(4f)
val valueModifier = Modifier.weight(6f)
Row {
private fun SummaryStats(item: ResultItem) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min) // So VerticalDividers don't expand to the whole screen
.padding(16.dp),
) {
Column(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
stringResource(Res.string.TestResults_Overview_Hero_Tests),
fontWeight = FontWeight.Bold,
modifier = labelModifier,
item.measurementCounts.total.toString(),
style = MaterialTheme.typography.headlineMedium,
)

Text(
stringResource(Res.string.TestResults_Summary_Websites_Hero_Tested_Singular),
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(bottom = 8.dp),
)
}

VerticalDivider(Modifier.padding(4.dp), color = LocalContentColor.current)

Column(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
item.measurements.size.toString(),
modifier = valueModifier,
item.measurementCounts.failed?.toString() ?: "0",
style = MaterialTheme.typography.headlineMedium,
)

Text(
stringResource(Res.string.TestResults_Summary_Websites_Hero_Blocked_Singular),
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(bottom = 8.dp),
)
}

VerticalDivider(Modifier.padding(4.dp), color = LocalContentColor.current)

Column(
modifier = Modifier.weight(1f),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
item.measurementCounts.succeeded?.toString() ?: "0",
style = MaterialTheme.typography.headlineMedium,
)

Text(
stringResource(Res.string.TestResults_Summary_Websites_Hero_Reachable_Singular),
style = MaterialTheme.typography.labelLarge,
modifier = Modifier.padding(bottom = 8.dp),
)
}
}
}

@Composable
private fun SummaryDetails(item: ResultItem) {
Column(Modifier.padding(horizontal = 16.dp)) {
val labelModifier = Modifier.weight(4f)
val valueModifier = Modifier.weight(6f)
Row {
Text(
stringResource(Res.string.TestResults_Summary_Hero_DateAndTime),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ SELECT * FROM Measurement
LEFT JOIN Url ON Measurement.url_id = Url.id
WHERE Measurement.result_id = ?;

countByResultId:
SELECT
COUNT(*) AS total_measurements,
SUM(CASE WHEN is_rerun = 0 AND is_done = 1 AND is_failed = 0 AND is_anomaly = 0 THEN 1 ELSE 0 END) AS ok_measurements,
SUM(CASE WHEN is_rerun = 0 AND is_done = 1 AND is_failed = 1 THEN 1 ELSE 0 END) AS failed_measurements
FROM Measurement
WHERE result_id = ?;

selectAllNotUploaded:
SELECT * FROM Measurement
WHERE Measurement.is_done = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class SetupDependencies(
}
}

private fun presentViewController(uiViewController: UIViewController): Boolean {
private fun presentViewController(uiViewController: UIViewController): Boolean {
return findCurrentViewController()?.let { viewController ->

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Expand Down

0 comments on commit e66983c

Please sign in to comment.