Skip to content

Commit 8265228

Browse files
authored
Merge pull request #143 from ooni/dashboard-ui
Dashboard UI
2 parents c903c63 + 13bab98 commit 8265228

File tree

13 files changed

+178
-151
lines changed

13 files changed

+178
-151
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="360dp"
3+
android:height="23dp"
4+
android:viewportWidth="360"
5+
android:viewportHeight="23">
6+
<path
7+
android:pathData="M0,0H360V23C360,23 272.92,10.21 181.97,10.21C91.02,10.21 0,23 0,23V0Z"
8+
android:fillColor="#000000"
9+
android:fillType="evenOdd"/>
10+
</vector>

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/dashboard/DashboardScreen.kt

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.ooni.probe.ui.dashboard
22

33
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.background
45
import androidx.compose.foundation.clickable
56
import androidx.compose.foundation.layout.Box
67
import androidx.compose.foundation.layout.Column
@@ -18,10 +19,10 @@ import androidx.compose.foundation.lazy.items
1819
import androidx.compose.foundation.shape.RoundedCornerShape
1920
import androidx.compose.material3.Button
2021
import androidx.compose.material3.ButtonDefaults
21-
import androidx.compose.material3.ElevatedButton
2222
import androidx.compose.material3.Icon
2323
import androidx.compose.material3.LinearProgressIndicator
2424
import androidx.compose.material3.MaterialTheme
25+
import androidx.compose.material3.OutlinedButton
2526
import androidx.compose.material3.Surface
2627
import androidx.compose.material3.Text
2728
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
@@ -30,7 +31,10 @@ import androidx.compose.runtime.Composable
3031
import androidx.compose.runtime.LaunchedEffect
3132
import androidx.compose.ui.Alignment
3233
import androidx.compose.ui.Modifier
34+
import androidx.compose.ui.graphics.ColorFilter
35+
import androidx.compose.ui.graphics.SolidColor
3336
import androidx.compose.ui.input.nestedscroll.nestedScroll
37+
import androidx.compose.ui.layout.ContentScale
3438
import androidx.compose.ui.text.font.FontWeight
3539
import androidx.compose.ui.text.style.TextAlign
3640
import androidx.compose.ui.unit.dp
@@ -44,6 +48,7 @@ import ooniprobe.composeapp.generated.resources.Modal_DisableVPN_Title
4448
import ooniprobe.composeapp.generated.resources.OONIRun_Run
4549
import ooniprobe.composeapp.generated.resources.Res
4650
import ooniprobe.composeapp.generated.resources.app_name
51+
import ooniprobe.composeapp.generated.resources.dashboard_arc
4752
import ooniprobe.composeapp.generated.resources.ic_timer
4853
import ooniprobe.composeapp.generated.resources.ic_warning
4954
import ooniprobe.composeapp.generated.resources.logo_probe
@@ -74,6 +79,24 @@ fun DashboardScreen(
7479
pullToRefreshState.endRefresh()
7580
}
7681
Box(Modifier.nestedScroll(pullToRefreshState.nestedScrollConnection)) {
82+
// Colorful top background
83+
Column {
84+
Box(
85+
Modifier
86+
.fillMaxWidth()
87+
.background(MaterialTheme.colorScheme.primary)
88+
.height(144.dp)
89+
.padding(WindowInsets.statusBars.asPaddingValues()),
90+
)
91+
Image(
92+
painterResource(Res.drawable.dashboard_arc),
93+
contentDescription = null,
94+
contentScale = ContentScale.FillWidth,
95+
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary),
96+
modifier = Modifier.fillMaxWidth(),
97+
)
98+
}
99+
77100
Column(
78101
horizontalAlignment = Alignment.CenterHorizontally,
79102
modifier = Modifier
@@ -83,8 +106,10 @@ fun DashboardScreen(
83106
Image(
84107
painterResource(Res.drawable.logo_probe),
85108
contentDescription = stringResource(Res.string.app_name),
86-
modifier = Modifier.padding(36.dp)
87-
.padding(WindowInsets.statusBars.asPaddingValues()),
109+
modifier = Modifier
110+
.padding(vertical = 20.dp)
111+
.padding(WindowInsets.statusBars.asPaddingValues())
112+
.height(72.dp),
88113
)
89114

90115
TestRunStateSection(state.testRunState, onEvent)
@@ -115,6 +140,7 @@ fun DashboardScreen(
115140
}
116141
}
117142
}
143+
118144
if (state.isRefreshing) {
119145
UpdateProgressStatus(
120146
modifier = Modifier.align(Alignment.BottomCenter),
@@ -147,9 +173,16 @@ private fun TestRunStateSection(
147173
) {
148174
when (state) {
149175
is TestRunState.Idle -> {
150-
ElevatedButton(
176+
OutlinedButton(
151177
onClick = { onEvent(DashboardViewModel.Event.RunTestsClick) },
152-
colors = ButtonDefaults.buttonColors(),
178+
colors = ButtonDefaults.outlinedButtonColors(
179+
contentColor = MaterialTheme.colorScheme.primary,
180+
containerColor = MaterialTheme.colorScheme.onPrimary,
181+
),
182+
border = ButtonDefaults.outlinedButtonBorder.copy(
183+
brush = SolidColor(MaterialTheme.colorScheme.primary),
184+
),
185+
elevation = ButtonDefaults.elevatedButtonElevation(defaultElevation = 4.dp),
153186
) {
154187
Text(
155188
stringResource(Res.string.OONIRun_Run),
@@ -185,8 +218,10 @@ private fun TestRunStateSection(
185218
is TestRunState.Running -> {
186219
Column(
187220
horizontalAlignment = Alignment.CenterHorizontally,
188-
modifier = Modifier.clickable { onEvent(DashboardViewModel.Event.RunningTestClick) }
189-
.padding(horizontal = 16.dp, vertical = 8.dp),
221+
modifier = Modifier
222+
.clickable { onEvent(DashboardViewModel.Event.RunningTestClick) }
223+
.padding(horizontal = 16.dp)
224+
.padding(top = 32.dp, bottom = 8.dp),
190225
) {
191226
state.testType?.let { testType ->
192227
Row {
@@ -245,7 +280,9 @@ private fun TestRunStateSection(
245280
TestRunState.Stopping -> {
246281
Column(
247282
horizontalAlignment = Alignment.CenterHorizontally,
248-
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
283+
modifier = Modifier
284+
.padding(horizontal = 16.dp)
285+
.padding(top = 32.dp, bottom = 8.dp),
249286
) {
250287
Text(
251288
text = stringResource(Res.string.Dashboard_Running_Stopping_Title),
Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package org.ooni.probe.ui.dashboard
22

3+
import androidx.compose.foundation.border
34
import androidx.compose.foundation.clickable
45
import androidx.compose.foundation.layout.Column
56
import androidx.compose.foundation.layout.Row
67
import androidx.compose.foundation.layout.fillMaxWidth
78
import androidx.compose.foundation.layout.padding
8-
import androidx.compose.material3.Card
9+
import androidx.compose.material3.CardDefaults
910
import androidx.compose.material3.Icon
11+
import androidx.compose.material3.MaterialTheme
1012
import androidx.compose.material3.Text
1113
import androidx.compose.runtime.Composable
1214
import androidx.compose.ui.Alignment
1315
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.draw.clip
1417
import androidx.compose.ui.unit.dp
1518
import ooniprobe.composeapp.generated.resources.Res
1619
import ooniprobe.composeapp.generated.resources.ic_chevron_right
@@ -24,37 +27,38 @@ fun TestDescriptorItem(
2427
onClick: () -> Unit,
2528
updateDescriptor: () -> Unit = {},
2629
) {
27-
Card(
28-
Modifier
30+
Row(
31+
verticalAlignment = Alignment.CenterVertically,
32+
modifier = Modifier
33+
.fillMaxWidth()
2934
.padding(horizontal = 16.dp, vertical = 4.dp)
30-
.clickable { onClick() },
35+
.clip(CardDefaults.shape)
36+
.clickable { onClick() }
37+
.border(
38+
width = 1.dp,
39+
color = MaterialTheme.colorScheme.surfaceVariant,
40+
shape = CardDefaults.shape,
41+
)
42+
.padding(vertical = 8.dp, horizontal = 12.dp),
3143
) {
32-
Row(
33-
verticalAlignment = Alignment.CenterVertically,
34-
modifier =
35-
Modifier
36-
.fillMaxWidth()
37-
.padding(8.dp),
44+
Column(
45+
modifier = Modifier.weight(1f),
3846
) {
39-
Column(
40-
modifier = Modifier.weight(1f),
41-
) {
42-
TestDescriptorLabel(descriptor)
47+
TestDescriptorLabel(descriptor)
4348

44-
descriptor.shortDescription()?.let { shortDescription ->
45-
Text(
46-
shortDescription,
47-
modifier = Modifier.padding(top = 4.dp),
48-
)
49-
}
50-
}
51-
if (descriptor.updatable) {
52-
UpdatesChip(onClick = updateDescriptor)
49+
descriptor.shortDescription()?.let { shortDescription ->
50+
Text(
51+
shortDescription,
52+
modifier = Modifier.padding(top = 4.dp),
53+
)
5354
}
54-
Icon(
55-
painter = painterResource(Res.drawable.ic_chevron_right),
56-
contentDescription = null,
57-
)
5855
}
56+
if (descriptor.updatable) {
57+
UpdatesChip(onClick = updateDescriptor)
58+
}
59+
Icon(
60+
painter = painterResource(Res.drawable.ic_chevron_right),
61+
contentDescription = null,
62+
)
5963
}
6064
}

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/dashboard/TestDescriptorLabel.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ fun TestDescriptorLabel(descriptor: Descriptor) {
3333
Text(
3434
descriptor.title(),
3535
style = MaterialTheme.typography.titleMedium,
36-
color = descriptor.color ?: Color.Unspecified,
3736
)
3837
}
3938
}

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/navigation/BottomNavigationBar.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package org.ooni.probe.ui.navigation
22

33
import androidx.compose.material3.Icon
4+
import androidx.compose.material3.MaterialTheme
45
import androidx.compose.material3.NavigationBar
56
import androidx.compose.material3.NavigationBarItem
7+
import androidx.compose.material3.NavigationBarItemDefaults
68
import androidx.compose.material3.Text
79
import androidx.compose.runtime.Composable
810
import androidx.compose.runtime.getValue
@@ -37,6 +39,10 @@ fun BottomNavigationBar(navController: NavController) {
3739
label = { Text(stringResource(screen.titleRes)) },
3840
selected = currentRoute == screen.route,
3941
onClick = { navController.navigateToMainScreen(screen) },
42+
colors = NavigationBarItemDefaults.colors(
43+
indicatorColor = MaterialTheme.colorScheme.primaryContainer,
44+
selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer,
45+
),
4046
)
4147
}
4248
}

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/run/RunScreen.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ fun RunScreen(
175175
enabled = selectedTestsCount > 0,
176176
modifier = Modifier
177177
.align(Alignment.BottomCenter)
178-
.padding(bottom = 16.dp),
178+
.padding(bottom = 16.dp)
179+
.padding(WindowInsets.navigationBars.asPaddingValues()),
179180
) {
180181
Text(
181182
text = pluralStringResource(

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/settings/SettingsScreen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package org.ooni.probe.ui.settings
22

3-
import androidx.compose.foundation.Image
43
import androidx.compose.foundation.clickable
54
import androidx.compose.foundation.layout.Column
65
import androidx.compose.foundation.layout.size
6+
import androidx.compose.material3.Icon
77
import androidx.compose.material3.ListItem
88
import androidx.compose.material3.Text
99
import androidx.compose.material3.TopAppBar
@@ -54,7 +54,7 @@ private fun SettingsItemView(
5454
ListItem(
5555
leadingContent = {
5656
icon?.let {
57-
Image(
57+
Icon(
5858
modifier = Modifier.size(24.dp),
5959
painter = painterResource(it),
6060
contentDescription = stringResource(title),

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/shared/UpdateProgressStatus.kt

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.ooni.probe.ui.shared
22

3-
import androidx.compose.foundation.background
43
import androidx.compose.foundation.layout.Arrangement
54
import androidx.compose.foundation.layout.Row
65
import androidx.compose.foundation.layout.fillMaxWidth
@@ -12,12 +11,12 @@ import androidx.compose.material3.CircularProgressIndicator
1211
import androidx.compose.material3.Icon
1312
import androidx.compose.material3.IconButton
1413
import androidx.compose.material3.MaterialTheme
14+
import androidx.compose.material3.Surface
1515
import androidx.compose.material3.Text
1616
import androidx.compose.material3.TextButton
1717
import androidx.compose.runtime.Composable
1818
import androidx.compose.ui.Alignment
1919
import androidx.compose.ui.Modifier
20-
import androidx.compose.ui.graphics.Color
2120
import androidx.compose.ui.unit.dp
2221
import ooniprobe.composeapp.generated.resources.Dashboard_Progress_ReviewLink_Action
2322
import ooniprobe.composeapp.generated.resources.Dashboard_Progress_ReviewLink_Label
@@ -34,29 +33,37 @@ fun UpdateProgressStatus(
3433
onReviewLinkClicked: () -> Unit = {},
3534
onCancelClicked: () -> Unit = {},
3635
) {
37-
Row(
38-
modifier = modifier.fillMaxWidth()
39-
.height(56.dp)
40-
.background(MaterialTheme.colorScheme.inverseSurface)
41-
.padding(horizontal = 16.dp, vertical = 8.dp),
42-
horizontalArrangement = if (type == UpdateStatusType.FetchingUpdates) Arrangement.spacedBy(10.dp) else Arrangement.SpaceBetween,
43-
verticalAlignment = Alignment.CenterVertically,
36+
Surface(
37+
color = MaterialTheme.colorScheme.inverseSurface,
38+
modifier = modifier,
4439
) {
45-
if (type == UpdateStatusType.FetchingUpdates) {
46-
CircularProgressIndicator()
47-
Text(stringResource(Res.string.Dashboard_Progress_UpdateLink_Label), color = Color.White)
48-
} else if (type == UpdateStatusType.ReviewLink) {
49-
Text(stringResource(Res.string.Dashboard_Progress_ReviewLink_Label), color = Color.White)
50-
Row {
51-
TextButton(onClick = onReviewLinkClicked) {
52-
Text(stringResource(Res.string.Dashboard_Progress_ReviewLink_Action), color = Color.White)
53-
}
54-
IconButton(onClick = onCancelClicked) {
55-
Icon(
56-
imageVector = Icons.Filled.Close,
57-
contentDescription = stringResource(Res.string.Modal_Cancel),
58-
tint = Color.White,
59-
)
40+
Row(
41+
modifier = Modifier.fillMaxWidth()
42+
.height(56.dp)
43+
.padding(horizontal = 16.dp, vertical = 8.dp),
44+
horizontalArrangement =
45+
if (type == UpdateStatusType.FetchingUpdates) {
46+
Arrangement.spacedBy(10.dp)
47+
} else {
48+
Arrangement.SpaceBetween
49+
},
50+
verticalAlignment = Alignment.CenterVertically,
51+
) {
52+
if (type == UpdateStatusType.FetchingUpdates) {
53+
CircularProgressIndicator()
54+
Text(stringResource(Res.string.Dashboard_Progress_UpdateLink_Label))
55+
} else if (type == UpdateStatusType.ReviewLink) {
56+
Text(stringResource(Res.string.Dashboard_Progress_ReviewLink_Label))
57+
Row {
58+
TextButton(onClick = onReviewLinkClicked) {
59+
Text(stringResource(Res.string.Dashboard_Progress_ReviewLink_Action))
60+
}
61+
IconButton(onClick = onCancelClicked) {
62+
Icon(
63+
imageVector = Icons.Filled.Close,
64+
contentDescription = stringResource(Res.string.Modal_Cancel),
65+
)
66+
}
6067
}
6168
}
6269
}

composeApp/src/commonMain/kotlin/org/ooni/probe/ui/theme/AppTheme.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ fun AppTheme(
1515
) {
1616
LightStatusBars(
1717
!useDarkTheme &&
18-
currentRoute != Screen.RunningTest.route &&
19-
currentRoute != Screen.Onboarding.route,
18+
currentRoute != Screen.Onboarding.route &&
19+
currentRoute != Screen.Dashboard.route &&
20+
currentRoute != Screen.RunningTest.route,
2021
)
2122

2223
CompositionLocalProvider(

0 commit comments

Comments
 (0)