Unverified Commit fcfb22ea authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge branch 'develop' into fix/display-username

parents 5382b1e5 c0f75bad
package chat.rocket.android.chatroom.di package chat.rocket.android.chatroom.di
import android.app.Application
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import chat.rocket.android.chatroom.presentation.ChatRoomView import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.ui.ChatRoomFragment import chat.rocket.android.chatroom.ui.ChatRoomFragment
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.db.ChatRoomDao import chat.rocket.android.db.ChatRoomDao
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.db.UserDao
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.Job
...@@ -42,4 +49,30 @@ class ChatRoomFragmentModule { ...@@ -42,4 +49,30 @@ class ChatRoomFragmentModule {
@Provides @Provides
@PerFragment @PerFragment
fun provideChatRoomDao(manager: DatabaseManager): ChatRoomDao = manager.chatRoomDao() fun provideChatRoomDao(manager: DatabaseManager): ChatRoomDao = manager.chatRoomDao()
@Provides
@PerFragment
fun provideUserDao(manager: DatabaseManager): UserDao = manager.userDao()
@Provides
@PerFragment
fun provideGetCurrentUserInteractor(
tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String,
userDao: UserDao
): GetCurrentUserInteractor {
return GetCurrentUserInteractor(tokenRepository, serverUrl, userDao)
}
@Provides
@PerFragment
fun provideRoomMapper(
context: Application,
repository: SettingsRepository,
userInteractor: GetCurrentUserInteractor,
@Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl, permissionsInteractor)
}
} }
...@@ -15,6 +15,7 @@ import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel ...@@ -15,6 +15,7 @@ import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.core.behaviours.showMessage import chat.rocket.android.core.behaviours.showMessage
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
...@@ -74,6 +75,7 @@ import chat.rocket.core.model.ChatRoom ...@@ -74,6 +75,7 @@ import chat.rocket.core.model.ChatRoom
import chat.rocket.core.model.ChatRoomRole import chat.rocket.core.model.ChatRoomRole
import chat.rocket.core.model.Command import chat.rocket.core.model.Command
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.Room
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.DefaultDispatcher import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.android.UI import kotlinx.coroutines.experimental.android.UI
...@@ -97,6 +99,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -97,6 +99,7 @@ class ChatRoomPresenter @Inject constructor(
private val analyticsManager: AnalyticsManager, private val analyticsManager: AnalyticsManager,
private val userHelper: UserHelper, private val userHelper: UserHelper,
private val mapper: UiModelMapper, private val mapper: UiModelMapper,
private val roomMapper: RoomUiModelMapper,
private val jobSchedulerInteractor: JobSchedulerInteractor, private val jobSchedulerInteractor: JobSchedulerInteractor,
private val messageHelper: MessageHelper, private val messageHelper: MessageHelper,
private val dbManager: DatabaseManager, private val dbManager: DatabaseManager,
...@@ -119,6 +122,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -119,6 +122,7 @@ class ChatRoomPresenter @Inject constructor(
private var typingStatusSubscriptionId: String? = null private var typingStatusSubscriptionId: String? = null
private var lastState = manager.state private var lastState = manager.state
private var typingStatusList = arrayListOf<String>() private var typingStatusList = arrayListOf<String>()
private val roomChangesChannel = Channel<Room>(Channel.CONFLATED)
fun setupChatRoom( fun setupChatRoom(
roomId: String, roomId: String,
...@@ -126,7 +130,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -126,7 +130,7 @@ class ChatRoomPresenter @Inject constructor(
roomType: String, roomType: String,
chatRoomMessage: String? = null chatRoomMessage: String? = null
) { ) {
launchUI(strategy) { launch(CommonPool + strategy.jobs) {
try { try {
chatRoles = if (roomTypeOf(roomType) !is RoomType.DirectMessage) { chatRoles = if (roomTypeOf(roomType) !is RoomType.DirectMessage) {
client.chatRoomRoles(roomType = roomTypeOf(roomType), roomName = roomName) client.chatRoomRoles(roomType = roomTypeOf(roomType), roomName = roomName)
...@@ -136,16 +140,21 @@ class ChatRoomPresenter @Inject constructor( ...@@ -136,16 +140,21 @@ class ChatRoomPresenter @Inject constructor(
chatRoles = emptyList() chatRoles = emptyList()
} finally { } finally {
// User has at least an 'owner' or 'moderator' role. // User has at least an 'owner' or 'moderator' role.
val userCanMod = isOwnerOrMod() val canModerate = isOwnerOrMod()
val chatRoom = dbManager.getRoom(roomId)
val muted = chatRoom?.chatRoom?.muted ?: emptyList()
// Can post anyway if has the 'post-readonly' permission on server. // Can post anyway if has the 'post-readonly' permission on server.
val userCanPost = userCanMod || permissions.canPostToReadOnlyChannels() || val room = dbManager.getRoom(roomId)
!muted.contains(currentLoggedUsername) room?.let {
chatIsBroadcast = chatRoom?.chatRoom?.run { chatIsBroadcast = it.chatRoom.broadcast ?: false
broadcast val roomUiModel = roomMapper.map(it, true)
} ?: false launchUI(strategy) {
view.onRoomUpdated(userCanPost, chatIsBroadcast, userCanMod) view.onRoomUpdated(roomUiModel = roomUiModel.copy(
broadcast = chatIsBroadcast,
canModerate = canModerate,
writable = roomUiModel.writable || canModerate
))
}
}
loadMessages(roomId, roomType, clearDataSet = true) loadMessages(roomId, roomType, clearDataSet = true)
chatRoomMessage?.let { messageHelper.messageIdFromPermalink(it) } chatRoomMessage?.let { messageHelper.messageIdFromPermalink(it) }
?.let { messageId -> ?.let { messageId ->
...@@ -157,10 +166,26 @@ class ChatRoomPresenter @Inject constructor( ...@@ -157,10 +166,26 @@ class ChatRoomPresenter @Inject constructor(
true true
) )
} }
subscribeRoomChanges()
}
}
}
private suspend fun subscribeRoomChanges() {
chatRoomId?.let {
manager.addRoomChannel(it, roomChangesChannel)
for (room in roomChangesChannel) {
dbManager.getRoom(room.id)?.let {
view.onRoomUpdated(roomMapper.map(chatRoom = it, showLastMessage = true))
}
} }
} }
} }
private fun unsubscribeRoomChanges() {
chatRoomId?.let { manager.removeRoomChannel(it) }
}
private fun isOwnerOrMod(): Boolean { private fun isOwnerOrMod(): Boolean {
return chatRoles.firstOrNull { it.user.username == currentLoggedUsername }?.roles?.any { return chatRoles.firstOrNull { it.user.username == currentLoggedUsername }?.roles?.any {
it == "owner" || it == "moderator" it == "owner" || it == "moderator"
...@@ -987,7 +1012,12 @@ class ChatRoomPresenter @Inject constructor( ...@@ -987,7 +1012,12 @@ class ChatRoomPresenter @Inject constructor(
try { try {
retryIO("joinChat($chatRoomId)") { client.joinChat(chatRoomId) } retryIO("joinChat($chatRoomId)") { client.joinChat(chatRoomId) }
val canPost = permissions.canPostToReadOnlyChannels() val canPost = permissions.canPostToReadOnlyChannels()
view.onJoined(canPost) dbManager.getRoom(chatRoomId)?.let {
val roomUiModel = roomMapper.map(it, true).copy(
writable = canPost)
view.onJoined(roomUiModel = roomUiModel)
view.onRoomUpdated(roomUiModel = roomUiModel)
}
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
Timber.e(ex) Timber.e(ex)
} }
...@@ -1157,6 +1187,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -1157,6 +1187,7 @@ class ChatRoomPresenter @Inject constructor(
} }
fun disconnect() { fun disconnect() {
unsubscribeRoomChanges()
unsubscribeTypingStatus() unsubscribeTypingStatus()
if (chatRoomId != null) { if (chatRoomId != null) {
unsubscribeMessages(chatRoomId.toString()) unsubscribeMessages(chatRoomId.toString())
......
...@@ -5,6 +5,7 @@ import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel ...@@ -5,6 +5,7 @@ import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.core.behaviours.LoadingView import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
...@@ -131,12 +132,7 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -131,12 +132,7 @@ interface ChatRoomView : LoadingView, MessageView {
fun populateEmojiSuggestions(emojis: List<EmojiSuggestionUiModel>) fun populateEmojiSuggestions(emojis: List<EmojiSuggestionUiModel>)
/** fun onJoined(roomUiModel: RoomUiModel)
* This user has joined the chat callback.
*
* @param userCanPost Whether the user can post a message or not.
*/
fun onJoined(userCanPost: Boolean)
fun showReactionsPopup(messageId: String) fun showReactionsPopup(messageId: String)
...@@ -147,9 +143,6 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -147,9 +143,6 @@ interface ChatRoomView : LoadingView, MessageView {
*/ */
fun populateCommandSuggestions(commands: List<CommandSuggestionUiModel>) fun populateCommandSuggestions(commands: List<CommandSuggestionUiModel>)
/** fun onRoomUpdated(roomUiModel: RoomUiModel)
* Communicate whether it's a broadcast channel and if current user can post to it.
*/
fun onRoomUpdated(userCanPost: Boolean, channelIsBroadcast: Boolean, userCanMod: Boolean)
} }
...@@ -51,6 +51,7 @@ import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel ...@@ -51,6 +51,7 @@ import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.draw.main.ui.DRAWING_BYTE_ARRAY_EXTRA_DATA import chat.rocket.android.draw.main.ui.DRAWING_BYTE_ARRAY_EXTRA_DATA
import chat.rocket.android.draw.main.ui.DrawingActivity import chat.rocket.android.draw.main.ui.DrawingActivity
import chat.rocket.android.emoji.ComposerEditText import chat.rocket.android.emoji.ComposerEditText
...@@ -401,17 +402,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -401,17 +402,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
empty_chat_view.isVisible = adapter.itemCount == 0 empty_chat_view.isVisible = adapter.itemCount == 0
} }
override fun onRoomUpdated( override fun onRoomUpdated(roomUiModel: RoomUiModel) {
userCanPost: Boolean,
channelIsBroadcast: Boolean,
userCanMod: Boolean
) {
// TODO: We should rely solely on the user being able to post, but we cannot guarantee // TODO: We should rely solely on the user being able to post, but we cannot guarantee
// that the "(channels|groups).roles" endpoint is supported by the server in use. // that the "(channels|groups).roles" endpoint is supported by the server in use.
ui { ui {
setupMessageComposer(userCanPost) setupToolbar(roomUiModel.name.toString())
isBroadcastChannel = channelIsBroadcast setupMessageComposer(roomUiModel)
if (isBroadcastChannel && !userCanMod) { isBroadcastChannel = roomUiModel.broadcast
if (isBroadcastChannel && !roomUiModel.canModerate) {
disableMenu = true disableMenu = true
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
} }
...@@ -790,12 +788,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -790,12 +788,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun onJoined(userCanPost: Boolean) { override fun onJoined(roomUiModel: RoomUiModel) {
ui { ui {
input_container.isVisible = true input_container.isVisible = true
button_join_chat.isVisible = false button_join_chat.isVisible = false
isSubscribed = true isSubscribed = true
setupMessageComposer(userCanPost)
} }
} }
...@@ -828,8 +825,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -828,8 +825,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
private fun setupMessageComposer(canPost: Boolean) { private fun setupMessageComposer(roomUiModel: RoomUiModel) {
if (!canPost) { if (isReadOnly || !roomUiModel.writable) {
text_room_is_read_only.isVisible = true text_room_is_read_only.isVisible = true
input_container.isVisible = false input_container.isVisible = false
text_room_is_read_only.setText( text_room_is_read_only.setText(
...@@ -845,6 +842,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -845,6 +842,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_join_chat.isVisible = true button_join_chat.isVisible = true
button_join_chat.setOnClickListener { presenter.joinChat(chatRoomId) } button_join_chat.setOnClickListener { presenter.joinChat(chatRoomId) }
} else { } else {
input_container.isVisible = true
text_room_is_read_only.isVisible = false
button_send.isVisible = false button_send.isVisible = false
button_show_attachment_options.alpha = 1f button_show_attachment_options.alpha = 1f
button_show_attachment_options.isVisible = true button_show_attachment_options.isVisible = true
......
...@@ -8,9 +8,8 @@ import androidx.core.text.color ...@@ -8,9 +8,8 @@ import androidx.core.text.color
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.db.model.ChatRoom import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.checkIfMyself
import chat.rocket.android.server.domain.GetCurrentUserInteractor import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.showLastMessage import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
...@@ -30,7 +29,8 @@ class RoomUiModelMapper( ...@@ -30,7 +29,8 @@ class RoomUiModelMapper(
private val context: Application, private val context: Application,
private val settings: PublicSettings, private val settings: PublicSettings,
private val userInteractor: GetCurrentUserInteractor, private val userInteractor: GetCurrentUserInteractor,
private val serverUrl: String private val serverUrl: String,
private val permissions: PermissionsInteractor
) { ) {
private val nameUnreadColor = ContextCompat.getColor(context, R.color.colorPrimaryText) private val nameUnreadColor = ContextCompat.getColor(context, R.color.colorPrimaryText)
private val nameColor = ContextCompat.getColor(context, R.color.colorSecondaryText) private val nameColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
...@@ -97,7 +97,9 @@ class RoomUiModelMapper( ...@@ -97,7 +97,9 @@ class RoomUiModelMapper(
avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true), avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true),
lastMessage = if(showLastMessage) { mapLastMessage(lastMessage?.sender?.id, lastMessage?.sender?.username, lastMessage = if(showLastMessage) { mapLastMessage(lastMessage?.sender?.id, lastMessage?.sender?.username,
lastMessage?.sender?.name, lastMessage?.message, lastMessage?.sender?.name, lastMessage?.message,
isDirectMessage = type is RoomType.DirectMessage)} else { null } isDirectMessage = type is RoomType.DirectMessage)} else { null },
muted = muted.orEmpty(),
writable = isChannelWritable(muted)
) )
} }
} }
...@@ -133,11 +135,18 @@ class RoomUiModelMapper( ...@@ -133,11 +135,18 @@ class RoomUiModelMapper(
alert = isUnread, alert = isUnread,
lastMessage = lastMessageMarkdown, lastMessage = lastMessageMarkdown,
status = status, status = status,
username = if (type is RoomType.DirectMessage) name else null username = if (type is RoomType.DirectMessage) name else null,
muted = muted.orEmpty(),
writable = isChannelWritable(muted)
) )
} }
} }
private fun isChannelWritable(muted: List<String>?): Boolean {
val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels()
return canWriteToReadOnlyChannels || !muted.orEmpty().contains(currentUser?.username)
}
private fun roomType(type: String): String { private fun roomType(type: String): String {
val resources = context.resources val resources = context.resources
return when (type) { return when (type) {
...@@ -205,4 +214,4 @@ class RoomUiModelMapper( ...@@ -205,4 +214,4 @@ class RoomUiModelMapper(
} }
} }
} }
} }
\ No newline at end of file
...@@ -15,5 +15,8 @@ data class RoomUiModel( ...@@ -15,5 +15,8 @@ data class RoomUiModel(
val lastMessage: CharSequence? = null, val lastMessage: CharSequence? = null,
val status: UserStatus? = null, val status: UserStatus? = null,
val username: String? = null, val username: String? = null,
val broadcast: Boolean = false,
val canModerate: Boolean = false,
val writable: Boolean = true,
val muted: List<String> = emptyList() val muted: List<String> = emptyList()
) )
...@@ -12,6 +12,7 @@ import chat.rocket.android.db.DatabaseManager ...@@ -12,6 +12,7 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.UserDao import chat.rocket.android.db.UserDao
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentUserInteractor import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
...@@ -88,9 +89,10 @@ class ChatRoomsFragmentModule { ...@@ -88,9 +89,10 @@ class ChatRoomsFragmentModule {
context: Application, context: Application,
repository: SettingsRepository, repository: SettingsRepository,
userInteractor: GetCurrentUserInteractor, userInteractor: GetCurrentUserInteractor,
@Named("currentServer") serverUrl: String @Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper { ): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl) return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl, permissionsInteractor)
} }
@Provides @Provides
......
...@@ -22,6 +22,7 @@ import chat.rocket.core.internal.realtime.unsubscribe ...@@ -22,6 +22,7 @@ import chat.rocket.core.internal.realtime.unsubscribe
import chat.rocket.core.internal.rest.chatRooms import chat.rocket.core.internal.rest.chatRooms
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.Myself import chat.rocket.core.model.Myself
import chat.rocket.core.model.Room
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.channels.Channel
...@@ -45,6 +46,7 @@ class ConnectionManager( ...@@ -45,6 +46,7 @@ class ConnectionManager(
private val roomMessagesChannels = LinkedHashMap<String, Channel<Message>>() private val roomMessagesChannels = LinkedHashMap<String, Channel<Message>>()
private val userDataChannels = ArrayList<Channel<Myself>>() private val userDataChannels = ArrayList<Channel<Myself>>()
private val roomsChannels = LinkedHashMap<String, Channel<Room>>()
private val subscriptionIdMap = HashMap<String, String>() private val subscriptionIdMap = HashMap<String, String>()
private var subscriptionId: String? = null private var subscriptionId: String? = null
...@@ -127,6 +129,18 @@ class ConnectionManager( ...@@ -127,6 +129,18 @@ class ConnectionManager(
maxSize = 10) { batch -> maxSize = 10) { batch ->
Timber.d("processing Stream batch: ${batch.size} - $batch") Timber.d("processing Stream batch: ${batch.size} - $batch")
dbManager.processChatRoomsBatch(batch) dbManager.processChatRoomsBatch(batch)
batch.forEach {
//TODO - Do we need to handle Type.Removed and Type.Inserted here?
if (it.type == Type.Updated) {
if (it.data is Room) {
val room = it.data as Room
roomsChannels[it.data.id]?.let { channel ->
channel.offer(room)
}
}
}
}
} }
val messagesActor = createBatchActor<Message>(messagesContext, parent = connectJob, val messagesActor = createBatchActor<Message>(messagesContext, parent = connectJob,
...@@ -241,6 +255,14 @@ class ConnectionManager( ...@@ -241,6 +255,14 @@ class ConnectionManager(
fun removeUserDataChannel(channel: Channel<Myself>) = userDataChannels.remove(channel) fun removeUserDataChannel(channel: Channel<Myself>) = userDataChannels.remove(channel)
fun addRoomChannel(roomId: String, channel: Channel<Room>) {
roomsChannels[roomId] = channel
}
fun removeRoomChannel(roomId: String) {
roomsChannels.remove(roomId)
}
fun subscribeRoomMessages(roomId: String, channel: Channel<Message>) { fun subscribeRoomMessages(roomId: String, channel: Channel<Message>) {
val oldSub = roomMessagesChannels.put(roomId, channel) val oldSub = roomMessagesChannels.put(roomId, channel)
if (oldSub != null) { if (oldSub != null) {
......
...@@ -10,7 +10,6 @@ import android.view.View ...@@ -10,7 +10,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText import android.widget.EditText
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
...@@ -22,6 +21,7 @@ import chat.rocket.android.emoji.internal.EmojiCategory ...@@ -22,6 +21,7 @@ import chat.rocket.android.emoji.internal.EmojiCategory
import chat.rocket.android.emoji.internal.EmojiPagerAdapter import chat.rocket.android.emoji.internal.EmojiPagerAdapter
import chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE import chat.rocket.android.emoji.internal.PREF_EMOJI_SKIN_TONE
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.dialog_skin_tone_chooser.view.*
import kotlinx.coroutines.experimental.android.UI import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
...@@ -77,59 +77,50 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow ...@@ -77,59 +77,50 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
} }
private fun showSkinToneChooser() { private fun showSkinToneChooser() {
val view = LayoutInflater.from(context).inflate(R.layout.color_select_popup, null) val view = LayoutInflater.from(context).inflate(R.layout.dialog_skin_tone_chooser, null)
val dialog = AlertDialog.Builder(context, R.style.Dialog) val dialog = AlertDialog.Builder(context, R.style.Dialog)
.setView(view) .setView(view)
.setTitle(context.getString(R.string.alert_title_default_skin_tone)) .setTitle(context.getString(R.string.alert_title_default_skin_tone))
.setCancelable(true) .setCancelable(true)
.create() .create()
view.findViewById<TextView>(R.id.default_tone_text).also { with (view) {
it.text = EmojiParser.parse(context, it.text) image_view_default_tone.setOnClickListener {
}.setOnClickListener { dialog.dismiss()
dialog.dismiss() changeSkinTone(Fitzpatrick.Default)
changeSkinTone(Fitzpatrick.Default) }
}
view.findViewById<TextView>(R.id.light_tone_text).also { image_view_light_tone.setOnClickListener {
it.text = EmojiParser.parse(context, it.text) dialog.dismiss()
}.setOnClickListener { changeSkinTone(Fitzpatrick.LightTone)
dialog.dismiss() }
changeSkinTone(Fitzpatrick.LightTone)
}
view.findViewById<TextView>(R.id.medium_light_text).also { image_view_medium_light.setOnClickListener {
it.text = EmojiParser.parse(context, it.text) dialog.dismiss()
}.setOnClickListener { changeSkinTone(Fitzpatrick.MediumLightTone)
dialog.dismiss() }
changeSkinTone(Fitzpatrick.MediumLightTone)
}
view.findViewById<TextView>(R.id.medium_tone_text).also { image_view_medium_tone.setOnClickListener {
it.text = EmojiParser.parse(context, it.text) dialog.dismiss()
}.setOnClickListener { changeSkinTone(Fitzpatrick.MediumTone)
dialog.dismiss() }
changeSkinTone(Fitzpatrick.MediumTone)
}
view.findViewById<TextView>(R.id.medium_dark_tone_text).also { image_view_medium_dark_tone.setOnClickListener {
it.text = EmojiParser.parse(context, it.text) dialog.dismiss()
}.setOnClickListener { changeSkinTone(Fitzpatrick.MediumDarkTone)
dialog.dismiss() }
changeSkinTone(Fitzpatrick.MediumDarkTone)
}
view.findViewById<TextView>(R.id.dark_tone_text).also { image_view_dark_tone.setOnClickListener {
it.text = EmojiParser.parse(context, it.text) dialog.dismiss()
}.setOnClickListener { changeSkinTone(Fitzpatrick.DarkTone)
dialog.dismiss() }
changeSkinTone(Fitzpatrick.DarkTone)
} }
dialog.show() dialog.show()
} }
private fun changeSkinTone(tone: Fitzpatrick) { private fun changeSkinTone(tone: Fitzpatrick) {
val drawable = ContextCompat.getDrawable(context, R.drawable.color_change_circle)!! val drawable = ContextCompat.getDrawable(context, R.drawable.bg_skin_tone)!!
val wrappedDrawable = DrawableCompat.wrap(drawable) val wrappedDrawable = DrawableCompat.wrap(drawable)
DrawableCompat.setTint(wrappedDrawable, getFitzpatrickColor(tone)) DrawableCompat.setTint(wrappedDrawable, getFitzpatrickColor(tone))
(changeColorView as ImageView).setImageDrawable(wrappedDrawable) (changeColorView as ImageView).setImageDrawable(wrappedDrawable)
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"> android:shape="oval">
<solid android:color="@color/tone_default" /> <solid android:color="@color/tone_default" />
<size <size
android:width="24dp" android:width="24dp"
android:height="24dp" /> android:height="24dp" />
</shape> </shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <ImageView
android:id="@+id/default_tone_text" android:id="@+id/image_view_default_tone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:text="👌" android:layout_marginBottom="16dp"
android:textSize="32sp"
android:tint="@color/tone_default" android:tint="@color/tone_default"
app:layout_constraintEnd_toStartOf="@+id/light_tone_text" app:layout_constraintBottom_toTopOf="@+id/image_view_medium_tone"
app:layout_constraintEnd_toStartOf="@+id/image_view_light_tone"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/color_change_circle" /> app:srcCompat="@drawable/bg_skin_tone" />
<TextView <ImageView
android:id="@+id/light_tone_text" android:id="@+id/image_view_light_tone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="24dp"
android:text="👌🏻"
android:textSize="32sp"
android:tint="@color/tone_light" android:tint="@color/tone_light"
app:layout_constraintEnd_toStartOf="@+id/medium_light_text" app:layout_constraintEnd_toStartOf="@+id/image_view_medium_light"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/default_tone_text" app:layout_constraintStart_toEndOf="@+id/image_view_default_tone"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/color_change_circle" app:srcCompat="@drawable/bg_skin_tone" />
tools:text="👌" />
<TextView <ImageView
android:id="@+id/medium_light_text" android:id="@+id/image_view_medium_light"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:text="👌🏼" android:layout_marginEnd="24dp"
android:textSize="32sp"
android:tint="@color/tone_medium_light" android:tint="@color/tone_medium_light"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/light_tone_text" app:layout_constraintStart_toEndOf="@+id/image_view_light_tone"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/color_change_circle" app:srcCompat="@drawable/bg_skin_tone" />
tools:text="👌" />
<TextView <ImageView
android:id="@+id/medium_tone_text" android:id="@+id/image_view_medium_tone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:text="👌🏽"
android:textSize="32sp"
android:tint="@color/tone_medium" android:tint="@color/tone_medium"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/medium_dark_tone_text" app:layout_constraintEnd_toStartOf="@+id/image_view_medium_dark_tone"
app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="@+id/image_view_default_tone"
app:layout_constraintTop_toBottomOf="@+id/default_tone_text" app:layout_constraintTop_toBottomOf="@+id/image_view_default_tone"
app:srcCompat="@drawable/color_change_circle" app:srcCompat="@drawable/bg_skin_tone" />
tools:text="👌" />
<TextView <ImageView
android:id="@+id/medium_dark_tone_text" android:id="@+id/image_view_medium_dark_tone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="16dp"
android:text="👌🏾"
android:textSize="32sp"
android:tint="@color/tone_medium_dark" android:tint="@color/tone_medium_dark"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="@+id/image_view_medium_tone"
app:layout_constraintEnd_toStartOf="@+id/dark_tone_text" app:layout_constraintEnd_toStartOf="@+id/image_view_dark_tone"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/medium_tone_text" app:layout_constraintStart_toEndOf="@+id/image_view_medium_tone"
app:layout_constraintTop_toBottomOf="@+id/light_tone_text" app:layout_constraintTop_toTopOf="@+id/image_view_medium_tone"
app:srcCompat="@drawable/color_change_circle" app:srcCompat="@drawable/bg_skin_tone" />
tools:text="👌" />
<TextView <ImageView
android:id="@+id/dark_tone_text" android:id="@+id/image_view_dark_tone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:text="👌🏿"
android:textSize="32sp"
android:tint="@color/tone_dark" android:tint="@color/tone_dark"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="@+id/image_view_medium_dark_tone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="@+id/image_view_medium_light"
app:layout_constraintStart_toEndOf="@+id/medium_dark_tone_text" app:layout_constraintStart_toEndOf="@+id/image_view_medium_dark_tone"
app:layout_constraintTop_toBottomOf="@+id/medium_light_text" app:layout_constraintTop_toTopOf="@+id/image_view_medium_dark_tone"
app:srcCompat="@drawable/color_change_circle" app:srcCompat="@drawable/bg_skin_tone" />
tools:text="👌" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/color_change_circle" /> app:srcCompat="@drawable/bg_skin_tone" />
<ImageView <ImageView
android:id="@+id/emoji_search" android:id="@+id/emoji_search"
......
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