diff --git a/app/src/main/java/app/myzel394/alibi/Constants.kt b/app/src/main/java/app/myzel394/alibi/Constants.kt
new file mode 100644
index 0000000..88c029e
--- /dev/null
+++ b/app/src/main/java/app/myzel394/alibi/Constants.kt
@@ -0,0 +1,3 @@
+package app.myzel394.alibi
+
+val SUPPORTED_LOCALES = arrayOf("en-US", "zh-CN")
\ No newline at end of file
diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/InAppLanguagePicker.kt b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/InAppLanguagePicker.kt
new file mode 100644
index 0000000..c7d4714
--- /dev/null
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/InAppLanguagePicker.kt
@@ -0,0 +1,101 @@
+package app.myzel394.alibi.ui.components.SettingsScreen.atoms
+
+import androidx.appcompat.app.AppCompatDelegate
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AudioFile
+import androidx.compose.material.icons.filled.CheckCircle
+import androidx.compose.material.icons.filled.ChevronRight
+import androidx.compose.material.icons.filled.Circle
+import androidx.compose.material.icons.filled.Translate
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.core.os.LocaleListCompat
+import app.myzel394.alibi.R
+import app.myzel394.alibi.SUPPORTED_LOCALES
+import app.myzel394.alibi.db.AudioRecorderSettings
+import app.myzel394.alibi.ui.components.atoms.SettingsTile
+import app.myzel394.alibi.ui.utils.IconResource
+import com.maxkeppeker.sheets.core.models.base.ButtonStyle
+import com.maxkeppeker.sheets.core.models.base.Header
+import com.maxkeppeker.sheets.core.models.base.IconSource
+import com.maxkeppeker.sheets.core.models.base.SelectionButton
+import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
+import com.maxkeppeler.sheets.list.ListDialog
+import com.maxkeppeler.sheets.list.models.ListOption
+import com.maxkeppeler.sheets.list.models.ListSelection
+import java.util.Locale
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun InAppLanguagePicker() {
+ val showDialog = rememberUseCaseState()
+ val locales = Locale.getAvailableLocales().filter {
+ val locale = it.language +
+ (if (it.country.isNotBlank()) "-${it.country}" else "") +
+ (if (it.variant.isNotBlank()) "-${it.variant}" else "")
+
+ SUPPORTED_LOCALES.contains(locale)
+ }
+
+ ListDialog(
+ state = showDialog,
+ header = Header.Default(
+ title = stringResource(R.string.ui_settings_language_title),
+ icon = IconSource(
+ painter = IconResource.fromImageVector(Icons.Default.Translate).asPainterResource(),
+ contentDescription = null,
+ )
+ ),
+ selection = ListSelection.Single(
+ showRadioButtons = true,
+ options = IntRange(0, locales.size - 1).map {index ->
+ val locale = locales[index]!!
+
+ ListOption(
+ titleText = locale.displayName,
+ subtitleText = locale.getDisplayName(Locale.ENGLISH),
+ )
+ }.toList(),
+ positiveButton = SelectionButton(
+ icon = IconSource(
+ painter = IconResource.fromImageVector(Icons.Default.CheckCircle).asPainterResource(),
+ contentDescription = null,
+ ),
+ text = stringResource(android.R.string.ok),
+ type = ButtonStyle.TEXT,
+ )
+ ) {index, _ ->
+ AppCompatDelegate.setApplicationLocales(
+ LocaleListCompat.forLanguageTags(
+ locales[index]!!.toLanguageTag(),
+ ),
+ )
+ },
+ )
+ SettingsTile(
+ firstModifier = Modifier
+ .fillMaxHeight()
+ .clickable {
+ showDialog.show()
+ },
+ title = stringResource(R.string.ui_settings_language_title),
+ leading = {
+ Icon(
+ Icons.Default.Translate,
+ contentDescription = null,
+ )
+ },
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/atoms/SettingsTile.kt b/app/src/main/java/app/myzel394/alibi/ui/components/atoms/SettingsTile.kt
index 7444d45..729995f 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/components/atoms/SettingsTile.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/atoms/SettingsTile.kt
@@ -17,6 +17,8 @@ import androidx.compose.ui.unit.dp
@Composable
fun SettingsTile(
+ modifier: Modifier = Modifier,
+ firstModifier: Modifier = Modifier,
title: String,
description: String? = null,
leading: @Composable () -> Unit = {},
@@ -27,8 +29,10 @@ fun SettingsTile(
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
+ .then(firstModifier)
.fillMaxWidth()
.padding(16.dp)
+ .then(modifier),
) {
leading()
Spacer(modifier = Modifier.width(16.dp))
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 463c4b7..a1db378 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
@@ -38,6 +38,7 @@ import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.BitrateTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.EncoderTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ForceExactMaxDurationTile
+import app.myzel394.alibi.ui.components.SettingsScreen.atoms.InAppLanguagePicker
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.IntervalDurationTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.MaxDurationTile
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.OutputFormatTile
@@ -120,6 +121,7 @@ fun SettingsScreen(
MaxDurationTile()
IntervalDurationTile()
ForceExactMaxDurationTile()
+ InAppLanguagePicker()
AnimatedVisibility(visible = settings.showAdvancedSettings) {
Column {
Divider(
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 303afad..15ab739 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -62,4 +62,6 @@
Audio Recording has been paused
An error occured
Alibi encountered an error during recording. Would you like to try saving the recording?
+ Language
+ Change
\ No newline at end of file