@@ -18,8 +18,10 @@
|
||||
package org.nsh07.pomodoro.ui.settingsScreen
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.LocaleManager
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
@@ -46,8 +48,10 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -68,6 +72,7 @@ import org.nsh07.pomodoro.service.TimerService
|
||||
import org.nsh07.pomodoro.ui.Screen
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.components.AboutCard
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.components.ClickableListItem
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.components.LocaleBottomSheet
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.components.PlusPromo
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.screens.AlarmSettings
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.screens.AppearanceSettings
|
||||
@@ -76,6 +81,7 @@ import org.nsh07.pomodoro.ui.settingsScreen.viewModel.PreferencesState
|
||||
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
|
||||
import org.nsh07.pomodoro.ui.settingsScreens
|
||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||
import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
|
||||
import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
|
||||
|
||||
|
||||
@@ -182,6 +188,22 @@ private fun SettingsScreen(
|
||||
val context = LocalContext.current
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
|
||||
val currentLocales =
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
context
|
||||
.getSystemService(LocaleManager::class.java)
|
||||
.applicationLocales
|
||||
} else null
|
||||
val currentLocalesSize = currentLocales?.size() ?: 0
|
||||
|
||||
var showLocaleSheet by remember { mutableStateOf(false) }
|
||||
|
||||
if (showLocaleSheet && currentLocales != null)
|
||||
LocaleBottomSheet(
|
||||
currentLocales = currentLocales,
|
||||
setShowSheet = { showLocaleSheet = it }
|
||||
)
|
||||
|
||||
NavDisplay(
|
||||
backStack = backStack,
|
||||
onBack = backStack::removeLastOrNull,
|
||||
@@ -266,6 +288,30 @@ private fun SettingsScreen(
|
||||
}
|
||||
|
||||
item { Spacer(Modifier.height(12.dp)) }
|
||||
|
||||
if (currentLocales != null)
|
||||
item {
|
||||
ClickableListItem(
|
||||
leadingContent = {
|
||||
Icon(
|
||||
painterResource(R.drawable.language),
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
headlineContent = { Text(stringResource(R.string.language)) },
|
||||
supportingContent = {
|
||||
Text(
|
||||
if (currentLocalesSize > 0) currentLocales.get(0).displayName
|
||||
else stringResource(R.string.system_default)
|
||||
)
|
||||
},
|
||||
colors = listItemColors,
|
||||
items = 1,
|
||||
index = 0
|
||||
) { showLocaleSheet = true }
|
||||
}
|
||||
|
||||
item { Spacer(Modifier.height(12.dp)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,11 +129,11 @@ fun AboutCard(
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.bmc),
|
||||
contentDescription = "Buy me a coffee",
|
||||
contentDescription = null,
|
||||
modifier = Modifier.height(24.dp)
|
||||
)
|
||||
|
||||
Text(text = "Buy me a coffee")
|
||||
Text(text = stringResource(R.string.bmc))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,11 +147,11 @@ fun AboutCard(
|
||||
) {
|
||||
Icon(
|
||||
painterResource(R.drawable.play_store),
|
||||
contentDescription = "Rate on Google Play",
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
|
||||
Text(text = "Rate on Google Play")
|
||||
Text(text = stringResource(R.string.rate_on_google_play))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Nishant Mishra
|
||||
*
|
||||
* This file is part of Tomato - a minimalist pomodoro timer for Android.
|
||||
*
|
||||
* Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tomato.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.nsh07.pomodoro.ui.settingsScreen.components
|
||||
|
||||
import android.app.LocaleConfig
|
||||
import android.app.LocaleManager
|
||||
import android.os.Build
|
||||
import android.os.LocaleList
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
import androidx.compose.material3.MaterialTheme.shapes
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
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.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import org.nsh07.pomodoro.R
|
||||
import org.nsh07.pomodoro.ui.theme.CustomColors.listItemColors
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.bottomListItemShape
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.middleListItemShape
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun LocaleBottomSheet(
|
||||
currentLocales: LocaleList,
|
||||
setShowSheet: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val supportedLocales = remember {
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
LocaleConfig(context).supportedLocales
|
||||
} else null
|
||||
}
|
||||
val supportedLocalesSize = supportedLocales?.size() ?: 0
|
||||
|
||||
val supportedLocalesList: List<AppLocale>? = remember {
|
||||
if (supportedLocales != null) {
|
||||
buildList {
|
||||
for (i in 0 until supportedLocalesSize) {
|
||||
add(AppLocale(supportedLocales.get(i), supportedLocales.get(i).displayName))
|
||||
}
|
||||
sortWith(compareBy { it.name })
|
||||
}
|
||||
} else null
|
||||
}
|
||||
|
||||
val bottomSheetState = rememberModalBottomSheetState()
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { setShowSheet(false) },
|
||||
sheetState = bottomSheetState,
|
||||
modifier = modifier
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = stringResource(R.string.choose_language),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
if (supportedLocalesList != null) {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
state = listState,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.clip(shapes.largeIncreased)
|
||||
) {
|
||||
item {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(stringResource(R.string.system_default))
|
||||
},
|
||||
trailingContent = {
|
||||
if (currentLocales.isEmpty)
|
||||
Icon(
|
||||
painterResource(R.drawable.check),
|
||||
contentDescription = stringResource(R.string.selected)
|
||||
)
|
||||
},
|
||||
colors =
|
||||
if (currentLocales.isEmpty)
|
||||
ListItemDefaults.colors(
|
||||
containerColor = colorScheme.primaryContainer.copy(
|
||||
0.3f
|
||||
)
|
||||
)
|
||||
else listItemColors,
|
||||
modifier = Modifier
|
||||
.clip(if (currentLocales.isEmpty) CircleShape else shapes.largeIncreased)
|
||||
.clickable(
|
||||
onClick = {
|
||||
scope
|
||||
.launch { bottomSheetState.hide() }
|
||||
.invokeOnCompletion {
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
context
|
||||
.getSystemService(LocaleManager::class.java)
|
||||
.applicationLocales = LocaleList()
|
||||
}
|
||||
setShowSheet(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
item {
|
||||
Spacer(Modifier.height(12.dp))
|
||||
}
|
||||
itemsIndexed(
|
||||
supportedLocalesList,
|
||||
key = { _: Int, it: AppLocale -> it.name }
|
||||
) { index, it ->
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(it.name)
|
||||
},
|
||||
trailingContent = {
|
||||
if (!currentLocales.isEmpty && it.locale == currentLocales.get(0))
|
||||
Icon(
|
||||
painterResource(R.drawable.check),
|
||||
tint = colorScheme.primary,
|
||||
contentDescription = stringResource(R.string.selected)
|
||||
)
|
||||
},
|
||||
colors =
|
||||
if (!currentLocales.isEmpty && it.locale == currentLocales.get(0))
|
||||
ListItemDefaults.colors(containerColor = colorScheme.primaryContainer)
|
||||
else listItemColors,
|
||||
modifier = Modifier
|
||||
.clip(
|
||||
if (!currentLocales.isEmpty && it.locale == currentLocales.get(0))
|
||||
CircleShape
|
||||
else when (index) {
|
||||
0 -> topListItemShape
|
||||
supportedLocalesSize - 1 -> bottomListItemShape
|
||||
else -> middleListItemShape
|
||||
}
|
||||
)
|
||||
.clickable(
|
||||
onClick = {
|
||||
scope
|
||||
.launch { bottomSheetState.hide() }
|
||||
.invokeOnCompletion { _ ->
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
context.getSystemService(LocaleManager::class.java)
|
||||
.applicationLocales =
|
||||
LocaleList(it.locale)
|
||||
}
|
||||
setShowSheet(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class AppLocale(
|
||||
val locale: Locale,
|
||||
val name: String
|
||||
)
|
||||
Reference in New Issue
Block a user