-
Notifications
You must be signed in to change notification settings - Fork 491
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
android: implement the bug reporting and about screen and localize
updates tailscale/corp#18202 fixes ENG-2876 Adds the bug reporting view. Functional, but not properly styled. Moves the various link URLs to a constants file and corrects link-opening in both but reporting and the settings screen. Adds an AboutView with app icon and same content as the iOS version. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
- Loading branch information
Showing
12 changed files
with
450 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright (c) Tailscale Inc & AUTHORS | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
package com.tailscale.ipn.ui | ||
|
||
object Links { | ||
const val DEFAULT_CONTROL_URL = "https://controlplane.tailscale.com" | ||
const val SERVER_URL = "https://login.tailscale.com" | ||
const val ADMIN_URL = SERVER_URL + "/admin" | ||
const val SIGNIN_URL = "https://tailscale.com/login" | ||
const val PRIVACY_POLICY_URL = "https://tailscale.com/privacy-policy/" | ||
const val TERMS_URL = "https://tailscale.com/terms" | ||
const val DOCS_URL = "https://tailscale.com/kb/" | ||
const val START_GUIDE_URL = "https://tailscale.com/kb/1017/install/" | ||
const val LICENSES_URL = "https://tailscale.com/licenses/android" | ||
const val DELETE_ACCOUNT_URL = "https://login.tailscale.com/login?next_url=%2Fadmin%2Fsettings%2Fgeneral" | ||
const val TAILNET_LOCK_KB_URL = "https://tailscale.com/kb/1226/tailnet-lock/" | ||
const val KEY_EXPIRY_KB_URL = "https://tailscale.com/kb/1028/key-expiry/" | ||
const val INSTALL_TAILSCALE_KB_URL = "https://tailscale.com/kb/installation/" | ||
const val INSTALL_UNSTABLE_KB_URL = "https://tailscale.com/kb/1083/install-unstable" | ||
const val MAGICDNS_KB_URL = "https://tailscale.com/kb/1081/magicdns" | ||
const val TROUBLESHOOTING_KB_URL = "https://tailscale.com/kb/1023/troubleshooting" | ||
const val SUPPORT_URL = "https://tailscale.com/contact/support#support-form" | ||
const val TAILDROP_KB_URL = "https://tailscale.com/kb/1106/taildrop" | ||
const val TAILFS_KB_URL = "https://tailscale.com/kb/1106/taildrop" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
android/src/main/java/com/tailscale/ipn/ui/view/AboutView.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// 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.Arrangement | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxHeight | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.layout.safeContentPadding | ||
import androidx.compose.foundation.layout.width | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material3.Button | ||
import androidx.compose.material3.ButtonDefaults | ||
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.platform.LocalUriHandler | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.font.FontWeight | ||
import androidx.compose.ui.text.style.TextAlign | ||
import androidx.compose.ui.unit.dp | ||
import com.tailscale.ipn.BuildConfig | ||
import com.tailscale.ipn.R | ||
import com.tailscale.ipn.ui.Links | ||
|
||
@Composable | ||
fun AboutView() { | ||
Surface(color = MaterialTheme.colorScheme.surface) { | ||
Column( | ||
verticalArrangement = Arrangement.spacedBy( | ||
space = 20.dp, alignment = Alignment.CenterVertically | ||
), | ||
horizontalAlignment = Alignment.CenterHorizontally, | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.fillMaxHeight() | ||
.safeContentPadding() | ||
) { | ||
Image( | ||
modifier = Modifier | ||
.width(100.dp) | ||
.height(100.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) | ||
) | ||
Column( | ||
verticalArrangement = Arrangement.spacedBy( | ||
space = 2.dp, alignment = Alignment.CenterVertically | ||
), horizontalAlignment = Alignment.CenterHorizontally | ||
) { | ||
Text( | ||
stringResource(R.string.about_view_title), | ||
fontWeight = FontWeight.SemiBold, | ||
fontSize = MaterialTheme.typography.titleLarge.fontSize, | ||
color = MaterialTheme.colorScheme.primary | ||
) | ||
Text( | ||
text = BuildConfig.VERSION_NAME, | ||
fontWeight = MaterialTheme.typography.bodyMedium.fontWeight, | ||
fontSize = MaterialTheme.typography.bodyMedium.fontSize, | ||
color = MaterialTheme.colorScheme.secondary | ||
) | ||
} | ||
Column( | ||
verticalArrangement = Arrangement.spacedBy( | ||
space = 4.dp, alignment = Alignment.CenterVertically | ||
), horizontalAlignment = Alignment.CenterHorizontally | ||
) { | ||
OpenURLButton( | ||
stringResource(R.string.acknowledgements), Links.LICENSES_URL | ||
) | ||
OpenURLButton( | ||
stringResource(R.string.privacy_policy), Links.PRIVACY_POLICY_URL | ||
) | ||
OpenURLButton( | ||
stringResource(R.string.terms_of_service), Links.TERMS_URL | ||
) | ||
} | ||
|
||
Text( | ||
stringResource(R.string.about_view_footnotes), | ||
fontWeight = FontWeight.Normal, | ||
fontSize = MaterialTheme.typography.labelMedium.fontSize, | ||
color = MaterialTheme.colorScheme.tertiary, | ||
textAlign = TextAlign.Center | ||
) | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun OpenURLButton(title: String, url: String) { | ||
val handler = LocalUriHandler.current | ||
|
||
Button( | ||
onClick = { handler.openUri(url) }, | ||
content = { | ||
Text(title) | ||
}, | ||
colors = ButtonDefaults.buttonColors( | ||
contentColor = MaterialTheme.colorScheme.secondary, | ||
containerColor = MaterialTheme.colorScheme.secondaryContainer | ||
) | ||
) | ||
} |
113 changes: 113 additions & 0 deletions
113
android/src/main/java/com/tailscale/ipn/ui/view/BugReportView.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright (c) Tailscale Inc & AUTHORS | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
package com.tailscale.ipn.ui.view | ||
|
||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.width | ||
import androidx.compose.foundation.text.ClickableText | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.outlined.Share | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Surface | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.platform.LocalClipboardManager | ||
import androidx.compose.ui.platform.LocalUriHandler | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.AnnotatedString | ||
import androidx.compose.ui.text.SpanStyle | ||
import androidx.compose.ui.text.buildAnnotatedString | ||
import androidx.compose.ui.text.style.TextAlign | ||
import androidx.compose.ui.text.style.TextOverflow | ||
import androidx.compose.ui.text.withStyle | ||
import androidx.compose.ui.unit.dp | ||
import com.tailscale.ipn.R | ||
import com.tailscale.ipn.ui.Links | ||
import com.tailscale.ipn.ui.util.defaultPaddingModifier | ||
import com.tailscale.ipn.ui.util.settingsRowModifier | ||
import com.tailscale.ipn.ui.viewModel.BugReportViewModel | ||
import kotlinx.coroutines.flow.StateFlow | ||
|
||
|
||
@Composable | ||
fun BugReportView(viewModel: BugReportViewModel) { | ||
val handler = LocalUriHandler.current | ||
|
||
Surface(color = MaterialTheme.colorScheme.surface) { | ||
Column(modifier = defaultPaddingModifier().fillMaxWidth()) { | ||
Text(text = stringResource(id = R.string.bug_report_title), | ||
modifier = Modifier.fillMaxWidth(), | ||
textAlign = TextAlign.Center, | ||
style = MaterialTheme.typography.titleMedium) | ||
|
||
Spacer(modifier = Modifier.height(8.dp)) | ||
|
||
ClickableText(text = contactText(), | ||
modifier = Modifier.fillMaxWidth(), | ||
style = MaterialTheme.typography.bodyMedium, | ||
onClick = { | ||
handler.openUri(Links.SUPPORT_URL) | ||
}) | ||
|
||
Spacer(modifier = Modifier.height(8.dp)) | ||
|
||
ReportIdRow(bugReportIdFlow = viewModel.bugReportID) | ||
|
||
Spacer(modifier = Modifier.height(8.dp)) | ||
|
||
Text(text = stringResource(id = R.string.bug_report_id_desc), | ||
modifier = Modifier.fillMaxWidth(), | ||
textAlign = TextAlign.Left, | ||
style = MaterialTheme.typography.bodySmall) | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun ReportIdRow(bugReportIdFlow: StateFlow<String>) { | ||
val localClipboardManager = LocalClipboardManager.current | ||
val bugReportId = bugReportIdFlow.collectAsState() | ||
|
||
Row(modifier = settingsRowModifier() | ||
.fillMaxWidth() | ||
.clickable(onClick = { localClipboardManager.setText(AnnotatedString(bugReportId.value)) }), | ||
verticalAlignment = Alignment.CenterVertically) { | ||
Box(Modifier.weight(10f)) { | ||
Text(text = bugReportId.value, style = MaterialTheme.typography.titleMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = defaultPaddingModifier()) | ||
} | ||
Box(Modifier.weight(1f)) { | ||
Icon(Icons.Outlined.Share, null, modifier = Modifier | ||
.width(24.dp) | ||
.height(24.dp)) | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun contactText(): AnnotatedString { | ||
val annotatedString = buildAnnotatedString { | ||
append(stringResource(id = R.string.bug_report_instructions_prefix)) | ||
|
||
pushStringAnnotation(tag = "reportLink", annotation = Links.SUPPORT_URL) | ||
withStyle(style = SpanStyle(color = Color.Blue)) { | ||
append(stringResource(id = R.string.bug_report_instructions_linktext)) | ||
} | ||
pop() | ||
|
||
append(stringResource(id = R.string.bug_report_instructions_suffix)) | ||
} | ||
return annotatedString | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.