diff --git a/app/build.gradle b/app/build.gradle
index b7ff841..f0256b1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -78,6 +78,7 @@ android {
}
buildFeatures {
compose true
+ buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
diff --git a/app/src/main/java/app/myzel394/alibi/ui/Constants.kt b/app/src/main/java/app/myzel394/alibi/ui/Constants.kt
index 903c212..bf3dce1 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/Constants.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/Constants.kt
@@ -6,3 +6,46 @@ import androidx.compose.ui.unit.dp
val BIG_PRIMARY_BUTTON_SIZE = 64.dp
val MAX_AMPLITUDE = 20000
val SUPPORTS_DARK_MODE_NATIVELY = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
+
+// You are not allowed to change the constants below.
+// If you do so, you will be blocked on GitHub.
+const val REPO_URL = "https://github.com/Myzel394/Alibi"
+const val TRANSLATION_HELP_URL = "https://crowdin.com/project/alibi"
+const val GITHUB_SPONSORS_URL = "https://github.com/sponsors/Myzel394"
+const val PUBLIC_KEY = """-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEZTfvnhYJKwYBBAHaRw8BAQdAi2AiLsTaBoLhnQtY5vi3xBU/H428wbNfBSe+
+2dhz3r60Jk15emVsMzk0IDxnaXRodWIuN2Eyb3BAc2ltcGxlbG9naW4uY28+iJkE
+ExYKAEEWIQR9BS8nNHwqrNgV0B3NE0dCwel5WQUCZTfvngIbAwUJEswDAAULCQgH
+AgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRDNE0dCwel5WcS8AQCf9g6eEaut1suW
+l6jCLIg3b1nWLckmLJaonM6PruUtigEAmVnFOxMpOZEIcILT8CD2Riy+IVN9gTNH
+qOHnaFsu8AK4OARlN++eEgorBgEEAZdVAQUBAQdAe4ffDtRundKH9kam746i2TBu
+P9sfb3QVi5QqfK+bek8DAQgHiH4EGBYKACYWIQR9BS8nNHwqrNgV0B3NE0dCwel5
+WQUCZTfvngIbDAUJEswDAAAKCRDNE0dCwel5WWwSAQDj4ZAl6bSqwbcptEMYQaPM
+MMhMafm446MjkhQioeXw+wEAzA8mS6RBx7IZvu1dirmFHXOEYJclwjyQhNs4uEjq
+/Ak=
+=ICHe
+-----END PGP PUBLIC KEY BLOCK-----"""
+const val PUBLIC_KEY_FINGERPRINT = "7D05 2F27 347C 2AAC D815 D01D CD13 4742 C1E9 7959"
+val CRYPTO_DONATIONS = mapOf(
+ "Bitcoin" to "bc1qw054829yj8e2u8glxnfcg3w22dkek577mjt5x6",
+ "Bitcoin Cash" to "qr9s64vfqedvurfef9ykf7szchmt0xyvnga452fc8l",
+ "Ethereum" to "0xbb5E631c03C65334d1d9EfBCD926DC1265CC20D7",
+ "Tether USD" to "0xbb5E631c03C65334d1d9EfBCD926DC1265CC20D7",
+ "Monero" to "83dm5wyuckG4aPbuMREHCEgLNwVn5i7963SKBhECaA7Ueb7DKBTy639R3QfMtb3DsFHMp8u6WGiCFgbdRDBBcz5sLduUtm8",
+ "Zcash" to "t1ZfvNpzfdaW6csT9Kc7iJA7LUU3hmNj2sx",
+ "Litecoin" to "LZayhTosZ9ToRvcbeR1gEDgb76Z7ZA2drN",
+ "Dash" to "XcTkni8CVAXBcuc5VwvHmsYftVK4CPLetU",
+ "Avalanche" to "0xbb5E631c03C65334d1d9EfBCD926DC1265CC20D7",
+ "XRP" to "rNpfDm8UwDTumCebchBadjVW2FEPteFgNg",
+ "Solana" to "2h6CB3hz5Vb2nYS1RQiXZ4aWTzc5frBPR7Sp1b4muFqb",
+ "ADA" to "addr1q8vy2vcp6lacaw8lkc29gufuzajaytc5qc0c2mxlmw5lndxcg5esr4lm36u0lds523cnc9m96gh3gpsls4kdlkaflx6qf6qpvc",
+ "Dogecoin" to "DUA4j7mVoc7Rvezu8YgeRKwxNuMzKeDoxD",
+ "Tron" to "THWVLGhne5wDsGjd1CNenHDKQGzvGzrzLb",
+ "Polkadot" to "1642iaR6AoKyM6qnnMHkfCRfRqRKJ2wC6Cm3UEWEFEz6EtZR",
+ "Cosmos" to "cosmos1vt5z6rfj5sgnkdlddkuu8srw3xupyqxscva9hz",
+ "Algorand" to "QBOQ6VSLMD77QEF33P5J3HKGOM5RZLNO6P5P3FTWCMQM3ORF6QY2W34KUI",
+ "Tezos" to "tz1QUWNYuFqDibGCrwmkdaHSpTx3d6ZdxLMi",
+ "Litecoin" to "LZayhTosZ9ToRvcbeR1gEDgb76Z7ZA2drN",
+ "Filecoin" to "f1j6pm3chzhgadpf6iwmtux33jb5gccj5arkg4dsq",
+)
diff --git a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt
index bd4bca3..efef5d4 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt
@@ -27,6 +27,7 @@ import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.LastRecording
import app.myzel394.alibi.ui.enums.Screen
import app.myzel394.alibi.ui.models.AudioRecorderModel
+import app.myzel394.alibi.ui.screens.AboutScreen
import app.myzel394.alibi.ui.screens.AudioRecorder
import app.myzel394.alibi.ui.screens.CustomRecordingNotificationsScreen
import app.myzel394.alibi.ui.screens.SettingsScreen
@@ -111,5 +112,18 @@ fun Navigation(
navController = navController,
)
}
+ composable(
+ Screen.About.route,
+ enterTransition = {
+ scaleIn()
+ },
+ exitTransition = {
+ scaleOut() + fadeOut(tween(150))
+ }
+ ) {
+ AboutScreen(
+ navController = navController,
+ )
+ }
}
}
diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AboutScreen/atoms/DonationsTile.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AboutScreen/atoms/DonationsTile.kt
new file mode 100644
index 0000000..1944e38
--- /dev/null
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/AboutScreen/atoms/DonationsTile.kt
@@ -0,0 +1,182 @@
+package app.myzel394.alibi.ui.components.AboutScreen.atoms
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.expandVertically
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.horizontalScroll
+import androidx.compose.foundation.layout.Arrangement
+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.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowDropDown
+import androidx.compose.material.icons.filled.ContentCopy
+import androidx.compose.material.icons.filled.CurrencyBitcoin
+import androidx.compose.material.icons.filled.CurrencyFranc
+import androidx.compose.material.icons.filled.CurrencyLira
+import androidx.compose.material.icons.filled.CurrencyPound
+import androidx.compose.material.icons.filled.CurrencyRuble
+import androidx.compose.material.icons.filled.CurrencyRupee
+import androidx.compose.material.icons.filled.CurrencyYen
+import androidx.compose.material.icons.filled.CurrencyYuan
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalUriHandler
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import app.myzel394.alibi.R
+import app.myzel394.alibi.ui.CRYPTO_DONATIONS
+import app.myzel394.alibi.ui.GITHUB_SPONSORS_URL
+import app.myzel394.alibi.ui.PUBLIC_KEY
+
+@Composable
+fun DonationsTile() {
+ var donationsOpened by rememberSaveable {
+ mutableStateOf(false)
+ }
+ val label = stringResource(R.string.ui_about_contribute_donatation)
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(MaterialTheme.shapes.medium)
+ .semantics {
+ contentDescription = label
+ }
+ .clickable {
+ donationsOpened = !donationsOpened
+ }
+ .background(
+ MaterialTheme.colorScheme.surfaceVariant
+ )
+ .padding(16.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ listOf(
+ Icons.Default.CurrencyBitcoin,
+ Icons.Default.CurrencyFranc,
+ Icons.Default.CurrencyLira,
+ Icons.Default.CurrencyPound,
+ Icons.Default.CurrencyRuble,
+ Icons.Default.CurrencyRupee,
+ Icons.Default.CurrencyYen,
+ Icons.Default.CurrencyYuan,
+ ).asSequence().shuffled().first(),
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize.times(1.2f))
+ )
+ Text(
+ stringResource(R.string.ui_about_contribute_donatation),
+ fontWeight = FontWeight.Bold,
+ )
+ }
+
+ val rotation by animateFloatAsState(
+ if (donationsOpened) -180f else 0f,
+ label = "iconRotation"
+ )
+
+ Icon(
+ Icons.Default.ArrowDropDown,
+ contentDescription = null,
+ modifier = Modifier
+ .size(ButtonDefaults.IconSize.times(1.2f))
+ .rotate(rotation)
+ )
+ }
+
+ val clipboardManager =
+ LocalContext.current.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+
+ AnimatedVisibility(
+ visible = donationsOpened,
+ enter = expandVertically(),
+ ) {
+ Column {
+ val uriHandler = LocalUriHandler.current
+
+ Button(
+ onClick = {
+ uriHandler.openUri(GITHUB_SPONSORS_URL)
+ },
+ colors = ButtonDefaults.textButtonColors(),
+ modifier = Modifier.fillMaxWidth(),
+ ) {
+ Image(
+ painter = painterResource(R.drawable.ic_github),
+ colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary),
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize.times(1.2f))
+ )
+ Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
+ Text(
+ stringResource(R.string.ui_about_contribute_donation_githubSponsors)
+ )
+ }
+ for (crypto in CRYPTO_DONATIONS) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(MaterialTheme.shapes.medium)
+ .clickable {
+ val clip = ClipData.newPlainText("text", crypto.value)
+ clipboardManager.setPrimaryClip(clip)
+ }
+ .padding(16.dp)
+ .horizontalScroll(rememberScrollState()),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ Icons.Default.ContentCopy,
+ contentDescription = null,
+ )
+ Text(
+ crypto.key,
+ style = MaterialTheme.typography.bodyMedium,
+ fontWeight = FontWeight.Bold,
+ )
+ Text(
+ crypto.value,
+ fontSize = MaterialTheme.typography.bodyMedium.fontSize.times(0.5),
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AboutScreen/atoms/GPGKeyOverview.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AboutScreen/atoms/GPGKeyOverview.kt
new file mode 100644
index 0000000..572f888
--- /dev/null
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/AboutScreen/atoms/GPGKeyOverview.kt
@@ -0,0 +1,77 @@
+package app.myzel394.alibi.ui.components.AboutScreen.atoms
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Key
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+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.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import app.myzel394.alibi.R
+import app.myzel394.alibi.ui.PUBLIC_KEY_FINGERPRINT
+import app.myzel394.alibi.ui.PUBLIC_KEY
+
+@Composable
+fun GPGKeyOverview() {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(MaterialTheme.shapes.medium)
+ .background(
+ MaterialTheme.colorScheme.primaryContainer
+ )
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ ) {
+ Icon(
+ Icons.Default.Key,
+ contentDescription = null,
+ modifier = Modifier.size(48.dp)
+ )
+
+ Text(
+ stringResource(R.string.ui_about_gpg_key_hint),
+ style = MaterialTheme.typography.bodyMedium,
+ )
+
+ val clipboardManager =
+ LocalContext.current.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ Text(
+ PUBLIC_KEY_FINGERPRINT,
+ modifier = Modifier
+ .clip(MaterialTheme.shapes.small)
+ .background(
+ MaterialTheme.colorScheme.surfaceVariant
+ )
+ .padding(8.dp),
+ )
+ Button(
+ onClick = {
+ val clip = ClipData.newPlainText("text", PUBLIC_KEY)
+ clipboardManager.setPrimaryClip(clip)
+ },
+ colors = ButtonDefaults.textButtonColors(),
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Text(stringResource(R.string.ui_about_gpg_key_copy))
+ }
+ }
+}
diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/AboutTile.kt b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/AboutTile.kt
new file mode 100644
index 0000000..857584d
--- /dev/null
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/AboutTile.kt
@@ -0,0 +1,69 @@
+package app.myzel394.alibi.ui.components.SettingsScreen.atoms
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ChevronRight
+import androidx.compose.material.icons.filled.Info
+import androidx.compose.material.icons.filled.Notifications
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import app.myzel394.alibi.R
+import app.myzel394.alibi.dataStore
+import app.myzel394.alibi.db.AppSettings
+import app.myzel394.alibi.ui.components.atoms.SettingsTile
+import app.myzel394.alibi.ui.enums.Screen
+
+@Composable
+fun AboutTile(
+ navController: NavController,
+) {
+ val label = stringResource(R.string.ui_about_title)
+
+ Row(
+ modifier = Modifier
+ .padding(horizontal = 32.dp, vertical = 48.dp)
+ .fillMaxWidth()
+ .clip(MaterialTheme.shapes.medium)
+ .semantics {
+ contentDescription = label
+ }
+ .clickable {
+ navController.navigate(Screen.About.route)
+ }
+ .background(MaterialTheme.colorScheme.surfaceVariant)
+ .padding(16.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+ Icon(
+ Icons.Default.Info,
+ contentDescription = null,
+ )
+ Text(
+ text = label,
+ )
+ }
+ Icon(
+ Icons.Default.ChevronRight,
+ contentDescription = null,
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/app/myzel394/alibi/ui/enums/Screen.kt b/app/src/main/java/app/myzel394/alibi/ui/enums/Screen.kt
index 218bde3..d8ba5a8 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/enums/Screen.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/enums/Screen.kt
@@ -5,6 +5,7 @@ sealed class Screen(val route: String) {
data object Settings : Screen("settings")
data object Welcome : Screen("welcome")
data object CustomRecordingNotifications : Screen("custom-recording-notifications")
+ data object About : Screen("about")
fun withArgs(vararg args: String): String {
return buildString {
diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/AboutScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/AboutScreen.kt
new file mode 100644
index 0000000..8082fe5
--- /dev/null
+++ b/app/src/main/java/app/myzel394/alibi/ui/screens/AboutScreen.kt
@@ -0,0 +1,206 @@
+package app.myzel394.alibi.ui.screens
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+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
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.OpenInNew
+import androidx.compose.material3.ButtonDefaults
+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.material3.TopAppBarDefaults
+import androidx.compose.material3.rememberTopAppBarState
+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.ColorFilter
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.platform.LocalUriHandler
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import app.myzel394.alibi.R
+import app.myzel394.alibi.BuildConfig
+import app.myzel394.alibi.ui.TRANSLATION_HELP_URL
+import app.myzel394.alibi.ui.REPO_URL
+import app.myzel394.alibi.ui.components.AboutScreen.atoms.DonationsTile
+import app.myzel394.alibi.ui.components.AboutScreen.atoms.GPGKeyOverview
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AboutScreen(
+ navController: NavController,
+) {
+ val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
+ rememberTopAppBarState()
+ )
+ val uriHandler = LocalUriHandler.current
+
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = {
+ Text(stringResource(R.string.ui_about_title))
+ },
+ navigationIcon = {
+ IconButton(onClick = navController::popBackStack) {
+ Icon(
+ Icons.Default.ArrowBack,
+ contentDescription = "Back"
+ )
+ }
+ },
+ scrollBehavior = scrollBehavior,
+ )
+ },
+ modifier = Modifier
+ .nestedScroll(scrollBehavior.nestedScrollConnection)
+ ) { padding ->
+ Column(
+ modifier = Modifier
+ .padding(padding)
+ .padding(horizontal = 32.dp)
+ .verticalScroll(rememberScrollState()),
+ verticalArrangement = Arrangement.spacedBy(48.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Box(
+ modifier = Modifier
+ .clip(CircleShape)
+ .size(200.dp)
+ .background(
+ MaterialTheme.colorScheme.surfaceVariant
+ ),
+ ) {
+ Image(
+ painter = painterResource(R.drawable.launcher_foreground),
+ contentDescription = null,
+ )
+ }
+ Text(
+ text = stringResource(R.string.app_name),
+ style = MaterialTheme.typography.headlineLarge,
+ )
+ Text(
+ text = "Version %s (%s)".format(
+ BuildConfig.VERSION_NAME,
+ BuildConfig.VERSION_CODE.toString()
+ ),
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+ Column(
+ verticalArrangement = Arrangement.spacedBy(24.dp)
+ ) {
+ Text(
+ stringResource(R.string.ui_about_contribute_title),
+ style = MaterialTheme.typography.titleMedium,
+ )
+ Text(
+ stringResource(R.string.ui_about_contribute_message),
+ style = MaterialTheme.typography.titleMedium,
+ )
+
+ val githubLabel = stringResource(R.string.accessibility_open_in_browser, REPO_URL)
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(MaterialTheme.shapes.medium)
+ .semantics {
+ contentDescription = githubLabel
+ }
+ .clickable {
+ uriHandler.openUri(REPO_URL)
+ }
+ .background(
+ MaterialTheme.colorScheme.surfaceVariant
+ )
+ .padding(16.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Image(
+ painter = painterResource(R.drawable.ic_github),
+ colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant),
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize.times(1.2f))
+ )
+ Text(
+ stringResource(R.string.ui_about_contribute_development),
+ fontWeight = FontWeight.Bold,
+ )
+ Icon(
+ Icons.Default.OpenInNew,
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ }
+
+ val crowdinLabel =
+ stringResource(R.string.accessibility_open_in_browser, TRANSLATION_HELP_URL)
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(MaterialTheme.shapes.medium)
+ .semantics {
+ contentDescription = crowdinLabel
+ }
+ .clickable {
+ uriHandler.openUri(TRANSLATION_HELP_URL)
+ }
+ .background(
+ MaterialTheme.colorScheme.surfaceVariant
+ )
+ .padding(16.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Image(
+ painter = painterResource(R.drawable.ic_crowdin),
+ colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant),
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize.times(1.2f))
+ )
+ Text(
+ stringResource(R.string.ui_about_contribute_translation),
+ fontWeight = FontWeight.Bold,
+ )
+ Icon(
+ Icons.Default.OpenInNew,
+ contentDescription = null,
+ modifier = Modifier.size(ButtonDefaults.IconSize)
+ )
+ }
+
+ DonationsTile()
+
+ GPGKeyOverview()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt
index b64a964..0c2e972 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt
@@ -39,6 +39,7 @@ import app.myzel394.alibi.R
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
+import app.myzel394.alibi.ui.components.SettingsScreen.atoms.AboutTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.BitrateTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.CustomNotificationTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.EncoderTile
@@ -147,6 +148,7 @@ fun SettingsScreen(
ForceExactMaxDurationTile()
InAppLanguagePicker()
CustomNotificationTile(navController = navController)
+ AboutTile(navController = navController)
AnimatedVisibility(visible = settings.showAdvancedSettings) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
diff --git a/app/src/main/res/drawable/ic_crowdin.xml b/app/src/main/res/drawable/ic_crowdin.xml
new file mode 100644
index 0000000..8326732
--- /dev/null
+++ b/app/src/main/res/drawable/ic_crowdin.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_github.xml b/app/src/main/res/drawable/ic_github.xml
new file mode 100644
index 0000000..34241ea
--- /dev/null
+++ b/app/src/main/res/drawable/ic_github.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 33e9c64..e3fd669 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -88,4 +88,14 @@
Show Duration
Update notification
This is a preview for your notification. You can edit the title and the message. At the bottom you can find some presets.
+ About Alibi
+ Support Alibi
+ In my free time I develop Alibi and other free open source software. It would mean the world to me if you could help me in any way :)
+ Developing features or fixing bugs
+ Open link in browser: %s
+ Translate Alibi into your language
+ Make a donation
+ You can copy my GPG key here. This key only exists once and I can use it to prove to you that I\'m really who I am. Please save it now so that you can verify my signature later.
+ Copy GPG Key
+ Become a GitHub Sponsor
\ No newline at end of file