From 5875f3ded780ed6cac05425c42eba732422a34f3 Mon Sep 17 00:00:00 2001 From: Infi Date: Wed, 6 Mar 2024 21:28:03 +0100 Subject: [PATCH] feat: add chat settings and quick reply options (for future use) Signed-off-by: Infi --- .../chat/revolt/activities/MainActivity.kt | 2 + .../java/chat/revolt/api/schemas/Settings.kt | 5 + .../chat/revolt/api/settings/GlobalState.kt | 13 ++- .../revolt/api/settings/SyncedSettings.kt | 8 +- .../revolt/components/generic/RadioItem.kt | 48 ++++++++ .../screens/settings/ChatSettingsScreen.kt | 105 ++++++++++++++++++ .../revolt/screens/settings/SettingsScreen.kt | 19 ++++ .../res/drawable/ic_message_text_24dp.xml | 9 ++ app/src/main/res/values/strings.xml | 6 + 9 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/chat/revolt/components/generic/RadioItem.kt create mode 100644 app/src/main/java/chat/revolt/screens/settings/ChatSettingsScreen.kt create mode 100644 app/src/main/res/drawable/ic_message_text_24dp.xml diff --git a/app/src/main/java/chat/revolt/activities/MainActivity.kt b/app/src/main/java/chat/revolt/activities/MainActivity.kt index c06d0da3..33171622 100644 --- a/app/src/main/java/chat/revolt/activities/MainActivity.kt +++ b/app/src/main/java/chat/revolt/activities/MainActivity.kt @@ -63,6 +63,7 @@ import chat.revolt.screens.register.RegisterVerifyScreen import chat.revolt.screens.services.DiscoverScreen import chat.revolt.screens.settings.AppearanceSettingsScreen import chat.revolt.screens.settings.ChangelogsSettingsScreen +import chat.revolt.screens.settings.ChatSettingsScreen import chat.revolt.screens.settings.DebugSettingsScreen import chat.revolt.screens.settings.ProfileSettingsScreen import chat.revolt.screens.settings.SessionSettingsScreen @@ -377,6 +378,7 @@ fun AppEntrypoint( composable("settings/profile") { ProfileSettingsScreen(navController) } composable("settings/sessions") { SessionSettingsScreen(navController) } composable("settings/appearance") { AppearanceSettingsScreen(navController) } + composable("settings/chat") { ChatSettingsScreen(navController) } composable("settings/debug") { DebugSettingsScreen(navController) } composable("settings/changelogs") { ChangelogsSettingsScreen(navController) } diff --git a/app/src/main/java/chat/revolt/api/schemas/Settings.kt b/app/src/main/java/chat/revolt/api/schemas/Settings.kt index b465259f..f3c18595 100644 --- a/app/src/main/java/chat/revolt/api/schemas/Settings.kt +++ b/app/src/main/java/chat/revolt/api/schemas/Settings.kt @@ -20,4 +20,9 @@ data class AndroidSpecificSettings( * Map of `primary, onPrimary, primaryContainer, onPrimaryContainer, inversePrimary, secondary, onSecondary, secondaryContainer, onSecondaryContainer, tertiary, onTertiary, tertiaryContainer, onTertiaryContainer, background, onBackground, surface, onSurface, surfaceVariant, onSurfaceVariant, surfaceTint, inverseSurface, inverseOnSurface, error, onError, errorContainer, onErrorContainer, outline, outlineVariant, scrim` to int colours. */ var colourOverrides: OverridableColourScheme? = null, + /** + * Message reply style. + * Can be one of `{ None, SwipeFromEnd, DoubleTap }` + */ + var messageReplyStyle: String? = null, ) diff --git a/app/src/main/java/chat/revolt/api/settings/GlobalState.kt b/app/src/main/java/chat/revolt/api/settings/GlobalState.kt index 1777e90f..044108c1 100644 --- a/app/src/main/java/chat/revolt/api/settings/GlobalState.kt +++ b/app/src/main/java/chat/revolt/api/settings/GlobalState.kt @@ -6,14 +6,25 @@ import androidx.compose.runtime.setValue import chat.revolt.ui.theme.Theme import chat.revolt.ui.theme.getDefaultTheme +enum class MessageReplyStyle { + None, + SwipeFromEnd, + DoubleTap +} + object GlobalState { var theme by mutableStateOf(getDefaultTheme()) + var messageReplyStyle by mutableStateOf(MessageReplyStyle.SwipeFromEnd) fun hydrateWithSettings(settings: SyncedSettings) { - settings.android.theme?.let { this.theme = Theme.valueOf(it) } + this.theme = settings.android.theme?.let { Theme.valueOf(it) } ?: getDefaultTheme() + this.messageReplyStyle = + settings.android.messageReplyStyle?.let { MessageReplyStyle.valueOf(it) } + ?: MessageReplyStyle.SwipeFromEnd } fun reset() { theme = getDefaultTheme() + messageReplyStyle = MessageReplyStyle.SwipeFromEnd } } diff --git a/app/src/main/java/chat/revolt/api/settings/SyncedSettings.kt b/app/src/main/java/chat/revolt/api/settings/SyncedSettings.kt index f14f19c5..3727ff5f 100644 --- a/app/src/main/java/chat/revolt/api/settings/SyncedSettings.kt +++ b/app/src/main/java/chat/revolt/api/settings/SyncedSettings.kt @@ -10,7 +10,13 @@ import chat.revolt.api.schemas.OrderingSettings object SyncedSettings { private val _ordering = mutableStateOf(OrderingSettings()) - private val _android = mutableStateOf(AndroidSpecificSettings("None")) + private val _android = mutableStateOf( + AndroidSpecificSettings( + theme = "None", + colourOverrides = null, + messageReplyStyle = "None" + ) + ) val ordering: OrderingSettings get() = _ordering.value diff --git a/app/src/main/java/chat/revolt/components/generic/RadioItem.kt b/app/src/main/java/chat/revolt/components/generic/RadioItem.kt new file mode 100644 index 00000000..e31b3328 --- /dev/null +++ b/app/src/main/java/chat/revolt/components/generic/RadioItem.kt @@ -0,0 +1,48 @@ +package chat.revolt.components.generic + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.selection.selectable +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.dp + +@Composable +fun RadioItem( + selected: Boolean, + onClick: () -> Unit, + label: @Composable () -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier + .fillMaxWidth() + .height(56.dp) + .selectable( + selected = selected, + onClick = onClick, + role = Role.RadioButton + ) + .padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + RadioButton( + selected = selected, + onClick = null + ) + Spacer(Modifier.width(16.dp)) + CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodyLarge) { + label() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/settings/ChatSettingsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/ChatSettingsScreen.kt new file mode 100644 index 00000000..66af24ee --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/settings/ChatSettingsScreen.kt @@ -0,0 +1,105 @@ +package chat.revolt.screens.settings + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import chat.revolt.R +import chat.revolt.api.settings.GlobalState +import chat.revolt.api.settings.MessageReplyStyle +import chat.revolt.api.settings.SyncedSettings +import chat.revolt.components.generic.ListHeader +import chat.revolt.components.generic.RadioItem +import kotlinx.coroutines.launch + +class ChatSettingsScreenViewModel : ViewModel() { + fun updateMessageReplyStyle(next: MessageReplyStyle) { + viewModelScope.launch { + SyncedSettings.updateAndroid(SyncedSettings.android.copy(messageReplyStyle = next.name)) + GlobalState.messageReplyStyle = next + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChatSettingsScreen( + navController: NavController, + viewModel: ChatSettingsScreenViewModel = viewModel() +) { + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() + + Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + LargeTopAppBar( + scrollBehavior = scrollBehavior, + title = { + Text( + text = stringResource(R.string.settings_chat), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + }, + navigationIcon = { + IconButton(onClick = { + navController.popBackStack() + }) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = stringResource(id = R.string.back) + ) + } + }, + ) + }, + ) { pv -> + Column( + Modifier + .padding(pv) + .imePadding() + ) { + ListHeader { + Text( + text = stringResource(R.string.settings_chat_quick_reply) + ) + } + + Column(Modifier.selectableGroup()) { + RadioItem( + selected = GlobalState.messageReplyStyle == MessageReplyStyle.None, + onClick = { viewModel.updateMessageReplyStyle(MessageReplyStyle.None) }, + label = { Text(text = stringResource(R.string.settings_chat_quick_reply_none)) } + ) + RadioItem( + selected = GlobalState.messageReplyStyle == MessageReplyStyle.SwipeFromEnd, + onClick = { viewModel.updateMessageReplyStyle(MessageReplyStyle.SwipeFromEnd) }, + label = { Text(text = stringResource(R.string.settings_chat_quick_reply_swipe_from_end)) } + ) + RadioItem( + selected = GlobalState.messageReplyStyle == MessageReplyStyle.DoubleTap, + onClick = { viewModel.updateMessageReplyStyle(MessageReplyStyle.DoubleTap) }, + label = { Text(text = stringResource(R.string.settings_chat_quick_reply_double_tap)) } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt index 4fc751ab..14a3b5bf 100644 --- a/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt @@ -178,6 +178,25 @@ fun SettingsScreen( } ) + ListItem( + headlineContent = { + Text( + text = stringResource(id = R.string.settings_chat) + ) + }, + leadingContent = { + Icon( + painter = painterResource(R.drawable.ic_message_text_24dp), + contentDescription = null, + ) + }, + modifier = Modifier + .testTag("settings_view_chat") + .clickable { + navController.navigate("settings/chat") + } + ) + ListHeader { Text(stringResource(R.string.settings_category_miscellaneous)) } diff --git a/app/src/main/res/drawable/ic_message_text_24dp.xml b/app/src/main/res/drawable/ic_message_text_24dp.xml new file mode 100644 index 00000000..79e57d73 --- /dev/null +++ b/app/src/main/res/drawable/ic_message_text_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6612c98d..3285f940 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -536,6 +536,12 @@ Import This file is not a valid colour override file. + Chat + Quick Reply + Long press to reply + Swipe to reply + Double tap to reply + Feedback Join the Revolt server to give feedback or suggestions and report bugs.