Skip to content

Commit c8396fb

Browse files
committed
Add daita grpc and ui
1 parent 43dace1 commit c8396fb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+453
-80
lines changed

.github/workflows/android-app.yml

+3
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ jobs:
324324
name: relay-list
325325
path: android/app/build/extraAssets
326326

327+
- name: Copy maybenot machines to asset directory
328+
run: cp dist-assets/maybenot_machines android/app/build/extraAssets/maybenot_machines
329+
327330
- name: Build app
328331
uses: burrunan/gradle-cache-action@v1
329332
with:

android/app/build.gradle.kts

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ plugins {
2020
val repoRootPath = rootProject.projectDir.absoluteFile.parentFile.absolutePath
2121
val extraAssetsDirectory = "${project.buildDir}/extraAssets"
2222
val relayListPath = "$extraAssetsDirectory/relays.json"
23+
val maybenotMachinesDirectory = "$extraAssetsDirectory/maybenot_machines"
2324
val defaultChangelogAssetsDirectory = "$repoRootPath/android/src/main/play/release-notes/"
2425
val extraJniDirectory = "${project.buildDir}/extraJni"
2526

@@ -239,6 +240,7 @@ android {
239240
// Ensure all relevant assemble tasks depend on our ensure tasks.
240241
tasks.get("assemble$capitalizedVariantName").apply {
241242
dependsOn(tasks.get("ensureRelayListExist"))
243+
dependsOn(tasks.get("ensureMaybenotMachinesExist"))
242244
dependsOn(tasks.get("ensureJniDirectoryExist"))
243245
dependsOn(tasks.get("ensureValidVersionCode"))
244246
}
@@ -283,6 +285,14 @@ tasks.register("ensureRelayListExist") {
283285
}
284286
}
285287

288+
tasks.register("ensureMaybenotMachinesExist") {
289+
doLast {
290+
if (!file(maybenotMachinesDirectory).exists()) {
291+
throw GradleException("Missing maybenot machines: $maybenotMachinesDirectory")
292+
}
293+
}
294+
}
295+
286296
tasks.register("ensureJniDirectoryExist") {
287297
doLast {
288298
if (!file(extraJniDirectory).exists()) {

android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ private val DUMMY_RELAY_1 =
2222
active = true,
2323
provider =
2424
Provider(providerId = ProviderId("PROVIDER RENTED"), ownership = Ownership.Rented),
25+
daita = false,
2526
)
2627
private val DUMMY_RELAY_2 =
2728
RelayItem.Location.Relay(
@@ -33,6 +34,7 @@ private val DUMMY_RELAY_2 =
3334
active = true,
3435
provider =
3536
Provider(providerId = ProviderId("PROVIDER OWNED"), ownership = Ownership.MullvadOwned),
37+
daita = false,
3638
)
3739
private val DUMMY_RELAY_CITY_1 =
3840
RelayItem.Location.City(

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt

+12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ fun FilterRow(
5757
is FilterChip.Ownership ->
5858
OwnershipFilterChip(it.ownership, onRemoveOwnershipFilter)
5959
is FilterChip.Provider -> ProviderFilterChip(it.count, onRemoveProviderFilter)
60+
is FilterChip.Daita -> DaitaFilterChip()
6061
}
6162
}
6263
}
@@ -67,6 +68,7 @@ fun ProviderFilterChip(providers: Int, onRemoveClick: () -> Unit) {
6768
MullvadFilterChip(
6869
text = stringResource(id = R.string.number_of_providers, providers),
6970
onRemoveClick = onRemoveClick,
71+
showIcon = true,
7072
)
7173
}
7274

@@ -75,6 +77,16 @@ fun OwnershipFilterChip(ownership: Ownership, onRemoveClick: () -> Unit) {
7577
MullvadFilterChip(
7678
text = stringResource(ownership.stringResources()),
7779
onRemoveClick = onRemoveClick,
80+
showIcon = true,
81+
)
82+
}
83+
84+
@Composable
85+
fun DaitaFilterChip() {
86+
MullvadFilterChip(
87+
text = stringResource(id = R.string.setting_chip, stringResource(id = R.string.daita)),
88+
onRemoveClick = {},
89+
showIcon = false,
7890
)
7991
}
8092

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/FilterChip.kt

+9-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ private fun PreviewMullvadFilterChip() {
2424
MullvadFilterChip(
2525
text = stringResource(id = R.string.number_of_providers),
2626
onRemoveClick = {},
27+
showIcon = true,
2728
)
2829
}
2930
}
@@ -36,6 +37,7 @@ fun MullvadFilterChip(
3637
iconColor: Color = MaterialTheme.colorScheme.onPrimary,
3738
text: String,
3839
onRemoveClick: () -> Unit,
40+
showIcon: Boolean,
3941
) {
4042
InputChip(
4143
shape = MaterialTheme.shapes.chipShape,
@@ -55,11 +57,13 @@ fun MullvadFilterChip(
5557
onClick = onRemoveClick,
5658
label = { Text(text = text, style = MaterialTheme.typography.labelMedium) },
5759
trailingIcon = {
58-
Icon(
59-
painter = painterResource(id = R.drawable.icon_close),
60-
contentDescription = null,
61-
modifier = Modifier.size(Dimens.smallIconSize),
62-
)
60+
if (showIcon) {
61+
Icon(
62+
painter = painterResource(id = R.drawable.icon_close),
63+
contentDescription = null,
64+
modifier = Modifier.size(Dimens.smallIconSize),
65+
)
66+
}
6367
},
6468
)
6569
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/LocationInfo.kt

+41-9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ private fun PreviewLocationInfo() {
3333
isVisible = true,
3434
isExpanded = true,
3535
location = null,
36+
isUsingDaita = false,
3637
inAddress = null,
3738
outAddress = "",
3839
)
@@ -48,6 +49,7 @@ fun LocationInfo(
4849
isVisible: Boolean,
4950
isExpanded: Boolean,
5051
location: GeoIpLocation?,
52+
isUsingDaita: Boolean,
5153
inAddress: Triple<String, Int, TransportProtocol>?,
5254
outAddress: String,
5355
) {
@@ -61,15 +63,12 @@ fun LocationInfo(
6163
.then(modifier)
6264
) {
6365
Row(verticalAlignment = Alignment.CenterVertically) {
64-
Text(
65-
text = location?.hostname ?: "",
66-
color =
67-
if (isExpanded) {
68-
colorExpanded
69-
} else {
70-
colorCollapsed
71-
},
72-
style = MaterialTheme.typography.labelLarge.copy(fontWeight = FontWeight.SemiBold),
66+
RelayHostname(
67+
hostname = location?.hostname,
68+
isUsingDaita = isUsingDaita,
69+
isExpanded = isExpanded,
70+
colorExpanded = colorExpanded,
71+
colorCollapsed = colorCollapsed,
7372
)
7473
Chevron(
7574
isExpanded = isExpanded,
@@ -119,3 +118,36 @@ fun LocationInfo(
119118
)
120119
}
121120
}
121+
122+
@Composable
123+
private fun RelayHostname(
124+
hostname: String?,
125+
isUsingDaita: Boolean,
126+
isExpanded: Boolean,
127+
colorExpanded: Color,
128+
colorCollapsed: Color,
129+
) {
130+
val hostnameTitle =
131+
when {
132+
hostname != null && isUsingDaita -> {
133+
stringResource(
134+
id = R.string.connected_using_daita,
135+
hostname,
136+
stringResource(id = R.string.daita),
137+
)
138+
}
139+
hostname != null -> hostname
140+
else -> ""
141+
}
142+
143+
Text(
144+
text = hostnameTitle,
145+
color =
146+
if (isExpanded) {
147+
colorExpanded
148+
} else {
149+
colorCollapsed
150+
},
151+
style = MaterialTheme.typography.labelLarge.copy(fontWeight = FontWeight.SemiBold),
152+
)
153+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package net.mullvad.mullvadvpn.compose.dialog
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Spacer
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.height
8+
import androidx.compose.foundation.rememberScrollState
9+
import androidx.compose.foundation.verticalScroll
10+
import androidx.compose.material3.AlertDialog
11+
import androidx.compose.material3.Icon
12+
import androidx.compose.material3.MaterialTheme
13+
import androidx.compose.material3.Text
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.res.painterResource
18+
import androidx.compose.ui.res.stringResource
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.lifecycle.compose.dropUnlessResumed
21+
import com.ramcosta.composedestinations.annotation.Destination
22+
import com.ramcosta.composedestinations.annotation.RootGraph
23+
import com.ramcosta.composedestinations.result.EmptyResultBackNavigator
24+
import com.ramcosta.composedestinations.result.ResultBackNavigator
25+
import com.ramcosta.composedestinations.spec.DestinationStyle
26+
import net.mullvad.mullvadvpn.R
27+
import net.mullvad.mullvadvpn.compose.button.PrimaryButton
28+
import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar
29+
import net.mullvad.mullvadvpn.lib.theme.AppTheme
30+
import net.mullvad.mullvadvpn.lib.theme.Dimens
31+
import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar
32+
33+
@Preview
34+
@Composable
35+
private fun PreviewDaitaConfirmationDialog() {
36+
AppTheme { DaitaConfirmation(EmptyResultBackNavigator()) }
37+
}
38+
39+
@Destination<RootGraph>(style = DestinationStyle.Dialog::class)
40+
@Composable
41+
fun DaitaConfirmation(navigator: ResultBackNavigator<Boolean>) {
42+
AlertDialog(
43+
onDismissRequest = dropUnlessResumed { navigator.navigateBack(false) },
44+
icon = {
45+
Icon(
46+
modifier = Modifier.fillMaxWidth().height(Dimens.dialogIconHeight),
47+
painter = painterResource(id = R.drawable.icon_alert),
48+
contentDescription = null,
49+
tint = MaterialTheme.colorScheme.onSurface,
50+
)
51+
},
52+
text = {
53+
val scrollState = rememberScrollState()
54+
Column(
55+
Modifier.drawVerticalScrollbar(
56+
scrollState,
57+
MaterialTheme.colorScheme.onPrimary.copy(alpha = AlphaScrollbar),
58+
)
59+
.verticalScroll(scrollState),
60+
horizontalAlignment = Alignment.CenterHorizontally,
61+
) {
62+
Text(
63+
text = stringResource(id = R.string.daita_relay_subset_warning),
64+
color = MaterialTheme.colorScheme.onSurface,
65+
style = MaterialTheme.typography.bodySmall,
66+
modifier = Modifier.fillMaxWidth(),
67+
)
68+
69+
Spacer(modifier = Modifier.height(Dimens.verticalSpace))
70+
71+
Text(
72+
text =
73+
stringResource(
74+
id = R.string.daita_warning,
75+
stringResource(id = R.string.daita),
76+
),
77+
color = MaterialTheme.colorScheme.onSurface,
78+
style = MaterialTheme.typography.bodySmall,
79+
modifier = Modifier.fillMaxWidth(),
80+
)
81+
}
82+
},
83+
confirmButton = {
84+
Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) {
85+
PrimaryButton(
86+
modifier = Modifier.fillMaxWidth(),
87+
text = stringResource(R.string.enable_anyway),
88+
onClick = { navigator.navigateBack(true) },
89+
)
90+
91+
PrimaryButton(
92+
modifier = Modifier.fillMaxWidth(),
93+
text = stringResource(R.string.back),
94+
onClick = dropUnlessResumed { navigator.navigateBack(false) },
95+
)
96+
}
97+
},
98+
containerColor = MaterialTheme.colorScheme.surface,
99+
titleContentColor = MaterialTheme.colorScheme.onSurface,
100+
)
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package net.mullvad.mullvadvpn.compose.dialog
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.ui.res.stringResource
5+
import androidx.compose.ui.tooling.preview.Preview
6+
import androidx.lifecycle.compose.dropUnlessResumed
7+
import com.ramcosta.composedestinations.annotation.Destination
8+
import com.ramcosta.composedestinations.annotation.RootGraph
9+
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
10+
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
11+
import com.ramcosta.composedestinations.spec.DestinationStyle
12+
import net.mullvad.mullvadvpn.R
13+
import net.mullvad.mullvadvpn.lib.theme.AppTheme
14+
15+
@Preview
16+
@Composable
17+
private fun PreviewDaitaInfoDialog() {
18+
AppTheme { DaitaInfo(EmptyDestinationsNavigator) }
19+
}
20+
21+
@Destination<RootGraph>(style = DestinationStyle.Dialog::class)
22+
@Composable
23+
fun DaitaInfo(navigator: DestinationsNavigator) {
24+
InfoDialog(
25+
message =
26+
stringResource(
27+
id = R.string.daita_info,
28+
stringResource(id = R.string.daita),
29+
stringResource(id = R.string.daita_full),
30+
),
31+
additionalInfo =
32+
stringResource(id = R.string.daita_warning, stringResource(id = R.string.daita)),
33+
onDismiss = dropUnlessResumed { navigator.navigateUp() },
34+
)
35+
}

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/RelayItemPreviewData.kt

+2
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,13 @@ private fun generateRelayItemRelay(
5151
cityCode: GeoLocationId.City,
5252
hostName: String,
5353
active: Boolean = true,
54+
daita: Boolean = true,
5455
) =
5556
RelayItem.Location.Relay(
5657
id = GeoLocationId.Hostname(city = cityCode, code = hostName),
5758
active = active,
5859
provider = Provider(ProviderId("Provider"), Ownership.MullvadOwned),
60+
daita = daita,
5961
)
6062

6163
private fun String.generateCountryCode() =

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/TunnelStatePreviewData.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ object TunnelStatePreviewData {
1818

1919
fun generateConnectingState(featureIndicators: Int, quantumResistant: Boolean) =
2020
TunnelState.Connecting(
21-
endpoint = generateTunnelEndpoint(quantumResistant = quantumResistant),
21+
endpoint = generateTunnelEndpoint(quantumResistant = quantumResistant, daita = false),
2222
location = generateLocation(),
2323
featureIndicators = generateFeatureIndicators(featureIndicators),
2424
)
2525

2626
fun generateConnectedState(featureIndicators: Int, quantumResistant: Boolean) =
2727
TunnelState.Connected(
28-
endpoint = generateTunnelEndpoint(quantumResistant = quantumResistant),
28+
endpoint = generateTunnelEndpoint(quantumResistant = quantumResistant, daita = true),
2929
location = generateLocation(),
3030
featureIndicators = generateFeatureIndicators(featureIndicators),
3131
)
@@ -39,7 +39,7 @@ object TunnelStatePreviewData {
3939
)
4040
}
4141

42-
private fun generateTunnelEndpoint(quantumResistant: Boolean): TunnelEndpoint =
42+
private fun generateTunnelEndpoint(quantumResistant: Boolean, daita: Boolean): TunnelEndpoint =
4343
TunnelEndpoint(
4444
endpoint = generateEndpoint(TransportProtocol.Udp),
4545
quantumResistant = quantumResistant,
@@ -48,6 +48,7 @@ private fun generateTunnelEndpoint(quantumResistant: Boolean): TunnelEndpoint =
4848
endpoint = generateEndpoint(TransportProtocol.Tcp),
4949
ObfuscationType.Udp2Tcp,
5050
),
51+
daita = daita,
5152
)
5253

5354
private fun generateEndpoint(transportProtocol: TransportProtocol) =

android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt

+1
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ private fun ConnectionInfo(state: ConnectUiState) {
356356
isVisible = state.showLocationInfo,
357357
isExpanded = expanded,
358358
location = state.location,
359+
isUsingDaita = state.tunnelState.isUsingDaita(),
359360
inAddress = state.inAddress,
360361
outAddress = state.outAddress,
361362
modifier =

0 commit comments

Comments
 (0)