feat: add chat settings and quick reply options

(for future use)

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2024-03-06 21:28:03 +01:00
parent 72e16cf591
commit 5875f3ded7
9 changed files with 213 additions and 2 deletions

View File

@ -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) }

View File

@ -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,
)

View File

@ -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
}
}

View File

@ -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

View File

@ -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()
}
}
}

View File

@ -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)) }
)
}
}
}
}

View File

@ -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))
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M6,9H18V11H6M14,14H6V12H14M18,8H6V6H18" />
</vector>

View File

@ -536,6 +536,12 @@
<string name="settings_appearance_colour_overrides_import">Import</string>
<string name="settings_appearance_colour_overrides_import_error">This file is not a valid colour override file.</string>
<string name="settings_chat">Chat</string>
<string name="settings_chat_quick_reply">Quick Reply</string>
<string name="settings_chat_quick_reply_none">Long press to reply</string>
<string name="settings_chat_quick_reply_swipe_from_end">Swipe to reply</string>
<string name="settings_chat_quick_reply_double_tap">Double tap to reply</string>
<string name="settings_feedback">Feedback</string>
<string name="settings_feedback_description">Join the Revolt server to give feedback or suggestions and report bugs.</string>