Skip to content

Commit e5efc02

Browse files
authored
android: add back button to taildrop share activity (#770)
fixes tailscale/corp#39202 Adds a back button to the taildrop share activity. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
1 parent 17c3085 commit e5efc02

2 files changed

Lines changed: 87 additions & 50 deletions

File tree

android/src/main/java/com/tailscale/ipn/ShareActivity.kt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,19 @@ import android.provider.OpenableColumns
1111
import android.webkit.MimeTypeMap
1212
import androidx.activity.ComponentActivity
1313
import androidx.activity.compose.setContent
14+
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.material.icons.Icons
16+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
17+
import androidx.compose.material3.ExperimentalMaterial3Api
18+
import androidx.compose.material3.Icon
19+
import androidx.compose.material3.IconButton
1420
import androidx.compose.material3.MaterialTheme
21+
import androidx.compose.material3.Scaffold
1522
import androidx.compose.material3.Surface
23+
import androidx.compose.material3.Text
24+
import androidx.compose.material3.TopAppBar
1625
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.res.stringResource
1727
import androidx.lifecycle.lifecycleScope
1828
import com.tailscale.ipn.ui.model.Ipn
1929
import com.tailscale.ipn.ui.theme.AppTheme
@@ -34,13 +44,31 @@ class ShareActivity : ComponentActivity() {
3444

3545
private val requestedTransfers: StateFlow<List<Ipn.OutgoingFile>> = MutableStateFlow(emptyList())
3646

47+
@OptIn(ExperimentalMaterial3Api::class)
3748
override fun onCreate(savedInstanceState: Bundle?) {
3849
super.onCreate(savedInstanceState)
3950
setContent {
4051
AppTheme {
4152
Surface(color = MaterialTheme.colorScheme.inverseSurface) { // Background for the letterbox
4253
Surface(modifier = Modifier.universalFit()) {
43-
TaildropView(requestedTransfers, (application as App).applicationScope)
54+
Scaffold(
55+
topBar = {
56+
TopAppBar(
57+
title = { Text(stringResource(R.string.share)) },
58+
navigationIcon = {
59+
IconButton(onClick = { finish() }) {
60+
Icon(
61+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
62+
contentDescription = stringResource(R.string.back),
63+
)
64+
}
65+
},
66+
)
67+
}) { innerPadding ->
68+
Surface(modifier = Modifier.padding(innerPadding)) {
69+
TaildropView(requestedTransfers, (application as App).applicationScope)
70+
}
71+
}
4472
}
4573
}
4674
}

android/src/main/java/com/tailscale/ipn/ui/view/TaildropView.kt

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@ import androidx.compose.foundation.layout.Arrangement
99
import androidx.compose.foundation.layout.Column
1010
import androidx.compose.foundation.layout.Row
1111
import androidx.compose.foundation.layout.Spacer
12-
import androidx.compose.foundation.layout.WindowInsets
1312
import androidx.compose.foundation.layout.fillMaxHeight
1413
import androidx.compose.foundation.layout.padding
1514
import androidx.compose.foundation.layout.size
16-
import androidx.compose.foundation.layout.statusBars
1715
import androidx.compose.foundation.lazy.LazyColumn
1816
import androidx.compose.material3.Icon
1917
import androidx.compose.material3.MaterialTheme
20-
import androidx.compose.material3.Scaffold
2118
import androidx.compose.material3.Text
2219
import androidx.compose.runtime.Composable
2320
import androidx.compose.runtime.LaunchedEffect
@@ -50,7 +47,7 @@ fun TaildropView(
5047
requestedTransfers: StateFlow<List<Ipn.OutgoingFile>>,
5148
applicationScope: CoroutineScope,
5249
viewModel: TaildropViewModel =
53-
viewModel(factory = TaildropViewModelFactory(requestedTransfers, applicationScope))
50+
viewModel(factory = TaildropViewModelFactory(requestedTransfers, applicationScope)),
5451
) {
5552
val TAG = "TaildropView"
5653
val focusRequester = remember { FocusRequester() }
@@ -64,29 +61,28 @@ fun TaildropView(
6461
}
6562
}
6663

67-
Scaffold(contentWindowInsets = WindowInsets.statusBars, topBar = { Header(R.string.share) }) {
68-
paddingInsets ->
69-
Column(modifier = Modifier.focusRequester(focusRequester).focusable().padding(paddingInsets)) {
70-
val showDialog = viewModel.showDialog.collectAsState().value
64+
Column(modifier = Modifier.focusRequester(focusRequester).focusable()) {
65+
val showDialog = viewModel.showDialog.collectAsState().value
7166

72-
showDialog?.let { ErrorDialog(type = it, action = { viewModel.showDialog.set(null) }) }
67+
showDialog?.let { ErrorDialog(type = it, action = { viewModel.showDialog.set(null) }) }
7368

74-
FileShareHeader(
75-
fileTransfers = requestedTransfers.collectAsState().value,
76-
totalSize = viewModel.totalSize)
69+
FileShareHeader(
70+
fileTransfers = requestedTransfers.collectAsState().value,
71+
totalSize = viewModel.totalSize,
72+
)
7773

78-
when (viewModel.state.collectAsState().value) {
79-
Ipn.State.Running -> {
80-
val peers by viewModel.myPeers.collectAsState()
81-
val context = LocalContext.current
82-
FileSharePeerList(
83-
peers = peers,
84-
stateViewGenerator = { peerId -> viewModel.TrailingContentForPeer(peerId = peerId) },
85-
onShare = { viewModel.share(context, it) })
86-
}
87-
else -> {
88-
FileShareConnectView { viewModel.startVPN() }
89-
}
74+
when (viewModel.state.collectAsState().value) {
75+
Ipn.State.Running -> {
76+
val peers by viewModel.myPeers.collectAsState()
77+
val context = LocalContext.current
78+
FileSharePeerList(
79+
peers = peers,
80+
stateViewGenerator = { peerId -> viewModel.TrailingContentForPeer(peerId = peerId) },
81+
onShare = { viewModel.share(context, it) },
82+
)
83+
}
84+
else -> {
85+
FileShareConnectView { viewModel.startVPN() }
9086
}
9187
}
9288
}
@@ -96,7 +92,7 @@ fun TaildropView(
9692
fun FileSharePeerList(
9793
peers: List<Tailcfg.Node>,
9894
stateViewGenerator: @Composable (String) -> Unit,
99-
onShare: (Tailcfg.Node) -> Unit
95+
onShare: (Tailcfg.Node) -> Unit,
10096
) {
10197
SectionDivider(stringResource(R.string.my_devices))
10298

@@ -105,11 +101,13 @@ fun FileSharePeerList(
105101
Column(
106102
modifier = Modifier.padding(horizontal = 8.dp).fillMaxHeight(),
107103
verticalArrangement = Arrangement.Center,
108-
horizontalAlignment = Alignment.CenterHorizontally) {
109-
Text(
110-
stringResource(R.string.no_devices_to_share_with),
111-
style = MaterialTheme.typography.titleMedium)
112-
}
104+
horizontalAlignment = Alignment.CenterHorizontally,
105+
) {
106+
Text(
107+
stringResource(R.string.no_devices_to_share_with),
108+
style = MaterialTheme.typography.titleMedium,
109+
)
110+
}
113111
}
114112
false -> {
115113
LazyColumn {
@@ -119,7 +117,8 @@ fun FileSharePeerList(
119117
peer = peer,
120118
onClick = { onShare(peer) },
121119
subtitle = { peer.Hostinfo.OS ?: "" },
122-
trailingContent = { stateViewGenerator(peer.StableID) })
120+
trailingContent = { stateViewGenerator(peer.StableID) },
121+
)
123122
}
124123
}
125124
}
@@ -132,17 +131,20 @@ fun FileShareConnectView(onToggle: () -> Unit) {
132131
Column(
133132
modifier = Modifier.padding(horizontal = 16.dp).fillMaxHeight(),
134133
verticalArrangement = Arrangement.spacedBy(6.dp, alignment = Alignment.CenterVertically),
135-
horizontalAlignment = Alignment.CenterHorizontally) {
136-
Text(
137-
stringResource(R.string.connect_to_your_tailnet_to_share_files),
138-
style = MaterialTheme.typography.titleMedium)
139-
Spacer(modifier = Modifier.size(1.dp))
140-
PrimaryActionButton(onClick = onToggle) {
141-
Text(
142-
text = stringResource(id = R.string.connect),
143-
fontSize = MaterialTheme.typography.titleMedium.fontSize)
144-
}
145-
}
134+
horizontalAlignment = Alignment.CenterHorizontally,
135+
) {
136+
Text(
137+
stringResource(R.string.connect_to_your_tailnet_to_share_files),
138+
style = MaterialTheme.typography.titleMedium,
139+
)
140+
Spacer(modifier = Modifier.size(1.dp))
141+
PrimaryActionButton(onClick = onToggle) {
142+
Text(
143+
text = stringResource(id = R.string.connect),
144+
fontSize = MaterialTheme.typography.titleMedium.fontSize,
145+
)
146+
}
147+
}
146148
}
147149

148150
@Composable
@@ -155,23 +157,26 @@ fun FileShareHeader(fileTransfers: List<Ipn.OutgoingFile>, totalSize: Long) {
155157
true ->
156158
Text(
157159
stringResource(R.string.no_files_to_share),
158-
style = MaterialTheme.typography.titleMedium)
160+
style = MaterialTheme.typography.titleMedium,
161+
)
159162
false -> {
160163

161164
when (fileTransfers.size) {
162165
1 -> Text(fileTransfers[0].Name, style = MaterialTheme.typography.titleMedium)
163166
else ->
164167
Text(
165168
stringResource(R.string.file_count, fileTransfers.size),
166-
style = MaterialTheme.typography.titleMedium)
169+
style = MaterialTheme.typography.titleMedium,
170+
)
167171
}
168172
}
169173
}
170174
val size = Formatter.formatFileSize(LocalContext.current, totalSize.toLong())
171175
Text(
172176
size,
173177
style = MaterialTheme.typography.titleSmall,
174-
color = MaterialTheme.colorScheme.secondary)
178+
color = MaterialTheme.colorScheme.secondary,
179+
)
175180
}
176181
}
177182
}
@@ -185,7 +190,8 @@ fun IconForTransfer(transfers: List<Ipn.OutgoingFile>) {
185190
Icon(
186191
painter = painterResource(R.drawable.warning),
187192
contentDescription = "no files",
188-
modifier = Modifier.size(32.dp))
193+
modifier = Modifier.size(32.dp),
194+
)
189195
1 -> {
190196
// Show a thumbnail for single image shares.
191197
val context = LocalContext.current
@@ -194,20 +200,23 @@ fun IconForTransfer(transfers: List<Ipn.OutgoingFile>) {
194200
AsyncImage(
195201
model = transfers[0].uri,
196202
contentDescription = "one file",
197-
modifier = Modifier.size(40.dp))
203+
modifier = Modifier.size(40.dp),
204+
)
198205
return
199206
}
200207

201208
Icon(
202209
painter = painterResource(R.drawable.single_file),
203210
contentDescription = "files",
204-
modifier = Modifier.size(40.dp))
211+
modifier = Modifier.size(40.dp),
212+
)
205213
}
206214
}
207215
else ->
208216
Icon(
209217
painter = painterResource(R.drawable.single_file),
210218
contentDescription = "files",
211-
modifier = Modifier.size(40.dp))
219+
modifier = Modifier.size(40.dp),
220+
)
212221
}
213222
}

0 commit comments

Comments
 (0)