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.