ChatRoomsPresenter.kt 9.55 KB
Newer Older
1 2 3
package chat.rocket.android.chatrooms.presentation

import chat.rocket.android.core.lifecycle.CancelStrategy
4
import chat.rocket.android.server.domain.GetChatRoomsInteractor
5
import chat.rocket.android.server.domain.GetCurrentServerInteractor
6
import chat.rocket.android.server.domain.RefreshSettingsInteractor
7
import chat.rocket.android.server.domain.SaveChatRoomsInteractor
8
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
9
import chat.rocket.android.util.extensions.launchUI
10
import chat.rocket.common.RocketChatException
11
import chat.rocket.core.RocketChatClient
12 13
import chat.rocket.core.internal.model.Subscription
import chat.rocket.core.internal.realtime.*
14
import chat.rocket.core.internal.rest.chatRooms
15
import chat.rocket.core.model.ChatRoom
16 17
import chat.rocket.core.model.Room
import kotlinx.coroutines.experimental.*
Lucio Maciel's avatar
Lucio Maciel committed
18
import kotlinx.coroutines.experimental.channels.Channel
19
import timber.log.Timber
20 21
import javax.inject.Inject

22 23
class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
                                             private val strategy: CancelStrategy,
24
                                             private val navigator: ChatRoomsNavigator,
25
                                             private val serverInteractor: GetCurrentServerInteractor,
26 27
                                             private val getChatRoomsInteractor: GetChatRoomsInteractor,
                                             private val saveChatRoomsInteractor: SaveChatRoomsInteractor,
28
                                             private val refreshSettingsInteractor: RefreshSettingsInteractor,
