From 872889fefdb4ce78bc9ecfd565e4215971edb7ea Mon Sep 17 00:00:00 2001 From: Infi Date: Tue, 27 Dec 2022 03:50:13 +0100 Subject: [PATCH] feat: send messages UI looks neater now --- .../main/java/chat/revolt/api/RevoltAPI.kt | 6 + .../revolt/api/realtime/RealtimeSocket.kt | 8 +- .../java/chat/revolt/api/routes/user/User.kt | 30 ++++ .../java/chat/revolt/api/schemas/Channel.kt | 26 +++- .../java/chat/revolt/api/schemas/Messages.kt | 17 +++ .../main/java/chat/revolt/api/schemas/User.kt | 19 ++- .../chat/revolt/components/chat/Message.kt | 60 ++++++++ .../revolt/components/chat/MessageField.kt | 130 ++++++++++++++++ .../chat/revolt/screens/chat/ChannelScreen.kt | 140 ++++++++++++++++-- .../chat/revolt/screens/chat/HomeScreen.kt | 71 --------- .../chat/revolt/screens/login/LoginScreen.kt | 4 +- .../chat/revolt/screens/login/MfaScreen.kt | 8 +- app/src/main/res/values/strings.xml | 22 +++ 13 files changed, 444 insertions(+), 97 deletions(-) create mode 100644 app/src/main/java/chat/revolt/components/chat/Message.kt create mode 100644 app/src/main/java/chat/revolt/components/chat/MessageField.kt diff --git a/app/src/main/java/chat/revolt/api/RevoltAPI.kt b/app/src/main/java/chat/revolt/api/RevoltAPI.kt index 10aa66f6..ae5ae224 100644 --- a/app/src/main/java/chat/revolt/api/RevoltAPI.kt +++ b/app/src/main/java/chat/revolt/api/RevoltAPI.kt @@ -99,6 +99,12 @@ object RevoltAPI { Log.e("RevoltAPI", "WebSocket error", e) } RealtimeSocket.open = false + + Log.i("RevoltAPI", "Reconnecting in 2.5 seconds...") + Thread.sleep(2500) + runBlocking { + connectWS() + } // FIXME ASAP move this to ChatRouting (whenever that's a thing) and do it properly } } socketThread!!.start() diff --git a/app/src/main/java/chat/revolt/api/realtime/RealtimeSocket.kt b/app/src/main/java/chat/revolt/api/realtime/RealtimeSocket.kt index 125f4505..21caf8cb 100644 --- a/app/src/main/java/chat/revolt/api/realtime/RealtimeSocket.kt +++ b/app/src/main/java/chat/revolt/api/realtime/RealtimeSocket.kt @@ -135,8 +135,12 @@ object RealtimeSocket { "UserUpdate" -> { val userUpdateFrame = RevoltJson.decodeFromString(UserUpdateFrame.serializer(), rawFrame) - // We will genuinely just ignore this frame for now, but it gets really spammy in the logs - // FIXME handle this frame + + val existing = RevoltAPI.userCache[userUpdateFrame.id] + ?: return // if we don't have the user no point in updating it + + RevoltAPI.userCache[userUpdateFrame.id] = + existing.mergeWithPartial(userUpdateFrame.data) } else -> { Log.i("RealtimeSocket", "Unknown frame: $rawFrame") diff --git a/app/src/main/java/chat/revolt/api/routes/user/User.kt b/app/src/main/java/chat/revolt/api/routes/user/User.kt index 48965904..7d0779f4 100644 --- a/app/src/main/java/chat/revolt/api/routes/user/User.kt +++ b/app/src/main/java/chat/revolt/api/routes/user/User.kt @@ -28,4 +28,34 @@ suspend fun fetchSelf(): User { RevoltAPI.selfId = user.id return user +} + +suspend fun fetchUser(id: String): User { + val response = RevoltHttp.get("/users/$id") { + headers.append(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken) + } + .bodyAsText() + + try { + val error = RevoltJson.decodeFromString(RevoltError.serializer(), response) + throw Error(error.type) + } catch (e: SerializationException) { + // Not an error + } + + val user = RevoltJson.decodeFromString(User.serializer(), response) + + RevoltAPI.userCache[user.id!!] = user + + return user +} + +suspend fun getOrFetchUser(id: String): User { + return RevoltAPI.userCache[id] ?: fetchUser(id) +} + +suspend fun addUserIfUnknown(id: String) { + if (RevoltAPI.userCache[id] == null) { + RevoltAPI.userCache[id] = fetchUser(id) + } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/api/schemas/Channel.kt b/app/src/main/java/chat/revolt/api/schemas/Channel.kt index 62ebd241..a6fc5e53 100644 --- a/app/src/main/java/chat/revolt/api/schemas/Channel.kt +++ b/app/src/main/java/chat/revolt/api/schemas/Channel.kt @@ -27,9 +27,10 @@ data class Member( @Serializable data class Channel( - val channelType: ChannelType? = null, @SerialName("_id") val id: String? = null, + @SerialName("channel_type") + val channelType: ChannelType? = null, val user: String? = null, val name: String? = null, val owner: String? = null, @@ -46,7 +47,28 @@ data class Channel( val defaultPermissions: DefaultPermissions? = null, val nsfw: Boolean? = null, val type: String? = null, // this is _only_ used for websocket events! -) +) { + fun mergeWithPartial(partial: Channel): Channel { + return Channel( + channelType = partial.channelType ?: channelType, + id = partial.id ?: id, + user = partial.user ?: user, + name = partial.name ?: name, + owner = partial.owner ?: owner, + description = partial.description ?: description, + recipients = partial.recipients ?: recipients, + icon = partial.icon ?: icon, + lastMessageID = partial.lastMessageID ?: lastMessageID, + active = partial.active ?: active, + permissions = partial.permissions ?: permissions, + server = partial.server ?: server, + rolePermissions = partial.rolePermissions ?: rolePermissions, + defaultPermissions = partial.defaultPermissions ?: defaultPermissions, + nsfw = partial.nsfw ?: nsfw, + type = partial.type ?: type + ) + } +} @Serializable enum class ChannelType(val value: String) { diff --git a/app/src/main/java/chat/revolt/api/schemas/Messages.kt b/app/src/main/java/chat/revolt/api/schemas/Messages.kt index 94987636..8fb87b6a 100644 --- a/app/src/main/java/chat/revolt/api/schemas/Messages.kt +++ b/app/src/main/java/chat/revolt/api/schemas/Messages.kt @@ -23,6 +23,23 @@ data class Message( fun getAuthor(): User? { return author?.let { RevoltAPI.userCache[it] } } + + fun mergeWithPartial(partial: Message): Message { + return Message( + id = partial.id ?: id, + nonce = partial.nonce ?: nonce, + channel = partial.channel ?: channel, + author = partial.author ?: author, + content = partial.content ?: content, + reactions = partial.reactions ?: reactions, + replies = partial.replies ?: replies, + attachments = partial.attachments ?: attachments, + edited = partial.edited ?: edited, + embeds = partial.embeds ?: embeds, + mentions = partial.mentions ?: mentions, + type = partial.type ?: type + ) + } } @Serializable diff --git a/app/src/main/java/chat/revolt/api/schemas/User.kt b/app/src/main/java/chat/revolt/api/schemas/User.kt index 4229a108..ec0a2182 100644 --- a/app/src/main/java/chat/revolt/api/schemas/User.kt +++ b/app/src/main/java/chat/revolt/api/schemas/User.kt @@ -20,7 +20,24 @@ data class User( val bot: Bot? = null, val relationship: String? = null, val online: Boolean? = null -) +) { + fun mergeWithPartial(partial: User): User { + return User( + id = partial.id ?: id, + username = partial.username ?: username, + avatar = partial.avatar ?: avatar, + relations = partial.relations ?: relations, + badges = partial.badges ?: badges, + status = partial.status ?: status, + profile = partial.profile ?: profile, + flags = partial.flags ?: flags, + privileged = partial.privileged ?: privileged, + bot = partial.bot ?: bot, + relationship = partial.relationship ?: relationship, + online = partial.online ?: online + ) + } +} @Serializable data class Bot( diff --git a/app/src/main/java/chat/revolt/components/chat/Message.kt b/app/src/main/java/chat/revolt/components/chat/Message.kt new file mode 100644 index 00000000..a3c92921 --- /dev/null +++ b/app/src/main/java/chat/revolt/components/chat/Message.kt @@ -0,0 +1,60 @@ +package chat.revolt.components.chat + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import chat.revolt.api.REVOLT_BASE +import chat.revolt.api.REVOLT_FILES +import chat.revolt.api.RevoltAPI +import chat.revolt.components.generic.RemoteImage +import chat.revolt.api.schemas.Message as MessageSchema + +@Composable +fun Message( + message: MessageSchema +) { + val author = RevoltAPI.userCache[message.author] ?: return CircularProgressIndicator() + + Row() { + if (author.avatar != null) { + RemoteImage( + url = "$REVOLT_FILES/avatars/${author.avatar.id!!}/user.png", + modifier = Modifier + .size(50.dp) + .clip(CircleShape), + description = "Avatar for ${author.username}" + ) + } else { + RemoteImage( + url = "$REVOLT_BASE/users/${author.id}/default_avatar", + modifier = Modifier + .size(50.dp) + .clip(CircleShape), + description = "Avatar for ${author.username}" + ) + } + + Column(modifier = Modifier.padding(start = 10.dp)) { + author.username?.let { + Text( + text = it, + fontWeight = FontWeight.Bold + ) + } + message.content?.let { + Text( + text = it + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/chat/MessageField.kt b/app/src/main/java/chat/revolt/components/chat/MessageField.kt new file mode 100644 index 00000000..0f4285e6 --- /dev/null +++ b/app/src/main/java/chat/revolt/components/chat/MessageField.kt @@ -0,0 +1,130 @@ +package chat.revolt.components.chat + +import android.widget.Toast +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.KeyboardArrowLeft +import androidx.compose.material.icons.filled.Send +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +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.unit.dp +import chat.revolt.R +import chat.revolt.api.schemas.ChannelType + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MessageField( + showButtons: Boolean, + onToggleButtons: (Boolean) -> Unit, + messageContent: String, + onMessageContentChange: (String) -> Unit, + onSendMessage: () -> Unit, + channelType: ChannelType, + channelName: String, + modifier: Modifier = Modifier, +) { + val context = LocalContext.current + val placeholderResource = when (channelType) { + ChannelType.DirectMessage -> R.string.message_field_placeholder_dm + ChannelType.Group -> R.string.message_field_placeholder_group + ChannelType.TextChannel -> R.string.message_field_placeholder_text + ChannelType.VoiceChannel -> R.string.message_field_placeholder_voice + ChannelType.SavedMessages -> R.string.message_field_placeholder_notes + } + + Row(modifier) { + // Additional buttons (currently adding an attachment) + AnimatedVisibility(visible = showButtons) { + Row(Modifier.weight(1f)) { + ElevatedButton( + onClick = { + Toast.makeText( + context, + "Placeholder for adding an attachment", + Toast.LENGTH_SHORT + ).show() + }, + modifier = Modifier.size(56.dp), + contentPadding = PaddingValues(0.dp), + shape = CircleShape + ) { + Icon( + Icons.Default.Add, + contentDescription = stringResource(id = R.string.add_attachment_alt) + ) + } + } + } + + // The small chevron you see when the buttons are hidden + AnimatedVisibility(visible = !showButtons) { + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.height(56.dp) + ) { + Icon( + Icons.Default.KeyboardArrowLeft, + contentDescription = stringResource(id = R.string.show_more_alt), + modifier = Modifier + .size(24.dp + 8.dp) + .padding(vertical = 4.dp) + .clickable(onClick = { + onToggleButtons(true) + }) + ) + } + } + + TextField( + value = messageContent, + onValueChange = onMessageContentChange, + singleLine = false, + shape = RoundedCornerShape(100), + placeholder = { + Text( + stringResource( + id = placeholderResource, + channelName + ) + ) + }, + colors = TextFieldDefaults.textFieldColors( + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + errorIndicatorColor = Color.Transparent, + placeholderColor = Color.Gray, + ), + modifier = Modifier + .weight(1f) + .padding(horizontal = 8.dp) + ) + + // Send button (visible when text is entered) + AnimatedVisibility(visible = messageContent.isNotBlank()) { + Button( + onClick = onSendMessage, + modifier = Modifier + .size(56.dp), + contentPadding = PaddingValues(0.dp), + shape = CircleShape + ) { + Icon( + Icons.Default.Send, + contentDescription = stringResource(id = R.string.send_alt) + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt b/app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt index f872cf55..f5455a62 100644 --- a/app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt @@ -1,20 +1,33 @@ package chat.revolt.screens.chat import android.util.Log -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.Text +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.hilt.navigation.compose.hiltViewModel +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import chat.revolt.api.RevoltAPI import chat.revolt.api.realtime.RealtimeSocket import chat.revolt.api.realtime.frames.receivable.ChannelStartTypingFrame import chat.revolt.api.realtime.frames.receivable.ChannelStopTypingFrame import chat.revolt.api.realtime.frames.receivable.MessageFrame +import chat.revolt.api.routes.channel.sendMessage +import chat.revolt.api.routes.user.addUserIfUnknown import chat.revolt.api.schemas.Channel -import chat.revolt.api.schemas.Message +import chat.revolt.api.schemas.Message as MessageSchema +import chat.revolt.components.chat.Message +import kotlinx.coroutines.launch +import chat.revolt.R +import chat.revolt.components.chat.MessageField class ChannelScreenViewModel : ViewModel() { private var _channel by mutableStateOf(null) @@ -25,22 +38,59 @@ class ChannelScreenViewModel : ViewModel() { val callbacks: RealtimeSocket.ChannelCallback? get() = _callbacks.value - private var _renderableMessages = mutableStateListOf() - val renderableMessages: List + private var _renderableMessages = mutableStateListOf() + val renderableMessages: List get() = _renderableMessages + private var _typingUsers = mutableStateListOf() + val typingUsers: List + get() = _typingUsers + + private var _messageContent by mutableStateOf("") + val messageContent: String + get() = _messageContent + + fun setMessageContent(content: String) { + _messageContent = content + + if (content.isEmpty()) { + _showButtons = true + } else if (showButtons) { + _showButtons = false + } + } + + private var _showButtons by mutableStateOf(true) + val showButtons: Boolean + get() = _showButtons + + fun setShowButtons(show: Boolean) { + _showButtons = show + } + inner class ChannelScreenCallback : RealtimeSocket.ChannelCallback { override fun onMessage(message: MessageFrame) { - Log.d("ChannelScreen", "onMessage: $message") + viewModelScope.launch { + addUserIfUnknown(message.author!!) + } + _renderableMessages.add(message) } override fun onStartTyping(typing: ChannelStartTypingFrame) { - Log.d("ChannelScreen", "onStartTyping: $typing") + viewModelScope.launch { + addUserIfUnknown(typing.user) + } + + if (!_typingUsers.contains(typing.user)) { + _typingUsers.add(typing.user) + } } override fun onStopTyping(typing: ChannelStopTypingFrame) { - Log.d("ChannelScreen", "onStopTyping: $typing") + if (_typingUsers.contains(typing.user)) { + _typingUsers.remove(typing.user) + } } } @@ -58,15 +108,40 @@ class ChannelScreenViewModel : ViewModel() { registerCallback() } + + fun sendPendingMessage() { + viewModelScope.launch { + sendMessage(channel!!.id!!, messageContent) + } + _messageContent = "" + } + + fun typingMessageResource(): Int { + return when (typingUsers.size) { + 0 -> R.string.typing_blank + 1 -> R.string.typing_one + in 2..4 -> R.string.typing_many + else -> R.string.typing_several + } + } + + fun getTypingUsernames(): String { + return typingUsers.joinToString { + RevoltAPI.userCache[it]?.let { u -> + u.username ?: u.id + } ?: it + } + } } @Composable fun ChannelScreen( navController: NavController, channelId: String, - viewModel: ChannelScreenViewModel = hiltViewModel() + viewModel: ChannelScreenViewModel = viewModel() ) { val channel = viewModel.channel + val scrollState = rememberScrollState() LaunchedEffect(channelId) { viewModel.fetchChannel(channelId) @@ -86,10 +161,45 @@ fun ChannelScreen( } Column { - Text(text = channel.name!!) - - viewModel.renderableMessages.forEach { - Text(text = "[" + it.getAuthor()!!.username + "] " + it.content!!) + Text(text = "#" + channel.name!!) + + Divider() + + // Column nesting is needed to make the vertical scroll work properly + Column(Modifier.weight(1f)) { + Column(Modifier.verticalScroll(scrollState)) { + viewModel.renderableMessages.forEach { + Message(message = it) + } + } + } + + AnimatedVisibility(visible = viewModel.typingUsers.isNotEmpty()) { + Row( + Modifier + .padding(all = 4.dp) + .background(MaterialTheme.colorScheme.surfaceVariant) + ) { + Text( + text = stringResource( + id = viewModel.typingMessageResource(), + viewModel.getTypingUsernames() + ) + ) + } + } + + + channel.channelType?.let { + MessageField( + showButtons = viewModel.showButtons, + onToggleButtons = viewModel::setShowButtons, + messageContent = viewModel.messageContent, + onMessageContentChange = viewModel::setMessageContent, + onSendMessage = viewModel::sendPendingMessage, + channelType = it, + channelName = channel.name + ) } } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt b/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt index b0fef8c0..a9353b4a 100644 --- a/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt @@ -2,15 +2,10 @@ package chat.revolt.screens.chat import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Send import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -19,11 +14,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.NavController -import chat.revolt.api.REVOLT_FILES import chat.revolt.api.RevoltAPI -import chat.revolt.components.generic.FormTextField -import chat.revolt.components.generic.RemoteImage -import chat.revolt.components.screens.home.LinkOnHome import chat.revolt.persistence.KVStorage import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -63,8 +54,6 @@ class HomeScreenViewModel @Inject constructor( @OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeScreen(navController: NavController, viewModel: HomeScreenViewModel = hiltViewModel()) { - val user = RevoltAPI.userCache[RevoltAPI.selfId] - val channelDrawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() @@ -111,67 +100,7 @@ fun HomeScreen(navController: NavController, viewModel: HomeScreenViewModel = hi .padding(horizontal = 15.dp, vertical = 15.dp) .fillMaxWidth(), ) - Column( - modifier = Modifier - .padding(10.dp) - .fillMaxSize() - .weight(1f), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - user?.let { - Row { - RemoteImage( - url = "${REVOLT_FILES}/avatars/${it.avatar?.id}/user.png", - modifier = Modifier - .size(50.dp) - .clip(CircleShape), - description = "Avatar for ${it.username} (placeholder!)" - ) - Column(modifier = Modifier.padding(start = 10.dp)) { - it.username?.let { it1 -> Text(text = it1) } - it.id?.let { it1 -> Text(text = it1) } - } - } - } - - Text( - text = "User cache", - style = MaterialTheme.typography.displaySmall.copy( - fontWeight = FontWeight.Bold, - textAlign = TextAlign.Left, - fontSize = 24.sp - ), - modifier = Modifier - .padding(horizontal = 15.dp, vertical = 15.dp) - .fillMaxWidth(), - ) - Column(modifier = Modifier.height(200.dp)) { - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - ) { - RevoltAPI.userCache.forEach { (_, user) -> - Text(text = user.username ?: user.id ?: "null") - } - } - } - - Column() { - FormTextField( - value = viewModel.messageContent, - label = "Content", - modifier = Modifier.fillMaxWidth(), - onChange = viewModel::setMessageContent - ) - LinkOnHome( - heading = "Send", - icon = Icons.Filled.Send, - onClick = viewModel::sendMessage - ) - } - } Button( onClick = { viewModel.logout() diff --git a/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt b/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt index 08981fb7..f81f4b69 100644 --- a/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt +++ b/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt @@ -72,11 +72,11 @@ class LoginViewModel @Inject constructor( } else { Log.d( "Login", - "No MFA required. Login is complete! We have a session token: ${response.firstUserHints!!.token}" + "No MFA required. Login is complete! We should have a session token" ) try { - RevoltAPI.loginAs(response.firstUserHints.token) + RevoltAPI.loginAs(response.firstUserHints!!.token) kvStorage.set("sessionToken", response.firstUserHints.token) _navigateTo = "home" diff --git a/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt b/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt index 88d94bbf..1577d44c 100644 --- a/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt +++ b/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt @@ -76,11 +76,11 @@ class MfaScreenViewModel @Inject constructor( } else { Log.d( "MFA", - "Successfully authorized TOTP. Token: ${response.firstUserHints!!.token}" + "Successfully authorized with TOTP." ) try { - RevoltAPI.loginAs(response.firstUserHints.token) + RevoltAPI.loginAs(response.firstUserHints!!.token) kvStorage.set("sessionToken", response.firstUserHints.token) _navigateToHome = true @@ -101,11 +101,11 @@ class MfaScreenViewModel @Inject constructor( } else { Log.d( "MFA", - "Successfully authorized recovery code. Token: ${response.firstUserHints!!.token}" + "Successfully authorized with a recovery code." ) try { - RevoltAPI.loginAs(response.firstUserHints.token) + RevoltAPI.loginAs(response.firstUserHints!!.token) kvStorage.set("sessionToken", response.firstUserHints.token) _navigateToHome = true diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb352797..6f5f9597 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,4 +61,26 @@ Gah, you found me! The feature you are trying to access is not ready yet, but we are steadily working on polishing it to perfection.. + + + %1$s is typing… + %1$s are typing… + Several people are typing + + Send + Add attachment + Show more + + Welcome to Revolt\'s in-progress Android experience! + Select a server and channel by swiping from the left. + + %1$s\'s avatar + + Message @%1$s + Message #%1$s + Message #%1$s + Message %1$s + Add a note + + Unknown message, tap to jump \ No newline at end of file