[ADDED] App info screen with basic info

Closes #60
This commit is contained in:
Hossain Khan
2025-06-16 19:49:38 -04:00
parent fe4aa1cbd4
commit 4fe4adb6d1
8 changed files with 248 additions and 2 deletions
@@ -19,4 +19,9 @@ object AppConfig {
* Ref: https://discord.com/channels/1281055965508141100/1284986536357662740/1364623667337760910
*/
const val TRMNL_API_SERVER_BASE_URL = "https://trmnl.app/"
/**
* URL for the TRMNL Android app on GitHub.
*/
const val TRMNL_ANDROID_APP_GITHUB_URL = "https://github.com/usetrmnl/trmnl-android"
}
@@ -0,0 +1,200 @@
package ink.trmnl.android.ui.aboutapp
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
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.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.slack.circuit.codegen.annotations.CircuitInject
import com.slack.circuit.runtime.CircuitUiState
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.screen.Screen
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import ink.trmnl.android.BuildConfig
import ink.trmnl.android.R
import ink.trmnl.android.data.AppConfig.TRMNL_ANDROID_APP_GITHUB_URL
import ink.trmnl.android.di.AppScope
import ink.trmnl.android.ui.aboutapp.AppInfoScreen.Event
import ink.trmnl.android.ui.aboutapp.AppInfoScreen.State
import ink.trmnl.android.ui.theme.TrmnlDisplayAppTheme
import ink.trmnl.android.ui.theme.TrmnlOrange
import kotlinx.parcelize.Parcelize
/**
* Screen for displaying app information and links.
*/
@Parcelize
data object AppInfoScreen : Screen {
data class State(
val appVersion: String,
val buildType: String,
val eventSink: (Event) -> Unit,
) : CircuitUiState
sealed class Event {
data object BackPressed : Event()
data object OpenGithub : Event()
}
}
class AppInfoPresenter
@AssistedInject
constructor(
@Assisted private val navigator: Navigator,
) : Presenter<AppInfoScreen.State> {
@Composable
override fun present(): AppInfoScreen.State {
val uriHandler = LocalUriHandler.current
val appVersion = BuildConfig.VERSION_NAME
val buildType = BuildConfig.BUILD_TYPE
return State(
appVersion = appVersion,
buildType = buildType,
eventSink = { event ->
when (event) {
Event.BackPressed -> navigator.pop()
Event.OpenGithub -> {
// Handled in the UI
uriHandler.openUri(TRMNL_ANDROID_APP_GITHUB_URL)
}
}
},
)
}
@CircuitInject(AppInfoScreen::class, AppScope::class)
@AssistedFactory
fun interface Factory {
fun create(navigator: Navigator): AppInfoPresenter
}
}
@CircuitInject(AppInfoScreen::class, AppScope::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppInfoContent(
state: State,
modifier: Modifier = Modifier,
) {
Scaffold(
modifier = modifier,
topBar = {
TopAppBar(
title = { Text("App Info") },
navigationIcon = {
IconButton(onClick = { state.eventSink(Event.BackPressed) }) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
)
}
},
windowInsets = WindowInsets.statusBars,
)
},
contentWindowInsets = WindowInsets.safeDrawing,
) { innerPadding ->
Column(
modifier =
Modifier
.padding(innerPadding)
.padding(horizontal = 32.dp)
.verticalScroll(rememberScrollState())
.fillMaxWidth()
.navigationBarsPadding(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Spacer(modifier = Modifier.height(24.dp))
Icon(
painter = painterResource(R.drawable.trmnl_logo_plain),
contentDescription = null,
tint = TrmnlOrange,
modifier = Modifier.height(64.dp),
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(R.string.app_name),
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.Bold,
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Version: ${state.appVersion}",
style = MaterialTheme.typography.bodyLarge,
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = "Build Type: ${state.buildType}",
style = MaterialTheme.typography.bodyMedium,
)
Spacer(modifier = Modifier.height(32.dp))
Button(
onClick = { state.eventSink(Event.OpenGithub) },
modifier = Modifier.fillMaxWidth(0.7f),
) {
Icon(
painter = painterResource(R.drawable.code_24dp),
contentDescription = null,
modifier = Modifier.padding(end = 8.dp),
)
Text("View Project on GitHub")
}
}
}
}
@PreviewLightDark
@Composable
private fun AppInfoScreenPreview() {
TrmnlDisplayAppTheme {
AppInfoContent(
state =
State(
appVersion = "1.0.0",
buildType = "debug",
eventSink = {},
),
)
}
}
@@ -91,6 +91,7 @@ import ink.trmnl.android.data.TrmnlDisplayRepository
import ink.trmnl.android.di.AppScope
import ink.trmnl.android.model.TrmnlDeviceConfig
import ink.trmnl.android.model.TrmnlDeviceType
import ink.trmnl.android.ui.aboutapp.AppInfoScreen
import ink.trmnl.android.ui.display.TrmnlMirrorDisplayScreen
import ink.trmnl.android.ui.settings.AppSettingsScreen.ValidationResult
import ink.trmnl.android.ui.settings.AppSettingsScreen.ValidationResult.Failure
@@ -193,6 +194,11 @@ data class AppSettingsScreen(
data class ServerUrlChanged(
val url: String,
) : Event()
/**
* Event triggered when the info icon is clicked.
*/
data object AppInfoPressed : Event()
}
}
@@ -358,6 +364,11 @@ class AppSettingsPresenter
validationResult = null
}
}
AppSettingsScreen.Event.AppInfoPressed -> {
// Navigate to AppInfoScreen
navigator.goTo(AppInfoScreen)
}
}
},
)
@@ -439,6 +450,15 @@ fun AppSettingsContent(
}
}
},
// Add the info action button to navigate to AppInfoScreen
actions = {
IconButton(onClick = { state.eventSink(AppSettingsScreen.Event.AppInfoPressed) }) {
Icon(
painter = painterResource(R.drawable.info_24dp),
contentDescription = "App Info",
)
}
},
// Configure the TopAppBar to handle status bar insets
windowInsets = WindowInsets.statusBars,
)
@@ -14,3 +14,6 @@ val Grey80 = Color(0xFFECEFF1)
val Blue40 = Color(0xFF2236B0)
val BlueGrey40 = Color(0xFF546E7A)
val Grey40 = Color(0xFF47676F)
// Add TRMNL color - #F8654B
val TrmnlOrange = Color(0xFFF8654B)
+9
View File
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M320,720 L80,480l240,-240 57,57 -184,184 183,183 -56,56ZM640,720 L583,663 767,479 584,296 640,240 880,480 640,720Z"
android:fillColor="#e8eaed"/>
</vector>
+9
View File
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M440,680h80v-240h-80v240ZM480,360q17,0 28.5,-11.5T520,320q0,-17 -11.5,-28.5T480,280q-17,0 -28.5,11.5T440,320q0,17 11.5,28.5T480,360ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880ZM480,800q134,0 227,-93t93,-227q0,-134 -93,-227t-227,-93q-134,0 -227,93t-93,227q0,134 93,227t227,93ZM480,480Z"
android:fillColor="#e8eaed"/>
</vector>
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#F86527</color>
<color name="ic_launcher_background">#F8654B</color>
</resources>
+1 -1
View File
@@ -1,2 +1,2 @@
F86527
F8654B