android/ui: handle device approval like usual login

This way, after approving a device, the Tailscale app automatically comes back up.

Updates tailscale/corp#19119

Signed-off-by: Percy Wegmann <percy@tailscale.com>
pull/318/head
Percy Wegmann 2 months ago
parent 72b0e365e9
commit 4ceac3bb19
No known key found for this signature in database
GPG Key ID: 29D8CDEB4C13D48B

@ -162,7 +162,7 @@ class MainActivity : ComponentActivity() {
onNavigateToRunAsExitNode = { navController.navigate("runExitNode") })
composable("main", enterTransition = { fadeIn(animationSpec = tween(150)) }) {
MainView(navigation = mainViewNav)
MainView(loginAtURL = ::login, navigation = mainViewNav)
}
composable("settings") { SettingsView(settingsNav) }
composable("exitNodes") { ExitNodePicker(exitNodePickerNav) }

@ -123,6 +123,8 @@ class Tailcfg {
return addresses
}
val primaryIP: String? = Addresses?.first()?.split("/")?.first()
val info: List<PeerSettingInfo>
get() {
val result = mutableListOf<PeerSettingInfo>()

@ -95,7 +95,11 @@ data class MainViewNavigation(
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewModel()) {
fun MainView(
navigation: MainViewNavigation,
loginAtURL: (String) -> Unit,
viewModel: MainViewModel = viewModel()
) {
LoadingIndicator.Wrap {
Scaffold(contentWindowInsets = WindowInsets.Companion.statusBars) { paddingInsets ->
Column(
@ -106,7 +110,6 @@ fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewMode
val stateVal = viewModel.stateRes.collectAsState(initial = R.string.placeholder).value
val stateStr = stringResource(id = stateVal)
val netmap = viewModel.netmap.collectAsState(initial = null)
val isAdmin = viewModel.isAdmin.collectAsState(initial = false).value
ListItem(
colors = MaterialTheme.colorScheme.surfaceContainerListItem,
@ -163,7 +166,13 @@ fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewMode
Ipn.State.NoState,
Ipn.State.Starting -> StartingView()
else -> {
ConnectView(state, user, { viewModel.toggleVpn() }, { viewModel.login {} }, isAdmin)
ConnectView(
state,
user,
{ viewModel.toggleVpn() },
{ viewModel.login {} },
loginAtURL,
netmap.value)
}
}
}
@ -258,7 +267,8 @@ fun ConnectView(
user: IpnLocal.LoginProfile?,
connectAction: () -> Unit,
loginAction: () -> Unit,
isAdmin: Boolean,
loginAtURL: (String) -> Unit,
netmap: Netmap.NetworkMap?,
) {
val handler = LocalUriHandler.current
@ -278,12 +288,14 @@ fun ConnectView(
text = stringResource(id = R.string.machine_auth_explainer),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center)
if (isAdmin) {
PrimaryActionButton(onClick = { handler.openUri(Links.ADMIN_URL) }) {
Text(
text = stringResource(id = R.string.open_admin_console),
fontSize = MaterialTheme.typography.titleMedium.fontSize)
}
Lists.SectionDivider()
netmap?.let {
PrimaryActionButton(
onClick = { loginAtURL("${Links.ADMIN_URL}/machines/${it.SelfNode.primaryIP}") }) {
Text(
text = stringResource(id = R.string.open_admin_console),
fontSize = MaterialTheme.typography.titleMedium.fontSize)
}
}
} else if (state != Ipn.State.NeedsLogin && user != null && !user.isEmpty()) {
Icon(
@ -447,7 +459,7 @@ fun PeerList(
},
supportingContent = {
Text(
text = peer.Addresses?.first()?.split("/")?.first() ?: "",
text = peer.primaryIP ?: "",
style =
MaterialTheme.typography.bodyMedium.copy(
lineHeight = MaterialTheme.typography.titleMedium.lineHeight))

@ -34,8 +34,6 @@ class MainViewModel : IpnViewModel() {
val prefs = Notifier.prefs
val netmap = Notifier.netmap
val isAdmin: StateFlow<Boolean> = MutableStateFlow(false)
// The active search term for filtering peers
val searchTerm: StateFlow<String> = MutableStateFlow("")
@ -55,7 +53,6 @@ class MainViewModel : IpnViewModel() {
it?.let { netmap ->
peerCategorizer.regenerateGroupedPeers(netmap)
peers.set(peerCategorizer.groupedAndFilteredPeers(searchTerm.value))
isAdmin.set(netmap.SelfNode.isAdmin)
}
}
}

Loading…
Cancel
Save