diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3256370..ad7176d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,8 +22,8 @@ android { // (android.media.midi) and AAudio low-latency audio we rely on. minSdk = 26 targetSdk = 34 - versionCode = 27 - versionName = "0.10.0" + versionCode = 29 + versionName = "0.11.1" // We provide our own instrumentation runner if/when tests are added. testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/space/rcmd/android/sizzle/ui/settings/SettingsScreen.kt b/app/src/main/java/space/rcmd/android/sizzle/ui/settings/SettingsScreen.kt index 23ee0ed..9893db0 100644 --- a/app/src/main/java/space/rcmd/android/sizzle/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/space/rcmd/android/sizzle/ui/settings/SettingsScreen.kt @@ -7,6 +7,7 @@ import android.content.Context import android.content.Intent import android.media.AudioDeviceInfo import android.media.AudioManager +import android.net.Uri import android.view.KeyEvent import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult @@ -93,6 +94,7 @@ fun SettingsScreen(vm: AppViewModel) { ) { item { PanicButton(vm) } item { ProjectCard(vm) } + item { HelpCard() } item { AudioDevicesCard(vm) } item { InterfaceCard(vm) } item { ThemeCard(vm) } @@ -370,6 +372,50 @@ private fun AudioDevicesCard(vm: AppViewModel) { } } +/** About + external links: app version, source, user guide, and support. */ +@Composable +private fun HelpCard() { + val context = LocalContext.current + val version = remember { + runCatching { context.packageManager.getPackageInfo(context.packageName, 0).versionName }.getOrNull() + } + val appName = remember { context.applicationInfo.loadLabel(context.packageManager).toString() } + SettingsCard("Help", subtitle = "About, source, user guide & support") { + Text( + appName + (version?.let { " v$it" } ?: ""), + style = MaterialTheme.typography.bodyMedium, + ) + LinkRow("Source code", "https://git.rcmd.space/tiredsysadmin/sizzletracker-android") + LinkRow( + "User guide", + "https://git.rcmd.space/tiredsysadmin/sizzletracker-android/src/branch/main/docs/USER_GUIDE.md", + ) + LinkRow("Support us", "https://rcmd.space/pages/support/") + } +} + +/** A tappable label + destination URL that opens in the system browser. A tall, + * full-width row (~64 dp) so it's a comfortable thumb target on a phone. */ +@Composable +private fun LinkRow(label: String, url: String) { + val context = LocalContext.current + Row( + Modifier.fillMaxWidth().clickable { openUrl(context, url) }.padding(vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Column(Modifier.weight(1f)) { + Text(label, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary) + Text(url, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + Icon(Icons.Filled.ChevronRight, contentDescription = null, tint = MaterialTheme.colorScheme.primary) + } +} + +/** Open [url] in the user's browser; a missing browser is ignored rather than crashing. */ +private fun openUrl(context: Context, url: String) { + runCatching { context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) } +} + /** Interface options: currently the mixer VU-meter toggle. */ @Composable private fun InterfaceCard(vm: AppViewModel) {