Add contact information to the About screen

This commit is contained in:
Pierre-Yves Nicolas
2025-09-13 08:26:52 +02:00
parent 60fb714356
commit fa41c57388
4 changed files with 106 additions and 45 deletions

View File

@@ -14,8 +14,10 @@
*/
package org.fairscan.app.view
import android.content.Intent
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -25,10 +27,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Email
import androidx.compose.material.icons.filled.Language
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
@@ -48,10 +53,15 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import org.fairscan.app.BuildConfig
import org.fairscan.app.R
import org.fairscan.app.ui.theme.MyScanTheme
@@ -83,71 +93,116 @@ fun AboutContent(
showLicenseDialog: MutableState<Boolean>,
onViewLibraries: () -> Unit,
) {
val context = LocalContext.current
Column(
modifier = modifier
.fillMaxSize()
.padding(16.dp)
.verticalScroll(rememberScrollState())
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
stringResource(R.string.app_name),
style = MaterialTheme.typography.headlineSmall
)
Spacer(Modifier.height(8.dp))
Text(stringResource(R.string.app_name), style = MaterialTheme.typography.headlineMedium)
Text(
stringResource(R.string.app_tagline),
style = MaterialTheme.typography.bodyMedium
textAlign = TextAlign.Center
)
Spacer(Modifier.height(16.dp))
HorizontalDivider()
Spacer(Modifier.height(16.dp))
Text(
stringResource(R.string.version),
style = MaterialTheme.typography.titleMedium
)
Section(title = stringResource(R.string.version)) {
Text(BuildConfig.VERSION_NAME)
}
Spacer(Modifier.height(16.dp))
Section(title = stringResource(R.string.developer)) {
Text("Pierre-Yves Nicolas")
}
Text(
stringResource(R.string.license),
style = MaterialTheme.typography.titleMedium
Section(title = stringResource(R.string.contact)) {
val emailAddress = "contact@fairscan.org"
ContactLink(
icon = Icons.Default.Email,
text = emailAddress,
onClick = {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = "mailto:$emailAddress".toUri()
}
context.startActivity(intent)
}
)
val websiteUrl = "https://fairscan.org"
ContactLink(
icon = Icons.Default.Language,
text = websiteUrl,
onClick = {
val intent = Intent(Intent.ACTION_VIEW, websiteUrl.toUri())
context.startActivity(intent)
}
)
}
Section(title = stringResource(R.string.license)) {
Text(
stringResource(R.string.licensed_under),
style = MaterialTheme.typography.bodyMedium
)
Text(
text = stringResource(R.string.view_the_full_license),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.clickable { showLicenseDialog.value = true },
color = MaterialTheme.colorScheme.primary
)
}
Spacer(Modifier.height(16.dp))
Text(
stringResource(R.string.libraries),
style = MaterialTheme.typography.titleMedium
)
Section(title = stringResource(R.string.libraries)) {
Text(
stringResource(R.string.libraries_intro) +
"\n• CameraX\n• Jetpack Compose\n• LiteRT\n• OpenCV\n• PDFBox",
style = MaterialTheme.typography.bodyMedium)
)
Text(
text = stringResource(R.string.view_full_list),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.clickable(onClick = onViewLibraries),
color = MaterialTheme.colorScheme.primary
)
}
Spacer(Modifier.height(32.dp))
}
}
@Composable
private fun Section(title: String, content: @Composable () -> Unit) {
Column(
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.fillMaxWidth()
) {
Text(title, style = MaterialTheme.typography.titleMedium)
content()
}
}
@Composable
private fun ContactLink(icon: ImageVector, text: String, onClick: () -> Unit) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { onClick() }
.padding(vertical = 4.dp)
) {
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
Spacer(Modifier.width(8.dp))
Text(
text,
style = MaterialTheme.typography.bodyLarge.copy(
color = MaterialTheme.colorScheme.primary,
textDecoration = TextDecoration.Underline
)
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LicenseBottomSheet(

View File

@@ -7,9 +7,11 @@
<string name="camera_permission_rationale">Die App benötigt Zugriff auf die Kamera, um Dokumente zu scannen. Aufgenommene Bilder werden nur auf diesem Gerät gespeichert und beim Schließen des aktuellen Dokuments gelöscht.</string>
<string name="cancel">Abbrechen</string>
<string name="clear_text">Text löschen</string>
<string name="contact">Kontakt</string>
<string name="creating_pdf">PDF wird erstellt…</string>
<string name="delete_page">Seite löschen</string>
<string name="delete_page_warning">Möchten Sie diese Seite löschen?</string>
<string name="developer">Entwickler</string>
<string name="discard_scan">Löschen</string>
<string name="end_scan">Scan beenden</string>
<string name="error">Fehler: %1$s</string>

View File

@@ -6,10 +6,12 @@
<string name="camera_permission_denied">L\'autorisation d\'accès à la caméra a été refusée</string>
<string name="camera_permission_rationale">Lapplication a besoin daccéder à lappareil photo pour scanner des documents. Les images capturées sont enregistrées uniquement sur cet appareil et seront supprimées lorsque vous fermerez le document en cours.</string>
<string name="cancel">Annuler</string>
<string name="contact">Contact</string>
<string name="clear_text">Effacer le text</string>
<string name="creating_pdf">Création du PDF…</string>
<string name="delete_page">Supprimer la page</string>
<string name="delete_page_warning">Voulez-vous supprimer cette page ?</string>
<string name="developer">Développeur</string>
<string name="discard_scan">Supprimer le scan</string>
<string name="end_scan">Terminer le scan</string>
<string name="error">Erreur : %1$s</string>

View File

@@ -8,9 +8,11 @@
<string name="camera_permission_rationale">The app requires camera access to scan documents. Captured images are stored only on this device and will be deleted when you close the current document.</string>
<string name="cancel">Cancel</string>
<string name="clear_text">Clear text</string>
<string name="contact">Contact</string>
<string name="creating_pdf">Creating PDF…</string>
<string name="delete_page">Delete page</string>
<string name="delete_page_warning">Do you want to delete this page?</string>
<string name="developer">Developer</string>
<string name="discard_scan">Discard scan</string>
<string name="end_scan">End scan</string>
<string name="error">Error: %1$s</string>