Commit 5cf2fe1f authored by Leonardo Aramaki's avatar Leonardo Aramaki

Check if message sender is either a moderator or owner in order to show the reply button

parent f19d5f99
......@@ -6,6 +6,7 @@ import chat.rocket.android.chatroom.adapter.AutoCompleteType
import chat.rocket.android.chatroom.adapter.PEOPLE
import chat.rocket.android.chatroom.adapter.ROOMS
import chat.rocket.android.chatroom.domain.UriInteractor
import chat.rocket.android.chatroom.viewmodel.RoomViewModel
import chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
......@@ -14,8 +15,7 @@ import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.username
import chat.rocket.android.server.domain.GetChatRoomsInteractor
import chat.rocket.android.server.domain.ChatRoomsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.JobSchedulerInteractor
......@@ -59,6 +59,7 @@ import chat.rocket.core.internal.rest.uploadFile
import chat.rocket.core.internal.realtime.subscribeTypingStatus
import chat.rocket.core.internal.realtime.unsubscribe
import chat.rocket.core.internal.rest.*
import chat.rocket.core.model.ChatRoomRole
import chat.rocket.core.model.Command
import chat.rocket.core.model.Message
import chat.rocket.core.model.Myself
......@@ -76,7 +77,7 @@ class ChatRoomPresenter @Inject constructor(
private val view: ChatRoomView,
private val navigator: ChatRoomNavigator,
private val strategy: CancelStrategy,
private val getChatRoomsInteractor: GetChatRoomsInteractor,
private val chatRoomsInteractor: ChatRoomsInteractor,
private val permissions: PermissionsInteractor,
private val uriInteractor: UriInteractor,
private val messagesRepository: MessagesRepository,
......@@ -94,25 +95,36 @@ class ChatRoomPresenter @Inject constructor(
private val manager = factory.create(currentServer)
private val client = manager.client
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
private val currentLoggedUsername = localRepository.username()
private val currentLoggedUsername = userHelper.username()
private val messagesChannel = Channel<Message>()
private var chatRoomId: String? = null
private var chatRoomType: String? = null
private var chatIsBroadcast: Boolean = false
private var chatRoles = emptyList<ChatRoomRole>()
private val stateChannel = Channel<State>()
private var typingStatusSubscriptionId: String? = null
private var lastState = manager.state
private var typingStatusList = arrayListOf<String>()
fun setupChatRoom(roomId: String) {
fun setupChatRoom(roomId: String, roomName: String, roomType: String) {
launchUI(strategy) {
val canPost = permissions.canPostToReadOnlyChannels()
chatIsBroadcast = getChatRoomsInteractor.getById(currentServer, roomId)?.run {
chatRoles = if (roomTypeOf(roomType) !is RoomType.DirectMessage) {
client.chatRoomRoles(roomType = roomTypeOf(roomType), roomName = roomName)
} else emptyList()
val canPost = isOwnerOrMod() || permissions.canPostToReadOnlyChannels()
chatIsBroadcast = chatRoomsInteractor.getById(currentServer, roomId)?.run {
broadcast
} ?: false
view.onRoomUpdated(canPost, chatIsBroadcast)
loadMessages(roomId, roomType)
}
}
private fun isOwnerOrMod(): Boolean {
return chatRoles.firstOrNull { it.user.username == currentLoggedUsername }?.roles?.firstOrNull {
it == "owner" || it == "moderator"
} ?: false == true
}
fun loadMessages(chatRoomId: String, chatRoomType: String, offset: Long = 0) {
......@@ -123,7 +135,8 @@ class ChatRoomPresenter @Inject constructor(
try {
if (offset == 0L) {
val localMessages = messagesRepository.getByRoomId(chatRoomId)
val oldMessages = mapper.map(localMessages, chatIsBroadcast)
val oldMessages = mapper.map(localMessages, RoomViewModel(roles = chatRoles,
isBroadcast = chatIsBroadcast))
if (oldMessages.isNotEmpty()) {
view.showMessages(oldMessages)
loadMissingMessages()
......@@ -163,8 +176,8 @@ class ChatRoomPresenter @Inject constructor(
client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result
}
messagesRepository.saveAll(messages)
val allMessages = mapper.map(messages, chatIsBroadcast)
view.showMessages(allMessages)
view.showMessages(mapper.map(messages, RoomViewModel(roles = chatRoles,
isBroadcast = chatIsBroadcast)))
}
fun sendMessage(chatRoomId: String, text: String, messageId: String?) {
......@@ -200,7 +213,8 @@ class ChatRoomPresenter @Inject constructor(
try {
val message = client.sendMessage(id, chatRoomId, text)
messagesRepository.save(newMessage)
view.showNewMessage(mapper.map(newMessage, chatIsBroadcast))
view.showNewMessage(mapper.map(newMessage, RoomViewModel(
roles = chatRoles, isBroadcast = chatIsBroadcast)))
message
} catch (ex: Exception) {
// Ok, not very beautiful, but the backend sends us a not valid response
......@@ -341,7 +355,8 @@ class ChatRoomPresenter @Inject constructor(
Timber.d("History: $messages")
if (messages.result.isNotEmpty()) {
val models = mapper.map(messages.result, chatIsBroadcast)
val models = mapper.map(messages.result, RoomViewModel(
roles = chatRoles, isBroadcast = chatIsBroadcast))
messagesRepository.saveAll(messages.result)
launchUI(strategy) {
......@@ -415,7 +430,8 @@ class ChatRoomPresenter @Inject constructor(
view.showReplyingAction(
username = getDisplayName(msg.sender),
replyMarkdown = "[ ]($currentServer/$roomType/$room?msg=$id) $mention ",
quotedMessage = mapper.map(message, chatIsBroadcast).last().preview?.message ?: ""
quotedMessage = mapper.map(message, RoomViewModel(roles = chatRoles,
isBroadcast = chatIsBroadcast)).last().preview?.message ?: ""
)
}
}
......@@ -605,7 +621,7 @@ class ChatRoomPresenter @Inject constructor(
fun loadChatRooms() {
launchUI(strategy) {
try {
val chatRooms = getChatRoomsInteractor.getAll(currentServer)
val chatRooms = chatRoomsInteractor.getAll(currentServer)
.filterNot {
it.type is RoomType.DirectMessage || it.type is RoomType.Livechat
}
......@@ -641,7 +657,7 @@ class ChatRoomPresenter @Inject constructor(
fun openDirectMessage(roomName: String, permalink: String) {
launchUI(strategy) {
try {
getChatRoomsInteractor.getByName(currentServer, roomName)?.let {
chatRoomsInteractor.getByName(currentServer, roomName)?.let {
val isDirectMessage = it.type is RoomType.DirectMessage
if (isDirectMessage) {
navigator.toDirectMessage(
......@@ -788,7 +804,8 @@ class ChatRoomPresenter @Inject constructor(
private fun updateMessage(streamedMessage: Message) {
launchUI(strategy) {
val viewModelStreamedMessage = mapper.map(streamedMessage, chatIsBroadcast)
val viewModelStreamedMessage = mapper.map(streamedMessage, RoomViewModel(
roles = chatRoles, isBroadcast = chatIsBroadcast))
val roomMessages = messagesRepository.getByRoomId(streamedMessage.roomId)
val index = roomMessages.indexOfFirst { msg -> msg.id == streamedMessage.id }
if (index > -1) {
......
......@@ -21,7 +21,6 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.text.SpannableStringBuilder
import android.view.*
import androidx.core.text.bold
import androidx.core.view.isVisible
import chat.rocket.android.R
......@@ -40,7 +39,6 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewMod
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.circularRevealOrUnreveal
import chat.rocket.android.util.extensions.fadeIn
......@@ -48,7 +46,6 @@ import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.hideKeyboard
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.isAtBottom
import chat.rocket.android.util.extensions.isVisible
import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast
......@@ -184,8 +181,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
super.onViewCreated(view, savedInstanceState)
setupToolbar(chatRoomName)
presenter.setupChatRoom(chatRoomId)
presenter.loadMessages(chatRoomId, chatRoomType)
presenter.setupChatRoom(chatRoomId, chatRoomName, chatRoomType)
presenter.loadChatRooms()
setupRecyclerView()
setupFab()
......@@ -358,7 +354,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if (!recyclerView.canScrollVertically(1)) {
button_fab.hide()
} else {
if (dy < 0 && !button_fab.isVisible()) {
if (dy < 0 && !button_fab.isVisible) {
button_fab.show()
}
}
......@@ -664,7 +660,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_join_chat.setVisible(true)
button_join_chat.setOnClickListener { presenter.joinChat(chatRoomId) }
} else {
text_message.textContent = chatRoomMessage ?: ""
if (chatRoomMessage.orEmpty().isNotEmpty()) {
text_message.textContent = chatRoomMessage!!
text_message.setSelection(chatRoomMessage!!.length)
}
button_send.alpha = 0f
button_send.setVisible(false)
button_show_attachment_options.alpha = 1f
......
package chat.rocket.android.chatroom.viewmodel
import chat.rocket.core.model.ChatRoomRole
data class RoomViewModel(
val roles: List<ChatRoomRole>,
val isBroadcast: Boolean = false
)
\ No newline at end of file
......@@ -16,15 +16,30 @@ import chat.rocket.android.R
import chat.rocket.android.chatroom.domain.MessageReply
import chat.rocket.android.helper.MessageParser
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.ChatRoomsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isNotNullNorEmpty
import chat.rocket.android.widget.emoji.EmojiParser
import chat.rocket.common.model.RoomType
import chat.rocket.core.model.ChatRoom
import chat.rocket.core.model.ChatRoomRole
import chat.rocket.core.model.Message
import chat.rocket.core.model.MessageType
import chat.rocket.core.model.Value
import chat.rocket.core.model.attachment.*
import chat.rocket.core.model.attachment.Attachment
import chat.rocket.core.model.attachment.AudioAttachment
import chat.rocket.core.model.attachment.AuthorAttachment
import chat.rocket.core.model.attachment.ColorAttachment
import chat.rocket.core.model.attachment.FileAttachment
import chat.rocket.core.model.attachment.GenericFileAttachment
import chat.rocket.core.model.attachment.ImageAttachment
import chat.rocket.core.model.attachment.MessageAttachment
import chat.rocket.core.model.attachment.VideoAttachment
import chat.rocket.core.model.isSystemMessage
import chat.rocket.core.model.url.Url
import kotlinx.coroutines.experimental.CommonPool
......@@ -36,7 +51,7 @@ import javax.inject.Inject
class ViewModelMapper @Inject constructor(
private val context: Context,
private val parser: MessageParser,
private val roomsInteractor: GetChatRoomsInteractor,
private val roomsInteractor: ChatRoomsInteractor,
tokenRepository: TokenRepository,
serverInteractor: GetCurrentServerInteractor,
getSettingsInteractor: GetSettingsInteractor,
......@@ -50,21 +65,24 @@ class ViewModelMapper @Inject constructor(
private val currentUsername: String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY)
private val secondaryTextColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
suspend fun map(message: Message, onBroadcastChannel: Boolean = false): List<BaseViewModel<*>> {
return translate(message, onBroadcastChannel)
suspend fun map(message: Message, roomViewModel: RoomViewModel = RoomViewModel(
roles = emptyList(), isBroadcast = true)): List<BaseViewModel<*>> {
return translate(message, roomViewModel)
}
suspend fun map(messages: List<Message>, onBroadcastChannel: Boolean = false): List<BaseViewModel<*>> = withContext(CommonPool) {
suspend fun map(messages: List<Message>, roomViewModel: RoomViewModel = RoomViewModel(
roles = emptyList(), isBroadcast = true)): List<BaseViewModel<*>> = withContext(CommonPool) {
val list = ArrayList<BaseViewModel<*>>(messages.size)
messages.forEach {
list.addAll(translate(it, onBroadcastChannel))
list.addAll(translate(it, roomViewModel))
}
return@withContext list
}
private suspend fun translate(message: Message, onBroadcastChannel: Boolean): List<BaseViewModel<*>> = withContext(CommonPool) {
private suspend fun translate(message: Message, roomViewModel: RoomViewModel)
: List<BaseViewModel<*>> = withContext(CommonPool) {
val list = ArrayList<BaseViewModel<*>>()
message.urls?.forEach {
......@@ -89,7 +107,7 @@ class ViewModelMapper @Inject constructor(
list[i].nextDownStreamMessage = next
}
if (onBroadcastChannel && isBroadcastReplyAvailable(message)) {
if (isBroadcastReplyAvailable(roomViewModel, message)) {
roomsInteractor.getById(currentServer, message.roomId)?.let { chatRoom ->
val replyViewModel = mapMessageReply(message, chatRoom)
list.first().nextDownStreamMessage = replyViewModel
......@@ -100,13 +118,20 @@ class ViewModelMapper @Inject constructor(
return@withContext list
}
private fun isBroadcastReplyAvailable(message: Message): Boolean {
return !message.isSystemMessage() && message.sender?.username != currentUsername
private fun isBroadcastReplyAvailable(roomViewModel: RoomViewModel, message: Message): Boolean {
val senderUsername = message.sender?.username
val senderRoles = roomViewModel.roles.find { it.user.username == senderUsername }?.roles
?: emptyList()
return roomViewModel.isBroadcast &&
!message.isSystemMessage() &&
senderUsername != currentUsername &&
senderRoles.any { it == "moderator" || it == "owner" || it != "bot" }
}
private fun mapMessageReply(message: Message, chatRoom: ChatRoom): MessageReplyViewModel {
val name = message.sender?.name
val roomName = if (settings.useRealName() && name != null) name else message.sender?.username ?: ""
val roomName = if (settings.useRealName() && name != null) name else message.sender?.username
?: ""
return MessageReplyViewModel(
messageId = message.id,
isTemporary = false,
......@@ -119,7 +144,13 @@ class ViewModelMapper @Inject constructor(
}
private fun makePermalink(message: Message, chatRoom: ChatRoom): String {
val type = chatRoom.type.toString()
val type = when (chatRoom.type) {
is RoomType.PrivateGroup -> "group"
is RoomType.Channel -> "channel"
is RoomType.DirectMessage -> "direct"
is RoomType.Livechat -> "livechat"
else -> "custom"
}
val name = if (settings.useRealName()) chatRoom.fullName ?: chatRoom.name else chatRoom.name
return "[ ]($currentServer/$type/$name?msg=${message.id}) "
}
......
......@@ -9,7 +9,18 @@ import chat.rocket.android.helper.SharedPreferenceHelper
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.ChatRoomsInteractor
import chat.rocket.android.server.domain.GetActiveUsersInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.JobSchedulerInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveActiveUsersInteractor
import chat.rocket.android.server.domain.SaveChatRoomsInteractor
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.hasShowLastMessage
import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManager
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.chatRooms
......@@ -31,9 +42,13 @@ import chat.rocket.core.internal.rest.permissions
import chat.rocket.core.internal.rest.spotlight
import chat.rocket.core.model.ChatRoom
import chat.rocket.core.model.Room
import kotlinx.coroutines.experimental.*
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.Deferred
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject
import kotlin.reflect.KProperty1
......@@ -43,7 +58,7 @@ class ChatRoomsPresenter @Inject constructor(
private val strategy: CancelStrategy,
private val navigator: MainNavigator,
private val serverInteractor: GetCurrentServerInteractor,
private val getChatRoomsInteractor: GetChatRoomsInteractor,
private val chatRoomsInteractor: ChatRoomsInteractor,
private val saveChatRoomsInteractor: SaveChatRoomsInteractor,
private val saveActiveUsersInteractor: SaveActiveUsersInteractor,
private val getActiveUsersInteractor: GetActiveUsersInteractor,
......@@ -148,7 +163,7 @@ class ChatRoomsPresenter @Inject constructor(
val currentServer = serverInteractor.get()!!
launchUI(strategy) {
try {
val roomList = getChatRoomsInteractor.getAllByName(currentServer, name)
val roomList = chatRoomsInteractor.getAllByName(currentServer, name)
if (roomList.isEmpty()) {
val (users, rooms) = retryIO("spotlight($name)") {
client.spotlight(name)
......@@ -253,7 +268,7 @@ class ChatRoomsPresenter @Inject constructor(
fun updateSortedChatRooms() {
launchUI(strategy) {
val roomList = getChatRoomsInteractor.getAll(currentServer)
val roomList = chatRoomsInteractor.getAll(currentServer)
view.updateChatRooms(sortRooms(roomList))
}
}
......@@ -453,7 +468,7 @@ class ChatRoomsPresenter @Inject constructor(
// Update a ChatRoom with a Room information
private fun updateRoom(room: Room) {
Timber.d("Updating Room: ${room.id} - ${room.name}")
val chatRooms = getChatRoomsInteractor.getAll(currentServer).toMutableList()
val chatRooms = chatRoomsInteractor.getAll(currentServer).toMutableList()
val chatRoom = chatRooms.find { chatRoom -> chatRoom.id == room.id }
chatRoom?.apply {
val newRoom = ChatRoom(
......@@ -493,7 +508,7 @@ class ChatRoomsPresenter @Inject constructor(
// Update a ChatRoom with a Subscription information
private fun updateSubscription(subscription: Subscription) {
Timber.d("Updating subscription: ${subscription.id} - ${subscription.name}")
val chatRooms = getChatRoomsInteractor.getAll(currentServer).toMutableList()
val chatRooms = chatRoomsInteractor.getAll(currentServer).toMutableList()
val chatRoom = chatRooms.find { chatRoom -> chatRoom.id == subscription.roomId }
chatRoom?.apply {
val newRoom = ChatRoom(
......@@ -532,7 +547,7 @@ class ChatRoomsPresenter @Inject constructor(
private fun removeRoom(
id: String,
chatRooms: MutableList<ChatRoom> = getChatRoomsInteractor.getAll(currentServer).toMutableList()
chatRooms: MutableList<ChatRoom> = chatRoomsInteractor.getAll(currentServer).toMutableList()
) {
Timber.d("Removing ROOM: $id")
synchronized(this) {
......@@ -573,7 +588,7 @@ class ChatRoomsPresenter @Inject constructor(
val username = user_.username
val status = user_.status
if (username != null && status != null) {
getChatRoomsInteractor.getByName(currentServer, username)?.let {
chatRoomsInteractor.getByName(currentServer, username)?.let {
val newRoom = ChatRoom(
id = it.id,
type = it.type,
......@@ -600,10 +615,10 @@ class ChatRoomsPresenter @Inject constructor(
broadcast = it.broadcast
)
getChatRoomsInteractor.remove(currentServer, it)
getChatRoomsInteractor.add(currentServer, newRoom)
chatRoomsInteractor.remove(currentServer, it)
chatRoomsInteractor.add(currentServer, newRoom)
launchUI(strategy) {
view.updateChatRooms(sortRooms(getChatRoomsInteractor.getAll(currentServer)))
view.updateChatRooms(sortRooms(chatRoomsInteractor.getAll(currentServer)))
}
}
}
......@@ -613,7 +628,7 @@ class ChatRoomsPresenter @Inject constructor(
Timber.i("Updating ChatRooms")
launch(strategy.jobs) {
val chatRoomsWithPreview = getChatRoomsWithPreviews(
getChatRoomsInteractor.getAll(currentServer)
chatRoomsInteractor.getAll(currentServer)
)
val chatRoomsWithStatus = getChatRoomWithStatus(chatRoomsWithPreview)
view.updateChatRooms(chatRoomsWithStatus)
......
......@@ -2,7 +2,7 @@ package chat.rocket.android.pinnedmessages.presentation
import chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetChatRoomsInteractor
import chat.rocket.android.server.domain.ChatRoomsInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI
......@@ -17,7 +17,7 @@ class PinnedMessagesPresenter @Inject constructor(
private val view: PinnedMessagesView,
private val strategy: CancelStrategy,
private val serverInteractor: GetCurrentServerInteractor,
private val roomsInteractor: GetChatRoomsInteractor,
private val roomsInteractor: ChatRoomsInteractor,
private val mapper: ViewModelMapper,
factory: RocketChatClientFactory
) {
......
......@@ -5,7 +5,7 @@ import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext
import javax.inject.Inject
class GetChatRoomsInteractor @Inject constructor(private val repository: ChatRoomsRepository) {
class ChatRoomsInteractor @Inject constructor(private val repository: ChatRoomsRepository) {
/**
* Get all [ChatRoom].
......@@ -41,8 +41,7 @@ class GetChatRoomsInteractor @Inject constructor(private val repository: ChatRoo
* @return The [ChatRoom] object or null if we couldn't find any.
*/
suspend fun getById(serverUrl: String, roomId: String): ChatRoom? = withContext(CommonPool) {
val allChatRooms = repository.get(serverUrl)
return@withContext allChatRooms.first {
return@withContext repository.get(serverUrl).find {
it.id == roomId
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment