Improvements to the Settings Interface

This commit is contained in:
Vitor Pamplona
2023-08-14 21:25:12 -04:00
parent decd6ef627
commit 3a8a50006d
6 changed files with 172 additions and 140 deletions
@@ -35,7 +35,7 @@ import kotlinx.collections.immutable.ImmutableList
@Composable
fun TextSpinner(
label: String,
label: String?,
placeholder: String,
options: ImmutableList<String>,
explainers: ImmutableList<String>? = null,
@@ -54,7 +54,7 @@ fun TextSpinner(
value = currentText,
onValueChange = {},
readOnly = true,
label = { Text(label) },
label = { label?.let { Text(it) } },
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester)
@@ -44,10 +44,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavHostController
import coil.Coil
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Account
@@ -108,7 +106,8 @@ fun AppTopBar(
navEntryState: State<NavBackStackEntry?>,
scaffoldState: ScaffoldState,
accountViewModel: AccountViewModel,
nav: (String) -> Unit
nav: (String) -> Unit,
navPopBack: () -> Unit
) {
val currentRoute by remember(navEntryState.value) {
derivedStateOf {
@@ -122,7 +121,7 @@ fun AppTopBar(
}
}
RenderTopRouteBar(currentRoute, id, followLists, scaffoldState, accountViewModel, nav)
RenderTopRouteBar(currentRoute, id, followLists, scaffoldState, accountViewModel, nav, navPopBack)
}
@Composable
@@ -132,14 +131,15 @@ private fun RenderTopRouteBar(
followLists: FollowListViewModel,
scaffoldState: ScaffoldState,
accountViewModel: AccountViewModel,
nav: (String) -> Unit
nav: (String) -> Unit,
navPopBack: () -> Unit
) {
when (currentRoute) {
// Route.Profile.route -> TopBarWithBackButton(nav)
Route.Home.base -> HomeTopBar(followLists, scaffoldState, accountViewModel, nav)
Route.Video.base -> StoriesTopBar(followLists, scaffoldState, accountViewModel, nav)
Route.Discover.base -> DiscoveryTopBar(followLists, scaffoldState, accountViewModel, nav)
Route.Notification.base -> NotificationTopBar(followLists, scaffoldState, accountViewModel, nav)
Route.Settings.base -> TopBarWithBackButton(stringResource(id = R.string.application_preferences), navPopBack)
else -> {
if (id != null) {
when (currentRoute) {
@@ -488,24 +488,23 @@ fun SimpleTextSpinner(
}
@Composable
fun TopBarWithBackButton(navController: NavHostController) {
fun TopBarWithBackButton(caption: String, popBack: () -> Unit) {
Column() {
TopAppBar(
elevation = 0.dp,
backgroundColor = Color(0xFFFFFF),
title = {},
title = {
Text(caption)
},
navigationIcon = {
IconButton(
onClick = {
navController.popBackStack()
},
onClick = popBack,
modifier = Modifier
) {
Icon(
imageVector = Icons.Filled.ArrowBack,
null,
modifier = Modifier.size(28.dp),
tint = MaterialTheme.colors.primary
imageVector = Icons.Default.ArrowBack,
contentDescription = stringResource(R.string.back),
tint = MaterialTheme.colors.onSurface
)
}
},
@@ -95,6 +95,13 @@ fun MainScreen(
}
}
val navPopBack = remember(navController) {
{
navController.popBackStack()
Unit
}
}
val followLists: FollowListViewModel = viewModel(
key = accountViewModel.userProfile().pubkeyHex + "FollowListViewModel",
factory = FollowListViewModel.Factory(accountViewModel.account)
@@ -201,7 +208,7 @@ fun MainScreen(
AppBottomBar(accountViewModel, navState, navBottomRow)
},
topBar = {
AppTopBar(followLists, navState, scaffoldState, accountViewModel, nav = nav)
AppTopBar(followLists, navState, scaffoldState, accountViewModel, nav = nav, navPopBack)
},
drawerContent = {
DrawerContent(nav, scaffoldState, sheetState, accountViewModel)
@@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -15,6 +16,7 @@ import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ExposedDropdownMenuBox
import androidx.compose.material.ExposedDropdownMenuDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
@@ -26,10 +28,12 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.os.LocaleListCompat
@@ -39,7 +43,10 @@ import com.vitorpamplona.amethyst.model.ConnectivityType
import com.vitorpamplona.amethyst.model.parseConnectivityType
import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.StdPadding
import com.vitorpamplona.amethyst.ui.theme.HalfVertSpacer
import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.Size20dp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.DelicateCoroutinesApi
@@ -108,16 +115,18 @@ fun SettingsScreen(
stringResource(ConnectivityType.WIFI_ONLY.reourceId),
stringResource(ConnectivityType.NEVER.reourceId)
)
val settings = accountViewModel.account.settings
val index = settings.automaticallyShowImages.screenCode
val videoIndex = settings.automaticallyStartPlayback.screenCode
val linkIndex = settings.automaticallyShowUrlPreview.screenCode
val themeItens = persistentListOf(
stringResource(R.string.system),
stringResource(R.string.light),
stringResource(R.string.dark)
)
val settings = accountViewModel.account.settings
val showImagesIndex = settings.automaticallyShowImages.screenCode
val videoIndex = settings.automaticallyStartPlayback.screenCode
val linkIndex = settings.automaticallyShowUrlPreview.screenCode
val themeIndex = themeViewModel.theme.value ?: 0
val context = LocalContext.current
@@ -127,123 +136,132 @@ fun SettingsScreen(
val languageIndex = getLanguageIndex(languageEntries)
Column(
StdPadding
Modifier
.padding(top = Size10dp, start = Size20dp, end = Size20dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
Section(stringResource(R.string.application_preferences))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
SettingsRow(
R.string.language,
R.string.language_description,
languageList,
languageIndex
) {
TextSpinner(
label = stringResource(R.string.language),
placeholder = languageList[languageIndex],
options = languageList,
onSelect = {
GlobalScope.launch(Dispatchers.Main) {
val job = scope.launch(Dispatchers.IO) {
val locale = languageEntries[languageList[it]]
accountViewModel.account.settings.preferredLanguage = locale
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
job.join()
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageEntries[languageList[it]])
AppCompatDelegate.setApplicationLocales(appLocale)
}
},
modifier = Modifier
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
.weight(1f)
GlobalScope.launch(Dispatchers.Main) {
val job = scope.launch(Dispatchers.IO) {
val locale = languageEntries[languageList[it]]
accountViewModel.account.settings.preferredLanguage = locale
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
job.join()
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageEntries[languageList[it]])
AppCompatDelegate.setApplicationLocales(appLocale)
}
}
Spacer(modifier = HalfVertSpacer)
SettingsRow(
R.string.theme,
R.string.theme_description,
themeItens,
themeIndex
) {
themeViewModel.onChange(it)
scope.launch(Dispatchers.IO) {
LocalPreferences.updateTheme(it)
}
}
Spacer(modifier = HalfVertSpacer)
SettingsRow(
R.string.automatically_load_images_gifs,
R.string.automatically_load_images_gifs_description,
selectedItens,
showImagesIndex
) {
val automaticallyShowImages = parseConnectivityType(it)
scope.launch(Dispatchers.IO) {
accountViewModel.updateAutomaticallyShowImages(automaticallyShowImages)
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
}
Spacer(modifier = HalfVertSpacer)
SettingsRow(
R.string.automatically_play_videos,
R.string.automatically_play_videos_description,
selectedItens,
videoIndex
) {
val automaticallyStartPlayback = parseConnectivityType(it)
scope.launch(Dispatchers.IO) {
accountViewModel.updateAutomaticallyStartPlayback(automaticallyStartPlayback)
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
}
Spacer(modifier = HalfVertSpacer)
SettingsRow(
R.string.automatically_show_url_preview,
R.string.automatically_show_url_preview_description,
selectedItens,
linkIndex
) {
val automaticallyShowUrlPreview = parseConnectivityType(it)
scope.launch(Dispatchers.IO) {
accountViewModel.updateAutomaticallyShowUrlPreview(automaticallyShowUrlPreview)
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
}
}
}
@Composable
fun SettingsRow(
name: Int,
description: Int,
selectedItens: ImmutableList<String>,
selectedIndex: Int,
onSelect: (Int) -> Unit
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.weight(2.0f),
verticalArrangement = Arrangement.spacedBy(3.dp)
) {
Text(
text = stringResource(name),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
text = stringResource(description),
style = MaterialTheme.typography.caption,
color = Color.Gray,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
TextSpinner(
label = stringResource(R.string.theme),
placeholder = themeItens[themeIndex],
options = themeItens,
onSelect = {
themeViewModel.onChange(it)
scope.launch(Dispatchers.IO) {
LocalPreferences.updateTheme(it)
}
},
modifier = Modifier
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
.weight(1f)
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
TextSpinner(
label = stringResource(R.string.automatically_load_images_gifs),
placeholder = selectedItens[index],
options = selectedItens,
onSelect = {
val automaticallyShowImages = parseConnectivityType(it)
scope.launch(Dispatchers.IO) {
accountViewModel.updateAutomaticallyShowImages(automaticallyShowImages)
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
},
modifier = Modifier
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
.weight(1f)
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
TextSpinner(
label = stringResource(R.string.automatically_play_videos),
placeholder = selectedItens[videoIndex],
options = selectedItens,
onSelect = {
val automaticallyStartPlayback = parseConnectivityType(it)
scope.launch(Dispatchers.IO) {
accountViewModel.updateAutomaticallyStartPlayback(automaticallyStartPlayback)
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
},
modifier = Modifier
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
.weight(1f)
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
TextSpinner(
label = stringResource(R.string.automatically_show_url_preview),
placeholder = selectedItens[linkIndex],
options = selectedItens,
onSelect = {
val automaticallyShowUrlPreview = parseConnectivityType(it)
scope.launch(Dispatchers.IO) {
accountViewModel.updateAutomaticallyShowUrlPreview(automaticallyShowUrlPreview)
LocalPreferences.saveToEncryptedStorage(accountViewModel.account)
}
},
modifier = Modifier
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
.weight(1f)
)
}
TextSpinner(
label = "",
placeholder = selectedItens[selectedIndex],
options = selectedItens,
onSelect = onSelect,
modifier = Modifier
.windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp))
.weight(1f)
)
}
}
+12 -4
View File
@@ -493,12 +493,12 @@
<string name="system">System</string>
<string name="light">Light</string>
<string name="dark">Dark</string>
<string name="application_preferences">Application preferences</string>
<string name="application_preferences">Application Preferences</string>
<string name="language">Language</string>
<string name="theme">Theme</string>
<string name="automatically_load_images_gifs">Automatically load images/gifs</string>
<string name="automatically_play_videos">Automatically play videos</string>
<string name="automatically_show_url_preview">Automatically show url preview</string>
<string name="automatically_load_images_gifs">Image Preview</string>
<string name="automatically_play_videos">Video Playback</string>
<string name="automatically_show_url_preview">URL Preview</string>
<string name="load_image">Load Image</string>
<string name="spamming_users">Spammers</string>
@@ -536,4 +536,12 @@
<string name="messages_group_descriptor">Members of this group</string>
<string name="messages_new_subject_message">Explanation to members</string>
<string name="messages_new_subject_message_placeholder">Changing the name for the new goals.</string>
<string name="language_description">For the App\'s Interface</string>
<string name="theme_description">Dark, Light or System theme</string>
<string name="automatically_load_images_gifs_description">Automatically load images and GIFs</string>
<string name="automatically_play_videos_description">Automatically plays videos and GIFs</string>
<string name="automatically_show_url_preview_description">Show URL previews</string>
<string name="load_image_description">When to load images</string>
</resources>
+3 -3
View File
@@ -4,10 +4,13 @@
<locale android:name="cs"/>
<locale android:name="de"/>
<locale android:name="eo"/>
<locale android:name="en"/>
<locale android:name="en-GB"/>
<locale android:name="es"/>
<locale android:name="fa"/>
<locale android:name="fr"/>
<locale android:name="hu"/>
<locale android:name="ja"/>
<locale android:name="nl"/>
<locale android:name="pt-BR"/>
<locale android:name="ru"/>
@@ -18,7 +21,4 @@
<locale android:name="zh"/>
<locale android:name="zh-HK"/>
<locale android:name="zh-TW"/>
<locale android:name="en"/>
<locale android:name="en-GB"/>
<locale android:name="ja"/>
</locale-config>