diff --git a/android/src/main/java/com/tailscale/ipn/MainActivity.kt b/android/src/main/java/com/tailscale/ipn/MainActivity.kt index 9d98083..fc68ef6 100644 --- a/android/src/main/java/com/tailscale/ipn/MainActivity.kt +++ b/android/src/main/java/com/tailscale/ipn/MainActivity.kt @@ -33,6 +33,7 @@ import com.tailscale.ipn.ui.view.BackNavigation import com.tailscale.ipn.ui.view.BugReportView import com.tailscale.ipn.ui.view.DNSSettingsView import com.tailscale.ipn.ui.view.ExitNodePicker +import com.tailscale.ipn.ui.view.IntroView import com.tailscale.ipn.ui.view.MDMSettingsDebugView import com.tailscale.ipn.ui.view.MainView import com.tailscale.ipn.ui.view.MainViewNavigation @@ -136,6 +137,13 @@ class MainActivity : ComponentActivity() { composable("permissions") { PermissionsView(nav = backNav, openApplicationSettings = ::openApplicationSettings) } + composable("intro") { IntroView { navController.popBackStack() } } + } + + // Show the intro screen one time + if (!introScreenViewed()) { + navController.navigate("intro") + setIntroScreenViewed(true) } } } @@ -209,6 +217,17 @@ class MainActivity : ComponentActivity() { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) } + + private fun introScreenViewed(): Boolean { + return getSharedPreferences("introScreen", Context.MODE_PRIVATE).getBoolean("seen", false) + } + + private fun setIntroScreenViewed(seen: Boolean) { + getSharedPreferences("introScreen", Context.MODE_PRIVATE) + .edit() + .putBoolean("seen", seen) + .apply() + } } class VpnPermissionContract : ActivityResultContract() { diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/IntroView.kt b/android/src/main/java/com/tailscale/ipn/ui/view/IntroView.kt new file mode 100644 index 0000000..3712377 --- /dev/null +++ b/android/src/main/java/com/tailscale/ipn/ui/view/IntroView.kt @@ -0,0 +1,62 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package com.tailscale.ipn.ui.view + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.tailscale.ipn.R + +@Composable +fun IntroView(onContinue: () -> Unit) { + Surface { + Column( + modifier = Modifier.fillMaxHeight().padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally) { + Spacer(modifier = Modifier.height(30.dp)) + Image( + modifier = + Modifier.width(140.dp) + .height(140.dp) + .clip(RoundedCornerShape(50)) + .background(Color.Black) + .padding(15.dp), + painter = painterResource(id = R.drawable.ic_tile), + contentDescription = stringResource(R.string.app_icon_content_description)) + Spacer(modifier = Modifier.height(10.dp)) + Text( + text = stringResource(R.string.tailscale), + style = MaterialTheme.typography.headlineLarge) + Spacer(modifier = Modifier.height(20.dp)) + Text( + text = stringResource(R.string.welcome1), + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center) + Spacer(modifier = Modifier.height(20.dp)) + PrimaryActionButton(onClick = onContinue) { + Text( + text = stringResource(id = R.string.getStarted), + fontSize = MaterialTheme.typography.titleMedium.fontSize) + } + } + } +} diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index 3fe26a3..1348bad 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -200,4 +200,9 @@ Not Connected Taildrop Failed + + Tailscale + Get Started + Tailscale is a mesh VPN for securely connecting your devices. All connections are device-to-device, so we never see your data.\n\nWe collect and use your email address and name, as well as your device name, OS version, and IP address in order to help you to connect your devices and manage your settings. We log when you are connected to your network.\n +