29
                                             factory: RocketChatClientFactory) {
30 31 32
    private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
    private val currentServer = serverInteractor.get()!!
    private var reloadJob: Deferred<List<ChatRoom>>? = null
33

Lucio Maciel's avatar
Lucio Maciel committed
34 35
    private val stateChannel = Channel<State>()

36
    fun loadChatRooms() {
37
        refreshSettingsInteractor.refreshAsync(currentServer)
38 39
        launchUI(strategy) {
            view.showLoading()
40 41 42 43 44 45 46 47 48
            try {
                view.updateChatRooms(loadRooms())
                subscribeRoomUpdates()
            } catch (e: RocketChatException) {
                Timber.e(e)
                view.showMessage(e.message!!)
            } finally {
                view.hideLoading()
            }
49 50
        }
    }
51

52 53
    fun loadChatRoom(chatRoom: ChatRoom) = navigator.toChatRoom(chatRoom.id, chatRoom.name,
            chatRoom.type.toString(), chatRoom.readonly ?: false)
54 55 56 57 58 59 60 61 62 63 64

    /**
     * Gets a [ChatRoom] list from local repository.
     * ChatRooms returned are filtered by name.
     */
    fun chatRoomsByName(name: String) {
        val currentServer = serverInteractor.get()!!
        launchUI(strategy) {
            val roomList = getChatRoomsInteractor.getByName(currentServer, name)
            view.updateChatRooms(roomList)
        }
65 66
    }

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    private suspend fun loadRooms(): List<ChatRoom> {
        val chatRooms = client.chatRooms().update
        val sortedRooms = sortRooms(chatRooms)
        saveChatRoomsInteractor.save(currentServer, sortedRooms)
        return sortedRooms
    }

    private fun sortRooms(chatRooms: List<ChatRoom>): List<ChatRoom> {
        val openChatRooms = getOpenChatRooms(chatRooms)
        return sortChatRooms(openChatRooms)
    }

    private fun updateRooms() {
        launch {
            view.updateChatRooms(getChatRoomsInteractor.get(currentServer))
        }
83 84
    }

85 86 87 88 89
    private fun getOpenChatRooms(chatRooms: List<ChatRoom>): List<ChatRoom> {
        return chatRooms.filter(ChatRoom::open)
    }

    private fun sortChatRooms(chatRooms: List<ChatRoom>): List<ChatRoom> {
90 91
        return chatRooms.sortedByDescending { chatRoom ->
            chatRoom.lastMessage?.timestamp
92 93
        }
    }
94 95 96

    // TODO - Temporary stuff, remove when adding DB support
    private suspend fun subscribeRoomUpdates() {
Lucio Maciel's avatar
Lucio Maciel committed
97
        client.addStateChannel(stateChannel)
98
        launch(CommonPool + strategy.jobs) {
Lucio Maciel's avatar
Lucio Maciel committed
99
            for (status in stateChannel) {
100 101 102 103 104
                Timber.d("Changing status to: $status")
                when (status) {
                    State.Authenticating -> Timber.d("Authenticating")
                    State.Connected -> {
                        Timber.d("Connected")
Lucio Maciel's avatar
Lucio Maciel committed
105 106 107 108 109 110
                        client.subscribeSubscriptions {
                            Timber.d("subscriptions: $it")
                        }
                        client.subscribeRooms {
                            Timber.d("rooms: $it")
                        }
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
                    }
                }
            }
            Timber.d("Done on statusChannel")
        }

        when (client.state) {
            State.Connected -> {
                Timber.d("Already connected")
            }
            else -> client.connect()
        }

        launch(CommonPool + strategy.jobs) {
            for (message in client.roomsChannel) {
                Timber.d("Got message: $message")
                updateRoom(message)
            }
        }

        launch(CommonPool + strategy.jobs) {
            for (message in client.subscriptionsChannel) {
                Timber.d("Got message: $message")
                updateSubscription(message)
            }
        }
    }

    private fun updateRoom(message: StreamMessage<Room>) {
        launchUI(strategy) {
            when (message.type) {
                Type.Removed -> {
                    removeRoom(message.data.id)
                }
                Type.Updated -> {
                    updateRoom(message.data)
                }
                Type.Inserted -> {
                    // On insertion, just get all chatrooms again, since we can't create one just
                    // from a Room
                    reloadRooms()
                }
            }

            updateRooms()
        }
    }

    private fun updateSubscription(message: StreamMessage<Subscription>) {
        launchUI(strategy) {
            when (message.type) {
                Type.Removed -> {
                    removeRoom(message.data.roomId)
                }
                Type.Updated -> {
                    updateSubscription(message.data)
                }
                Type.Inserted -> {
                    // On insertion, just get all chatrooms again, since we can't create one just
                    // from a Subscription
                    reloadRooms()
                }
            }

            updateRooms()
        }
    }

    private suspend fun reloadRooms() {
        Timber.d("realoadRooms()")
        reloadJob?.cancel()

        reloadJob = async(CommonPool + strategy.jobs) {
            delay(1000)
            Timber.d("reloading rooms after wait")
            loadRooms()
        }
        reloadJob?.await()
    }

    // Update a ChatRoom with a Room information
    private fun updateRoom(room: Room) {
        val chatRooms = getChatRoomsInteractor.get(currentServer).toMutableList()
        val chatRoom = chatRooms.find { chatRoom -> chatRoom.id == room.id }
        chatRoom?.apply {
            val newRoom = ChatRoom(room.id,
                    room.type,
                    room.user ?: user,
                    room.name ?: name,
                    room.fullName ?: fullName,
                    room.readonly,
                    room.updatedAt ?: updatedAt,
                    timestamp,
204
                    lastSeen,
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
                    room.topic,
                    room.announcement,
                    default,
                    open,
                    alert,
                    unread,
                    userMenstions,
                    groupMentions,
                    room.lastMessage,
                    client)
            removeRoom(room.id, chatRooms)
            chatRooms.add(newRoom)
            saveChatRoomsInteractor.save(currentServer, sortRooms(chatRooms))
        }
    }

    // Update a ChatRoom with a Subscription information
    private fun updateSubscription(subscription: Subscription) {
        val chatRooms = getChatRoomsInteractor.get(currentServer).toMutableList()
        val chatRoom = chatRooms.find { chatRoom -> chatRoom.id == subscription.roomId }
        chatRoom?.apply {
            val newRoom = ChatRoom(subscription.roomId,
                    subscription.type,
                    subscription.user ?: user,
                    subscription.name,
                    subscription.fullName ?: fullName,
                    subscription.readonly ?: readonly,
                    subscription.updatedAt ?: updatedAt,
                    subscription.timestamp ?: timestamp,
234
                    subscription.lastSeen ?: lastSeen,
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
                    topic,
                    announcement,
                    subscription.isDefault,
                    subscription.open,
                    subscription.alert,
                    subscription.unread,
                    subscription.userMentions,
                    subscription.groupMentions,
                    lastMessage,
                    client)
            removeRoom(subscription.roomId, chatRooms)
            chatRooms.add(newRoom)
            saveChatRoomsInteractor.save(currentServer, sortRooms(chatRooms))
        }
    }


    private fun removeRoom(id: String,
                           chatRooms: MutableList<ChatRoom> = getChatRoomsInteractor.get(currentServer).toMutableList()) {
        synchronized(this) {
            chatRooms.removeAll { chatRoom -> chatRoom.id == id }
        }
        saveChatRoomsInteractor.save(currentServer, sortRooms(chatRooms))
    }
259 260

    fun disconnect() {
Lucio Maciel's avatar
Lucio Maciel committed
261
        client.removeStateChannel(stateChannel)
262 263
        client.disconnect()
    }
264
}