Commit ac7a6e1e authored by Lucio Maciel's avatar Lucio Maciel

Read messages from DB

parent cc24c585
673693445664
673693445664
...@@ -190,7 +190,7 @@ class ChatRoomAdapter( ...@@ -190,7 +190,7 @@ class ChatRoomAdapter(
notifyDataSetChanged() notifyDataSetChanged()
} }
fun updateItem(message: BaseUiModel<*>) { fun updateItem(message: BaseUiModel<*>): Boolean {
val index = dataSet.indexOfLast { it.messageId == message.messageId } val index = dataSet.indexOfLast { it.messageId == message.messageId }
val indexOfNext = dataSet.indexOfFirst { it.messageId == message.messageId } val indexOfNext = dataSet.indexOfFirst { it.messageId == message.messageId }
Timber.d("index: $index") Timber.d("index: $index")
...@@ -209,7 +209,9 @@ class ChatRoomAdapter( ...@@ -209,7 +209,9 @@ class ChatRoomAdapter(
dataSet.removeAt(indexOfNext) dataSet.removeAt(indexOfNext)
notifyItemRemoved(indexOfNext) notifyItemRemoved(indexOfNext)
} }
return true
} }
return false
} }
fun removeItem(messageId: String) { fun removeItem(messageId: String) {
......
...@@ -226,7 +226,6 @@ class ChatRoomPresenter @Inject constructor( ...@@ -226,7 +226,6 @@ class ChatRoomPresenter @Inject constructor(
retryIO("loadAndShowMessages($chatRoomId, $chatRoomType, $offset") { retryIO("loadAndShowMessages($chatRoomId, $chatRoomType, $offset") {
client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result
} }
dbManager.processMessagesBatch(messages)
messagesRepository.saveAll(messages) messagesRepository.saveAll(messages)
//we are saving last sync date of latest synced chat room message //we are saving last sync date of latest synced chat room message
...@@ -304,7 +303,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -304,7 +303,7 @@ class ChatRoomPresenter @Inject constructor(
type = null, type = null,
updatedAt = null, updatedAt = null,
urls = null, urls = null,
isTemporary = true, synced = false,
unread = true unread = true
) )
try { try {
...@@ -316,6 +315,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -316,6 +315,7 @@ class ChatRoomPresenter @Inject constructor(
), false ), false
) )
client.sendMessage(id, chatRoomId, text) client.sendMessage(id, chatRoomId, text)
messagesRepository.save(newMessage.copy(synced = true))
logMessageSent() logMessageSent()
} catch (ex: Exception) { } catch (ex: Exception) {
// Ok, not very beautiful, but the backend sends us a not valid response // Ok, not very beautiful, but the backend sends us a not valid response
...@@ -511,8 +511,6 @@ class ChatRoomPresenter @Inject constructor( ...@@ -511,8 +511,6 @@ class ChatRoomPresenter @Inject constructor(
} }
Timber.d("History: $messages") Timber.d("History: $messages")
dbManager.processMessagesBatch(messages.result)
if (messages.result.isNotEmpty()) { if (messages.result.isNotEmpty()) {
val models = mapper.map(messages.result, RoomUiModel( val models = mapper.map(messages.result, RoomUiModel(
roles = chatRoles, roles = chatRoles,
...@@ -1128,11 +1126,11 @@ class ChatRoomPresenter @Inject constructor( ...@@ -1128,11 +1126,11 @@ class ChatRoomPresenter @Inject constructor(
val index = roomMessages.indexOfFirst { msg -> msg.id == streamedMessage.id } val index = roomMessages.indexOfFirst { msg -> msg.id == streamedMessage.id }
if (index > -1) { if (index > -1) {
Timber.d("Updating message at $index") Timber.d("Updating message at $index")
messagesRepository.save(streamedMessage) //messagesRepository.save(streamedMessage)
view.dispatchUpdateMessage(index, viewModelStreamedMessage) view.dispatchUpdateMessage(index, viewModelStreamedMessage)
} else { } else {
Timber.d("Adding new message") Timber.d("Adding new message")
messagesRepository.save(streamedMessage) //messagesRepository.save(streamedMessage)
view.showNewMessage(viewModelStreamedMessage, true) view.showNewMessage(viewModelStreamedMessage, true)
} }
} }
......
...@@ -2,9 +2,11 @@ package chat.rocket.android.chatroom.service ...@@ -2,9 +2,11 @@ package chat.rocket.android.chatroom.service
import android.app.job.JobParameters import android.app.job.JobParameters
import android.app.job.JobService import android.app.job.JobService
import chat.rocket.android.server.domain.CurrentServerRepository import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.server.domain.MessagesRepository import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.DatabaseMessageMapper
import chat.rocket.android.server.infraestructure.DatabaseMessagesRepository
import chat.rocket.core.internal.rest.sendMessage import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
...@@ -17,9 +19,9 @@ class MessageService : JobService() { ...@@ -17,9 +19,9 @@ class MessageService : JobService() {
@Inject @Inject
lateinit var factory: ConnectionManagerFactory lateinit var factory: ConnectionManagerFactory
@Inject @Inject
lateinit var currentServerRepository: CurrentServerRepository lateinit var dbFactory: DatabaseManagerFactory
@Inject @Inject
lateinit var messageRepository: MessagesRepository lateinit var getAccountsInteractor: GetAccountsInteractor
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
...@@ -32,21 +34,21 @@ class MessageService : JobService() { ...@@ -32,21 +34,21 @@ class MessageService : JobService() {
override fun onStartJob(params: JobParameters?): Boolean { override fun onStartJob(params: JobParameters?): Boolean {
launch(CommonPool) { launch(CommonPool) {
val currentServer = currentServerRepository.get() getAccountsInteractor.get().forEach { account ->
if (currentServer != null) { retrySendingMessages(params, account.serverUrl)
retrySendingMessages(params, currentServer)
jobFinished(params, false)
} }
jobFinished(params, false)
} }
return true return true
} }
private suspend fun retrySendingMessages(params: JobParameters?, currentServer: String) { private suspend fun retrySendingMessages(params: JobParameters?, serverUrl: String) {
val dbManager = dbFactory.create(serverUrl)
val messageRepository = DatabaseMessagesRepository(dbManager, DatabaseMessageMapper())
val temporaryMessages = messageRepository.getAllUnsent() val temporaryMessages = messageRepository.getAllUnsent()
.sortedWith(compareBy(Message::timestamp)) .sortedWith(compareBy(Message::timestamp))
if (temporaryMessages.isNotEmpty()) { if (temporaryMessages.isNotEmpty()) {
val connectionManager = factory.create(currentServer) val client = factory.create(serverUrl).client
val client = connectionManager.client
temporaryMessages.forEach { message -> temporaryMessages.forEach { message ->
try { try {
client.sendMessage( client.sendMessage(
...@@ -57,7 +59,7 @@ class MessageService : JobService() { ...@@ -57,7 +59,7 @@ class MessageService : JobService() {
attachments = message.attachments, attachments = message.attachments,
alias = message.senderAlias alias = message.senderAlias
) )
messageRepository.save(message.copy(isTemporary = false)) messageRepository.save(message.copy(synced = true))
Timber.d("Sent scheduled message given by id: ${message.id}") Timber.d("Sent scheduled message given by id: ${message.id}")
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.e(ex) Timber.e(ex)
...@@ -71,7 +73,7 @@ class MessageService : JobService() { ...@@ -71,7 +73,7 @@ class MessageService : JobService() {
// some other error // some other error
if (ex.message?.contains("E11000", true) == true) { if (ex.message?.contains("E11000", true) == true) {
// XXX: Temporary solution. We need proper error codes from the api. // XXX: Temporary solution. We need proper error codes from the api.
messageRepository.save(message.copy(isTemporary = false)) messageRepository.save(message.copy(synced = false))
} }
jobFinished(params, true) jobFinished(params, true)
} }
......
...@@ -545,9 +545,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -545,9 +545,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun dispatchUpdateMessage(index: Int, message: List<BaseUiModel<*>>) { override fun dispatchUpdateMessage(index: Int, message: List<BaseUiModel<*>>) {
ui { ui {
adapter.updateItem(message.last()) if (adapter.updateItem(message.last())) {
if (message.size > 1) { if (message.size > 1) {
adapter.prependData(listOf(message.first())) adapter.prependData(listOf(message.first()))
}
} else {
showNewMessage(message, true)
} }
} }
} }
......
...@@ -477,7 +477,7 @@ class UiModelMapper @Inject constructor( ...@@ -477,7 +477,7 @@ class UiModelMapper @Inject constructor(
val time = getTime(message.timestamp) val time = getTime(message.timestamp)
val avatar = getUserAvatar(message) val avatar = getUserAvatar(message)
val preview = mapMessagePreview(message) val preview = mapMessagePreview(message)
val isTemp = message.isTemporary ?: false val synced = message.synced ?: true
val unread = if (settings.messageReadReceiptEnabled()) { val unread = if (settings.messageReadReceiptEnabled()) {
message.unread ?: false message.unread ?: false
} else { } else {
...@@ -492,7 +492,7 @@ class UiModelMapper @Inject constructor( ...@@ -492,7 +492,7 @@ class UiModelMapper @Inject constructor(
messageId = message.id, avatar = avatar!!, time = time, senderName = sender, messageId = message.id, avatar = avatar!!, time = time, senderName = sender,
content = content, isPinned = message.pinned, currentDayMarkerText = dayMarkerText, content = content, isPinned = message.pinned, currentDayMarkerText = dayMarkerText,
showDayMarker = false, reactions = getReactions(message), isFirstUnread = false, showDayMarker = false, reactions = getReactions(message), isFirstUnread = false,
preview = preview, isTemporary = isTemp, unread = unread) preview = preview, isTemporary = !synced, unread = unread)
} }
private fun mapMessagePreview(message: Message): Message { private fun mapMessagePreview(message: Message): Message {
......
...@@ -43,6 +43,8 @@ import chat.rocket.android.server.domain.RoomRepository ...@@ -43,6 +43,8 @@ import chat.rocket.android.server.domain.RoomRepository
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
import chat.rocket.android.server.domain.UsersRepository import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.infraestructure.DatabaseMessageMapper
import chat.rocket.android.server.infraestructure.DatabaseMessagesRepository
import chat.rocket.android.server.infraestructure.JobSchedulerInteractorImpl import chat.rocket.android.server.infraestructure.JobSchedulerInteractorImpl
import chat.rocket.android.server.infraestructure.MemoryActiveUsersRepository import chat.rocket.android.server.infraestructure.MemoryActiveUsersRepository
import chat.rocket.android.server.infraestructure.MemoryChatRoomsRepository import chat.rocket.android.server.infraestructure.MemoryChatRoomsRepository
...@@ -253,7 +255,7 @@ class AppModule { ...@@ -253,7 +255,7 @@ class AppModule {
return SharedPreferencesMultiServerTokenRepository(repository, moshi) return SharedPreferencesMultiServerTokenRepository(repository, moshi)
} }
@Provides /*@Provides
@Singleton @Singleton
fun provideMessageRepository( fun provideMessageRepository(
@ForMessages preferences: SharedPreferences, @ForMessages preferences: SharedPreferences,
...@@ -261,6 +263,11 @@ class AppModule { ...@@ -261,6 +263,11 @@ class AppModule {
currentServerInteractor: GetCurrentServerInteractor currentServerInteractor: GetCurrentServerInteractor
): MessagesRepository { ): MessagesRepository {
return SharedPreferencesMessagesRepository(preferences, moshi, currentServerInteractor) return SharedPreferencesMessagesRepository(preferences, moshi, currentServerInteractor)
}*/
@Provides
fun provideMessageRepository(databaseManager: DatabaseManager): MessagesRepository {
return DatabaseMessagesRepository(databaseManager, DatabaseMessageMapper())
} }
@Provides @Provides
......
...@@ -5,12 +5,11 @@ import chat.rocket.android.R ...@@ -5,12 +5,11 @@ import chat.rocket.android.R
import chat.rocket.android.db.model.BaseMessageEntity import chat.rocket.android.db.model.BaseMessageEntity
import chat.rocket.android.db.model.BaseUserEntity import chat.rocket.android.db.model.BaseUserEntity
import chat.rocket.android.db.model.ChatRoomEntity import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.MessageChannelsRelation import chat.rocket.android.db.model.MessageChannels
import chat.rocket.android.db.model.MessageEntity import chat.rocket.android.db.model.MessageEntity
import chat.rocket.android.db.model.MessageFavoritesRelation import chat.rocket.android.db.model.MessageFavoritesRelation
import chat.rocket.android.db.model.MessageMentionsRelation import chat.rocket.android.db.model.MessageMentionsRelation
import chat.rocket.android.db.model.ReactionEntity import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.ReactionMessageRelation
import chat.rocket.android.db.model.UrlEntity import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.db.model.UserStatus import chat.rocket.android.db.model.UserStatus
...@@ -31,6 +30,7 @@ import chat.rocket.core.model.Myself ...@@ -31,6 +30,7 @@ import chat.rocket.core.model.Myself
import chat.rocket.core.model.Room import chat.rocket.core.model.Room
import chat.rocket.core.model.attachment.Attachment import chat.rocket.core.model.attachment.Attachment
import chat.rocket.core.model.userId import chat.rocket.core.model.userId
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.newSingleThreadContext import kotlinx.coroutines.experimental.newSingleThreadContext
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
...@@ -44,7 +44,7 @@ class DatabaseManager(val context: Application, ...@@ -44,7 +44,7 @@ class DatabaseManager(val context: Application,
RCDatabase::class.java, serverUrl.databaseName()) RCDatabase::class.java, serverUrl.databaseName())
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration()
.build() .build()
private val dbContext = newSingleThreadContext("$serverUrl-db-context") val dbContext = newSingleThreadContext("$serverUrl-db-context")
private val insertSubs = HashMap<String, Subscription>() private val insertSubs = HashMap<String, Subscription>()
private val insertRooms = HashMap<String, Room>() private val insertRooms = HashMap<String, Room>()
...@@ -58,6 +58,11 @@ class DatabaseManager(val context: Application, ...@@ -58,6 +58,11 @@ class DatabaseManager(val context: Application,
fun clearUsersStatus() { fun clearUsersStatus() {
launch(dbContext) { launch(dbContext) {
userDao().clearStatus() userDao().clearStatus()
val message = messageDao().getMessageById("Ne6Wm9LqvZuBFiyME")
message?.let {
Timber.d("MESSAGE FROM DB: $it")
}
} }
} }
...@@ -153,8 +158,8 @@ class DatabaseManager(val context: Application, ...@@ -153,8 +158,8 @@ class DatabaseManager(val context: Application,
} }
} }
fun processMessagesBatch(messages: List<Message>) { fun processMessagesBatch(messages: List<Message>): Job {
launch(dbContext) { return launch(dbContext) {
val dao = messageDao() val dao = messageDao()
val list = mutableListOf<Pair<MessageEntity, List<BaseMessageEntity>>>() val list = mutableListOf<Pair<MessageEntity, List<BaseMessageEntity>>>()
messages.forEach { message -> messages.forEach { message ->
...@@ -190,11 +195,9 @@ class DatabaseManager(val context: Application, ...@@ -190,11 +195,9 @@ class DatabaseManager(val context: Application,
val list = mutableListOf<BaseMessageEntity>() val list = mutableListOf<BaseMessageEntity>()
reactions.keys.forEach { reaction -> reactions.keys.forEach { reaction ->
list.add(ReactionEntity(reaction))
val users = reactions[reaction] val users = reactions[reaction]
users?.size?.let { size -> users?.let { users ->
list.add(ReactionMessageRelation(reaction, message.id, size)) list.add(ReactionEntity(reaction, message.id, users.size, users.joinToString()))
} }
} }
...@@ -220,9 +223,9 @@ class DatabaseManager(val context: Application, ...@@ -220,9 +223,9 @@ class DatabaseManager(val context: Application,
return null return null
} }
val list = mutableListOf<MessageChannelsRelation>() val list = mutableListOf<MessageChannels>()
message.channels!!.forEach { channel -> message.channels!!.forEach { channel ->
list.add(MessageChannelsRelation(message.id, channel.id, channel.name)) list.add(MessageChannels(message.id, channel.id, channel.name))
} }
return list return list
......
package chat.rocket.android.db
import chat.rocket.android.infrastructure.MessagesRepository
import chat.rocket.core.model.Message
class DatabaseMessagesRepository(val dbManager: DatabaseManager) : MessagesRepository {
override fun saveMessage(message: Message) {
saveMessages(listOf(message))
}
override fun saveMessages(messages: List<Message>) {
messages.forEach { message ->
}
}
}
\ No newline at end of file
...@@ -8,15 +8,17 @@ import androidx.room.Transaction ...@@ -8,15 +8,17 @@ import androidx.room.Transaction
import chat.rocket.android.db.model.AttachmentEntity import chat.rocket.android.db.model.AttachmentEntity
import chat.rocket.android.db.model.AttachmentFieldEntity import chat.rocket.android.db.model.AttachmentFieldEntity
import chat.rocket.android.db.model.BaseMessageEntity import chat.rocket.android.db.model.BaseMessageEntity
import chat.rocket.android.db.model.MessageChannelsRelation import chat.rocket.android.db.model.FullMessage
import chat.rocket.android.db.model.PartialMessage
import chat.rocket.android.db.model.MessageChannels
import chat.rocket.android.db.model.MessageEntity import chat.rocket.android.db.model.MessageEntity
import chat.rocket.android.db.model.MessageFavoritesRelation import chat.rocket.android.db.model.MessageFavoritesRelation
import chat.rocket.android.db.model.MessageMentionsRelation import chat.rocket.android.db.model.MessageMentionsRelation
import chat.rocket.android.db.model.MessagesSync
import chat.rocket.android.db.model.ReactionEntity import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.ReactionMessageRelation
import chat.rocket.android.db.model.UrlEntity import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity
import timber.log.Timber import timber.log.Timber
@Dao @Dao
abstract class MessageDao { abstract class MessageDao {
@Insert @Insert
...@@ -29,7 +31,7 @@ abstract class MessageDao { ...@@ -29,7 +31,7 @@ abstract class MessageDao {
abstract fun insert(relation: MessageMentionsRelation) abstract fun insert(relation: MessageMentionsRelation)
@Insert @Insert
abstract fun insert(relation: MessageChannelsRelation) abstract fun insert(relation: MessageChannels)
@Insert @Insert
abstract fun insert(attachment: AttachmentEntity) abstract fun insert(attachment: AttachmentEntity)
...@@ -40,15 +42,15 @@ abstract class MessageDao { ...@@ -40,15 +42,15 @@ abstract class MessageDao {
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
abstract fun insert(reaction: ReactionEntity) abstract fun insert(reaction: ReactionEntity)
@Insert
abstract fun insert(relation: ReactionMessageRelation)
@Insert @Insert
abstract fun insert(url: UrlEntity) abstract fun insert(url: UrlEntity)
@Query("DELETE FROM messages WHERE id = :id") @Query("DELETE FROM messages WHERE id = :id")
abstract fun delete(id: String) abstract fun delete(id: String)
@Query("DELETE FROM messages WHERE roomId = :roomId")
abstract fun deleteByRoomId(roomId: String)
@Transaction @Transaction
open fun insert(message: MessageEntity, entities: List<BaseMessageEntity>) { open fun insert(message: MessageEntity, entities: List<BaseMessageEntity>) {
insertInternal(message, entities) insertInternal(message, entities)
...@@ -68,11 +70,10 @@ abstract class MessageDao { ...@@ -68,11 +70,10 @@ abstract class MessageDao {
is MessageEntity -> insert(entity) is MessageEntity -> insert(entity)
is MessageFavoritesRelation -> insert(entity) is MessageFavoritesRelation -> insert(entity)
is MessageMentionsRelation -> insert(entity) is MessageMentionsRelation -> insert(entity)
is MessageChannelsRelation -> insert(entity) is MessageChannels -> insert(entity)
is AttachmentEntity -> insert(entity) is AttachmentEntity -> insert(entity)
is AttachmentFieldEntity -> insert(entity) is AttachmentFieldEntity -> insert(entity)
is ReactionEntity -> insert(entity) is ReactionEntity -> insert(entity)
is ReactionMessageRelation -> insert(entity)
is UrlEntity -> insert(entity) is UrlEntity -> insert(entity)
} }
} }
...@@ -83,4 +84,105 @@ abstract class MessageDao { ...@@ -83,4 +84,105 @@ abstract class MessageDao {
insertInternal(message, entities) insertInternal(message, entities)
} }
} }
//@Query("SELECT * FROM messages WHERE id = :id")
@Query("""
$BASE_MESSAGE_QUERY
WHERE messages.id = :id
""")
abstract fun internalGetMessageById(id: String): PartialMessage?
@Transaction
open fun getMessageById(id: String): FullMessage? {
return internalGetMessageById(id)?.let { message ->
retrieveFullMessage(message)
}
}
@Query("""
$BASE_MESSAGE_QUERY
WHERE messages.roomId = :roomId
ORDER BY messages.timestamp DESC
"""
)
abstract fun internalGetMessagesByRoomId(roomId: String): List<PartialMessage>
@Query("""
$BASE_MESSAGE_QUERY
WHERE messages.roomId = :roomId
ORDER BY messages.timestamp DESC
LIMIT :count
"""
)
abstract fun internalGetRecentMessagesByRoomId(roomId: String, count: Long): List<PartialMessage>
@Transaction
open fun getMessagesByRoomId(roomId: String): List<FullMessage> {
return internalGetMessagesByRoomId(roomId).map { message ->
retrieveFullMessage(message)
}
}
@Transaction
open fun getRecentMessagesByRoomId(roomId: String, count: Long): List<FullMessage> {
return internalGetRecentMessagesByRoomId(roomId, count).map { message ->
retrieveFullMessage(message)
}
}
@Query("""
SELECT * FROM users WHERE users.id IN
(SELECT userId FROM message_favorites WHERE messageId = :messageId)
""")
abstract fun getFavoritesByMessage(messageId: String): List<UserEntity>
@Query("""
SELECT * FROM users WHERE users.id IN
(SELECT userId FROM message_mentions WHERE messageId = :messageId)
""")
abstract fun getMentionsByMessage(messageId: String): List<UserEntity>
@Query("""
$BASE_MESSAGE_QUERY
WHERE synced = 0
ORDER BY messages.timestamp DESC
""")
abstract fun internalUnsetMessages(): List<PartialMessage>
@Transaction
open fun getUnsentMessages(): List<FullMessage> {
return internalUnsetMessages().map { message ->
retrieveFullMessage(message)
}
}
internal fun retrieveFullMessage(message: PartialMessage): FullMessage {
val favorites = getFavoritesByMessage(message.message.id)
val mentions = getFavoritesByMessage(message.message.id)
return FullMessage(message, favorites, mentions)
}
@Query("SELECT * FROM messages_sync WHERE roomId = :roomId")
abstract fun getLastSync(roomId: String): MessagesSync?
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun saveLastSync(entity: MessagesSync)
companion object {
const val BASE_MESSAGE_QUERY = """
SELECT
messages.*,
senderBy.name as senderName,
senderBy.username as senderUsername,
editBy.name as editName,
editBy.username as editUsername
FROM messages
LEFT JOIN urls as u ON u.messageId = messages.id
LEFT JOIN attachments as attachment ON attachment.message_id = messages.id
LEFT JOIN reactions ON reactions.messageId = messages.id
LEFT JOIN message_channels ON message_channels.messageId = messages.id
LEFT JOIN users as senderBy ON messages.senderId = senderBy.id
LEFT JOIN users as editBy ON messages.editedBy = editBy.id
"""
}
} }
\ No newline at end of file
...@@ -5,12 +5,12 @@ import androidx.room.RoomDatabase ...@@ -5,12 +5,12 @@ import androidx.room.RoomDatabase
import chat.rocket.android.db.model.AttachmentEntity import chat.rocket.android.db.model.AttachmentEntity
import chat.rocket.android.db.model.AttachmentFieldEntity import chat.rocket.android.db.model.AttachmentFieldEntity
import chat.rocket.android.db.model.ChatRoomEntity import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.MessageChannelsRelation import chat.rocket.android.db.model.MessageChannels
import chat.rocket.android.db.model.MessageEntity import chat.rocket.android.db.model.MessageEntity
import chat.rocket.android.db.model.MessageFavoritesRelation import chat.rocket.android.db.model.MessageFavoritesRelation
import chat.rocket.android.db.model.MessageMentionsRelation import chat.rocket.android.db.model.MessageMentionsRelation
import chat.rocket.android.db.model.MessagesSync
import chat.rocket.android.db.model.ReactionEntity import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.ReactionMessageRelation
import chat.rocket.android.db.model.UrlEntity import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
...@@ -18,11 +18,11 @@ import chat.rocket.android.db.model.UserEntity ...@@ -18,11 +18,11 @@ import chat.rocket.android.db.model.UserEntity
entities = [ entities = [
UserEntity::class, ChatRoomEntity::class, MessageEntity::class, UserEntity::class, ChatRoomEntity::class, MessageEntity::class,
MessageFavoritesRelation::class, MessageMentionsRelation::class, MessageFavoritesRelation::class, MessageMentionsRelation::class,
MessageChannelsRelation::class, AttachmentEntity::class, MessageChannels::class, AttachmentEntity::class,
AttachmentFieldEntity::class, UrlEntity::class, ReactionEntity::class, AttachmentFieldEntity::class, UrlEntity::class, ReactionEntity::class,
ReactionMessageRelation::class MessagesSync::class
], ],
version = 6, version = 7,
exportSchema = true exportSchema = true
) )
abstract class RCDatabase : RoomDatabase() { abstract class RCDatabase : RoomDatabase() {
......
...@@ -21,7 +21,7 @@ import timber.log.Timber ...@@ -21,7 +21,7 @@ import timber.log.Timber
]) ])
data class AttachmentEntity( data class AttachmentEntity(
@PrimaryKey @PrimaryKey
var id: String, var _id: String,
@ColumnInfo(name = "message_id") @ColumnInfo(name = "message_id")
val messageId: String, val messageId: String,
val title: String? = null, val title: String? = null,
...@@ -66,7 +66,7 @@ data class AttachmentEntity( ...@@ -66,7 +66,7 @@ data class AttachmentEntity(
@Entity(tableName = "attachment_fields", @Entity(tableName = "attachment_fields",
foreignKeys = [ foreignKeys = [
ForeignKey(entity = AttachmentEntity::class, parentColumns = ["id"], ForeignKey(entity = AttachmentEntity::class, parentColumns = ["_id"],
childColumns = ["attachmentId"], onDelete = ForeignKey.CASCADE) childColumns = ["attachmentId"], onDelete = ForeignKey.CASCADE)
]) ])
data class AttachmentFieldEntity( data class AttachmentFieldEntity(
...@@ -96,7 +96,7 @@ fun Attachment.asEntity(msgId: String): List<BaseMessageEntity> { ...@@ -96,7 +96,7 @@ fun Attachment.asEntity(msgId: String): List<BaseMessageEntity> {
fun ImageAttachment.asEntity(msgId: String): AttachmentEntity = fun ImageAttachment.asEntity(msgId: String): AttachmentEntity =
AttachmentEntity( AttachmentEntity(
id = "${msgId}_${hashCode()}", _id = "${msgId}_${hashCode()}",
messageId = msgId, messageId = msgId,
title = title, title = title,
description = description, description = description,
...@@ -110,7 +110,7 @@ fun ImageAttachment.asEntity(msgId: String): AttachmentEntity = ...@@ -110,7 +110,7 @@ fun ImageAttachment.asEntity(msgId: String): AttachmentEntity =
fun VideoAttachment.asEntity(msgId: String): AttachmentEntity = fun VideoAttachment.asEntity(msgId: String): AttachmentEntity =
AttachmentEntity( AttachmentEntity(
id = "${msgId}_${hashCode()}", _id = "${msgId}_${hashCode()}",
messageId = msgId, messageId = msgId,
title = title, title = title,
description = description, description = description,
...@@ -124,7 +124,7 @@ fun VideoAttachment.asEntity(msgId: String): AttachmentEntity = ...@@ -124,7 +124,7 @@ fun VideoAttachment.asEntity(msgId: String): AttachmentEntity =
fun AudioAttachment.asEntity(msgId: String): AttachmentEntity = fun AudioAttachment.asEntity(msgId: String): AttachmentEntity =
AttachmentEntity( AttachmentEntity(
id = "${msgId}_${hashCode()}", _id = "${msgId}_${hashCode()}",
messageId = msgId, messageId = msgId,
title = title, title = title,
description = description, description = description,
...@@ -139,7 +139,7 @@ fun AudioAttachment.asEntity(msgId: String): AttachmentEntity = ...@@ -139,7 +139,7 @@ fun AudioAttachment.asEntity(msgId: String): AttachmentEntity =
fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> { fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
val list = mutableListOf<BaseMessageEntity>() val list = mutableListOf<BaseMessageEntity>()
val attachment = AttachmentEntity( val attachment = AttachmentEntity(
id = "${msgId}_${hashCode()}", _id = "${msgId}_${hashCode()}",
messageId = msgId, messageId = msgId,
authorLink = url, authorLink = url,
authorIcon = authorIcon, authorIcon = authorIcon,
...@@ -149,7 +149,7 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> { ...@@ -149,7 +149,7 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
fields?.forEach { field -> fields?.forEach { field ->
val entity = AttachmentFieldEntity( val entity = AttachmentFieldEntity(
attachmentId = attachment.id, attachmentId = attachment._id,
title = field.title, title = field.title,
value = field.value value = field.value
) )
...@@ -161,7 +161,7 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> { ...@@ -161,7 +161,7 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
fun ColorAttachment.asEntity(msgId: String): AttachmentEntity = fun ColorAttachment.asEntity(msgId: String): AttachmentEntity =
AttachmentEntity( AttachmentEntity(
id = "${msgId}_${hashCode()}", _id = "${msgId}_${hashCode()}",
messageId = msgId, messageId = msgId,
color = color.rawColor color = color.rawColor
) )
...@@ -169,7 +169,7 @@ fun ColorAttachment.asEntity(msgId: String): AttachmentEntity = ...@@ -169,7 +169,7 @@ fun ColorAttachment.asEntity(msgId: String): AttachmentEntity =
// TODO - how to model An message attachment with attachments??? // TODO - how to model An message attachment with attachments???
fun MessageAttachment.asEntity(msgId: String): AttachmentEntity = fun MessageAttachment.asEntity(msgId: String): AttachmentEntity =
AttachmentEntity( AttachmentEntity(
id = "${msgId}_${hashCode()}", _id = "${msgId}_${hashCode()}",
messageId = msgId, messageId = msgId,
authorName = author, authorName = author,
authorIcon = icon, authorIcon = icon,
......
package chat.rocket.android.db.model package chat.rocket.android.db.model
import androidx.room.Embedded
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import androidx.room.Relation
interface BaseMessageEntity interface BaseMessageEntity
...@@ -26,7 +28,9 @@ data class MessageEntity( ...@@ -26,7 +28,9 @@ data class MessageEntity(
val groupable: Boolean = false, val groupable: Boolean = false,
val parseUrls: Boolean = false, val parseUrls: Boolean = false,
val pinned: Boolean = false, val pinned: Boolean = false,
val role: String? val role: String?,
val synced: Boolean = true,
val unread: Boolean? = null
) : BaseMessageEntity ) : BaseMessageEntity
@Entity(tableName = "message_favorites", @Entity(tableName = "message_favorites",
...@@ -60,8 +64,43 @@ data class MessageMentionsRelation( ...@@ -60,8 +64,43 @@ data class MessageMentionsRelation(
childColumns = ["messageId"], onDelete = ForeignKey.CASCADE) childColumns = ["messageId"], onDelete = ForeignKey.CASCADE)
] ]
) )
data class MessageChannelsRelation( data class MessageChannels(
val messageId: String, val messageId: String,
val roomId: String, val roomId: String,
val roomName: String? val roomName: String?
) : BaseMessageEntity ) : BaseMessageEntity
@Entity(tableName = "messages_sync")
data class MessagesSync(
@PrimaryKey val roomId: String,
val timestamp: Long
)
data class PartialMessage(
@Embedded val message: MessageEntity,
val senderName: String?,
val senderUsername: String?,
val editName: String?,
val editUsername: String?
) {
@Relation(parentColumn = "id", entityColumn = "messageId")
var urls: List<UrlEntity>? = null
@Relation(parentColumn = "id", entityColumn = "message_id")
var attachments: List<AttachmentEntity>? = null
@Relation(parentColumn = "id", entityColumn = "messageId")
var reactions: List<ReactionEntity>? = null
@Relation(parentColumn = "id", entityColumn = "messageId")
var channels: List<MessageChannels>? = null
override fun toString(): String {
return "PartialMessage(message=$message, senderName=$senderName, senderUsername=$senderUsername, editName=$editName, editUsername=$editUsername, urls=$urls, attachments=$attachments, reactions=$reactions, channels=$channels)"
}
}
data class FullMessage(
val message: PartialMessage,
val favorites: List<UserEntity>,
val mentions: List<UserEntity>
)
...@@ -5,15 +5,8 @@ import androidx.room.ForeignKey ...@@ -5,15 +5,8 @@ import androidx.room.ForeignKey
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "reactions") @Entity(tableName = "reactions",
data class ReactionEntity(
@PrimaryKey val reaction: String
) : BaseMessageEntity
@Entity(tableName = "reactions_message_relations",
foreignKeys = [ foreignKeys = [
ForeignKey(entity = ReactionEntity::class, parentColumns = ["reaction"],
childColumns = ["reactionId"]),
ForeignKey(entity = MessageEntity::class, parentColumns = ["id"], ForeignKey(entity = MessageEntity::class, parentColumns = ["id"],
childColumns = ["messageId"], onDelete = ForeignKey.CASCADE) childColumns = ["messageId"], onDelete = ForeignKey.CASCADE)
], ],
...@@ -21,11 +14,9 @@ data class ReactionEntity( ...@@ -21,11 +14,9 @@ data class ReactionEntity(
Index(value = ["messageId"]) Index(value = ["messageId"])
] ]
) )
data class ReactionMessageRelation( data class ReactionEntity(
val reactionId: String, @PrimaryKey val reaction: String,
val messageId: String, val messageId: String,
val count: Int val count: Int,
) : BaseMessageEntity { val usernames: String
@PrimaryKey(autoGenerate = true) ) : BaseMessageEntity
var id: Long? = null \ No newline at end of file
}
\ No newline at end of file
...@@ -22,5 +22,5 @@ data class UrlEntity( ...@@ -22,5 +22,5 @@ data class UrlEntity(
val imageUrl: String? val imageUrl: String?
) : BaseMessageEntity { ) : BaseMessageEntity {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long? = null var urlId: Long? = null
} }
\ No newline at end of file
package chat.rocket.android.infrastructure
import chat.rocket.core.model.Message
interface MessagesRepository {
fun saveMessage(message: Message)
fun saveMessages(messages: List<Message>)
}
\ No newline at end of file
...@@ -16,27 +16,20 @@ interface MessagesRepository { ...@@ -16,27 +16,20 @@ interface MessagesRepository {
/** /**
* Get all messages from the current room id. * Get all messages from the current room id.
* *
* @param rid The room id. * @param roomId The room id.
* @return A list of Message objects for the room with given room id or an empty list. * @return A list of Message objects for the room with given room id or an empty list.
*/ */
suspend fun getByRoomId(rid: String): List<Message> suspend fun getByRoomId(roomId: String): List<Message>
/** /**
* Get most recent messages up to count different users. * Get most recent messages up to count different users.
* *
* @param rid The id of the room the messages are. * @param roomId The id of the room the messages are.
* @param count The count last messages to get. * @param count The count last messages to get.
* *
* @return List of last count messages. * @return List of last count messages.
*/ */
suspend fun getRecentMessages(rid: String, count: Long): List<Message> suspend fun getRecentMessages(roomId: String, count: Long): List<Message>
/**
* Get all messages. Use carefully!
*
* @return All messages or an empty list.
*/
suspend fun getAll(): List<Message>
/** /**
* Save a single message object. * Save a single message object.
...@@ -50,11 +43,6 @@ interface MessagesRepository { ...@@ -50,11 +43,6 @@ interface MessagesRepository {
*/ */
suspend fun saveAll(newMessages: List<Message>) suspend fun saveAll(newMessages: List<Message>)
/**
* Removes all messages.
*/
suspend fun clear()
/** /**
* Remove message by id. * Remove message by id.
* *
...@@ -65,29 +53,27 @@ interface MessagesRepository { ...@@ -65,29 +53,27 @@ interface MessagesRepository {
/** /**
* Remove all messages from a given room. * Remove all messages from a given room.
* *
* @param rid The room id where messages are to be removed. * @param roomId The room id where messages are to be removed.
*/ */
suspend fun removeByRoomId(rid: String) suspend fun removeByRoomId(roomId: String)
suspend fun getAllUnsent(): List<Message> suspend fun getAllUnsent(): List<Message>
suspend fun getUnsentByRoomId(roomId: String): List<Message>
/** /**
* Save time of the latest room messages sync. * Save time of the latest room messages sync.
* Call this fun only when the latest messages list being received via /history or /messages network calls * Call this fun only when the latest messages list being received via /history or /messages network calls
* *
* @param rid The id of the room the messages are. * @param roomId The id of the room the messages are.
* @param timeMillis time of room messages sync or the latest room message timestamp(which came with /history request) * @param timeMillis time of room messages sync or the latest room message timestamp(which came with /history request)
*/ */
suspend fun saveLastSyncDate(rid: String, timeMillis: Long) suspend fun saveLastSyncDate(roomId: String, timeMillis: Long)
/** /**
* Get time when the room chat history has been loaded last time. * Get time when the room chat history has been loaded last time.
* *
* @param rid The id of the room the messages are. * @param roomId The id of the room the messages are.
* *
* @return Last Sync time or Null. * @return Last Sync time or Null.
*/ */
suspend fun getLastSyncDate(rid: String): Long? suspend fun getLastSyncDate(roomId: String): Long?
} }
\ No newline at end of file
...@@ -133,6 +133,13 @@ class ConnectionManager( ...@@ -133,6 +133,13 @@ class ConnectionManager(
maxSize = 100, maxTime = 500) { messages -> maxSize = 100, maxTime = 500) { messages ->
Timber.d("Processing Messages batch: ${messages.size}") Timber.d("Processing Messages batch: ${messages.size}")
dbManager.processMessagesBatch(messages.distinctBy { it.id }) dbManager.processMessagesBatch(messages.distinctBy { it.id })
launch {
messages.forEach { message ->
val channel = roomMessagesChannels[message.roomId]
channel?.send(message)
}
}
} }
// stream-notify-user - ${userId}/rooms-changed // stream-notify-user - ${userId}/rooms-changed
...@@ -161,8 +168,6 @@ class ConnectionManager( ...@@ -161,8 +168,6 @@ class ConnectionManager(
for (message in client.messagesChannel) { for (message in client.messagesChannel) {
Timber.d("Received new Message for room ${message.roomId}") Timber.d("Received new Message for room ${message.roomId}")
messagesActor.send(message) messagesActor.send(message)
val channel = roomMessagesChannels[message.roomId]
channel?.send(message)
} }
} }
......
package chat.rocket.android.server.infraestructure
import chat.rocket.android.db.model.AttachmentEntity
import chat.rocket.android.db.model.FullMessage
import chat.rocket.android.db.model.ReactionEntity
import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.common.model.SimpleRoom
import chat.rocket.common.model.SimpleUser
import chat.rocket.core.model.Message
import chat.rocket.core.model.Reactions
import chat.rocket.core.model.attachment.Attachment
import chat.rocket.core.model.messageTypeOf
import chat.rocket.core.model.url.Meta
import chat.rocket.core.model.url.ParsedUrl
import chat.rocket.core.model.url.Url
class DatabaseMessageMapper {
fun map(message: FullMessage): Message? = map(listOf(message)).firstOrNull()
fun map(messages: List<FullMessage>): List<Message> {
val list = mutableListOf<Message>()
messages.forEach { message ->
val favorites = mutableListOf<SimpleUser>()
message.favorites.forEach { user ->
favorites.add(mapUser(user))
}
val mentions = mutableListOf<SimpleUser>()
message.mentions.forEach { user ->
mentions.add(mapUser(user))
}
val channels = mutableListOf<SimpleRoom>()
message.message.channels?.forEach { channel ->
channels.add(SimpleRoom(channel.roomId, channel.roomName))
}
with(message.message) {
val sender = this.message.senderId?.let { id ->
SimpleUser(id, this.senderUsername, this.senderName)
}
val editedBy = this.message.editedBy?.let { id ->
SimpleUser(id, this.editUsername, this.editName)
}
val urls = this.urls?.let { mapUrl(it) }
val reactions = this.reactions?.let { mapReactions(it) }
val attachments = this.attachments?.let { mapAttachments(it) }
val messageType = messageTypeOf(this.message.type)
list.add(Message(
id = this.message.id,
roomId = this.message.roomId,
message = this.message.message,
timestamp = this.message.timestamp,
sender = sender,
updatedAt = this.message.updatedAt,
editedAt = this.message.editedAt,
editedBy = editedBy,
senderAlias = this.message.senderAlias,
avatar = this.message.avatar,
type = messageType,
groupable = this.message.groupable,
parseUrls = this.message.parseUrls,
urls = urls,
mentions = mentions,
channels = channels,
attachments = attachments,
pinned = this.message.pinned,
starred = favorites,
reactions = reactions,
role = this.message.role,
synced = this.message.synced,
unread = this.message.unread
))
}
}
return list
}
private fun mapReactions(reactions: List<ReactionEntity>): Reactions {
val map = Reactions()
reactions.forEach { reaction ->
val usernames = reaction.usernames.split(",").map { it.trim() }
map[reaction.reaction] = usernames
}
return map
}
private fun mapUrl(urls: List<UrlEntity>): List<Url> {
val list = mutableListOf<Url>()
urls.forEach { url ->
val parsedUrl = url.hostname?.let {
ParsedUrl(host = it)
}
val meta = if (!url.description.isNullOrEmpty() || !url.imageUrl.isNullOrEmpty() || !url.title.isNullOrEmpty()) {
val raw = HashMap<String, String>()
if (url.description != null) raw["ogDescription"] = url.description
if (url.title != null) raw["ogTitle"] = url.title
if (url.imageUrl != null) raw["ogImage"] = url.imageUrl
Meta(title = url.title,description = url.description, imageUrl = url.imageUrl, raw = raw)
} else null
list.add(Url(url = url.url, meta = meta, parsedUrl = parsedUrl))
}
return list
}
private fun mapUser(user: UserEntity): SimpleUser {
return with(user) {
SimpleUser(
id = id,
username = username,
name = name
)
}
}
private fun mapAttachments(attachments: List<AttachmentEntity>): List<Attachment> {
val list = mutableListOf<Attachment>()
attachments.forEach { attachment ->
}
// TODO - implement mapping
return list
}
}
\ No newline at end of file
package chat.rocket.android.server.infraestructure
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.model.MessagesSync
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.core.model.Message
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext
class DatabaseMessagesRepository(
private val dbManager: DatabaseManager,
private val mapper: DatabaseMessageMapper
) : MessagesRepository {
override suspend fun getById(id: String): Message? = withContext(CommonPool) {
dbManager.messageDao().getMessageById(id)?.let { message -> mapper.map(message) }
}
override suspend fun getByRoomId(roomId: String): List<Message> = withContext(CommonPool) {
// FIXME - investigate how to avoid this distinctBy here, since DAO is returning a lot of
// duplicate rows (something related to our JOINS and relations on Room)
dbManager.messageDao().getMessagesByRoomId(roomId)
.distinctBy { it.message.message.id }
.let { messages ->
mapper.map(messages)
}
}
override suspend fun getRecentMessages(roomId: String, count: Long): List<Message> = withContext(CommonPool) {
dbManager.messageDao().getRecentMessagesByRoomId(roomId, count)
.distinctBy { it.message.message.id }
.let { messages ->
mapper.map(messages)
}
}
override suspend fun save(message: Message) {
dbManager.processMessagesBatch(listOf(message)).join()
}
override suspend fun saveAll(messages: List<Message>) {
dbManager.processMessagesBatch(messages).join()
}
override suspend fun removeById(id: String) {
withContext(CommonPool) {
dbManager.messageDao().delete(id)
}
}
override suspend fun removeByRoomId(roomId: String) {
withContext(CommonPool) {
dbManager.messageDao().deleteByRoomId(roomId)
}
}
override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) {
dbManager.messageDao().getUnsentMessages()
.distinctBy { it.message.message.id }
.let { mapper.map(it) }
}
override suspend fun saveLastSyncDate(roomId: String, timeMillis: Long) {
withContext(dbManager.dbContext) {
dbManager.messageDao().saveLastSync(MessagesSync(roomId, timeMillis))
}
}
override suspend fun getLastSyncDate(roomId: String): Long? = withContext(CommonPool) {
dbManager.messageDao().getLastSync(roomId)?.let { it.timestamp }
}
}
\ No newline at end of file
package chat.rocket.android.server.infraestructure
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.core.model.Message
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext
class MemoryMessagesRepository : MessagesRepository {
private var lastSyncDates: HashMap<String, Long> = HashMap()
private val messages: HashMap<String, Message> = HashMap()
override suspend fun saveLastSyncDate(rid: String, timeMillis: Long) {
lastSyncDates[rid] = timeMillis
}
override suspend fun getLastSyncDate(rid: String) = lastSyncDates[rid]
override suspend fun getById(id: String): Message? = withContext(CommonPool) {
return@withContext messages[id]
}
override suspend fun getByRoomId(rid: String): List<Message> = withContext(CommonPool) {
return@withContext messages.filter { it.value.roomId == rid }.values.toList()
}
override suspend fun getRecentMessages(rid: String, count: Long): List<Message> = withContext(CommonPool) {
return@withContext getByRoomId(rid).sortedByDescending { it.timestamp }
.distinctBy { it.sender }.take(count.toInt())
}
override suspend fun getAll(): List<Message> = withContext(CommonPool) {
return@withContext messages.values.toList()
}
override suspend fun getUnsentByRoomId(roomId: String): List<Message> = withContext(CommonPool) {
val allByRoomId = getByRoomId(roomId)
if (allByRoomId.isEmpty()) {
return@withContext emptyList<Message>()
}
return@withContext allByRoomId.filter { it.isTemporary ?: false && it.roomId == roomId }
}
override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) {
val all = getAll()
if (all.isEmpty()) {
return@withContext emptyList<Message>()
}
return@withContext all.filter { it.isTemporary ?: false }
}
override suspend fun save(message: Message) = withContext(CommonPool) {
messages[message.id] = message
}
override suspend fun saveAll(newMessages: List<Message>) = withContext(CommonPool) {
for (msg in newMessages) {
messages[msg.id] = msg
}
}
override suspend fun clear() = withContext(CommonPool) {
messages.clear()
}
override suspend fun removeById(id: String) {
withContext(CommonPool) {
messages.remove(id)
}
}
override suspend fun removeByRoomId(rid: String) = withContext(CommonPool) {
val roomMessages = messages.filter { it.value.roomId == rid }.values
roomMessages.forEach {
messages.remove(it.roomId)
}
}
}
\ No newline at end of file
...@@ -68,19 +68,6 @@ class SharedPreferencesMessagesRepository( ...@@ -68,19 +68,6 @@ class SharedPreferencesMessagesRepository(
.distinctBy { it.sender }.take(count.toInt()) .distinctBy { it.sender }.take(count.toInt())
} }
override suspend fun getAll(): List<Message> = withContext(CommonPool) {
val adapter = moshi.adapter<Message>(Message::class.java)
if (prefs.all.values.isEmpty()) {
return@withContext emptyList<Message>()
}
currentServerInteractor.get()?.also { server ->
val values = prefs.all.entries.filter { it.key.startsWith(server) }
.map { it.value } as Collection<String>
return@withContext values.mapNotNull { adapter.fromJson(it) }
}
return@withContext emptyList<Message>()
}
override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) { override suspend fun getAllUnsent(): List<Message> = withContext(CommonPool) {
if (prefs.all.values.isEmpty()) { if (prefs.all.values.isEmpty()) {
return@withContext emptyList<Message>() return@withContext emptyList<Message>()
...@@ -90,19 +77,11 @@ class SharedPreferencesMessagesRepository( ...@@ -90,19 +77,11 @@ class SharedPreferencesMessagesRepository(
.map { it.value } as Collection<String> .map { it.value } as Collection<String>
val adapter = moshi.adapter<Message>(Message::class.java) val adapter = moshi.adapter<Message>(Message::class.java)
return@withContext values.mapNotNull { adapter.fromJson(it) } return@withContext values.mapNotNull { adapter.fromJson(it) }
.filter { it.isTemporary ?: false } .filterNot { it.synced ?: false }
} }
return@withContext emptyList<Message>() return@withContext emptyList<Message>()
} }
override suspend fun getUnsentByRoomId(roomId: String): List<Message> = withContext(CommonPool) {
val allByRoomId = getByRoomId(roomId)
if (allByRoomId.isEmpty()) {
return@withContext emptyList<Message>()
}
return@withContext allByRoomId.filter { it.isTemporary ?: false }
}
override suspend fun save(message: Message) { override suspend fun save(message: Message) {
withContext(CommonPool) { withContext(CommonPool) {
currentServerInteractor.get()?.also { currentServerInteractor.get()?.also {
...@@ -125,10 +104,6 @@ class SharedPreferencesMessagesRepository( ...@@ -125,10 +104,6 @@ class SharedPreferencesMessagesRepository(
} }
} }
override suspend fun clear() = withContext(CommonPool) {
prefs.edit().clear().apply()
}
override suspend fun removeById(id: String) { override suspend fun removeById(id: String) {
withContext(CommonPool) { withContext(CommonPool) {
currentServerInteractor.get()?.also { currentServerInteractor.get()?.also {
......
...@@ -31,20 +31,21 @@ suspend fun RocketChatClientFactory.registerPushToken( ...@@ -31,20 +31,21 @@ suspend fun RocketChatClientFactory.registerPushToken(
fun Message.toEntity(): MessageEntity { fun Message.toEntity(): MessageEntity {
return MessageEntity( return MessageEntity(
id = id, id = id,
roomId = roomId, roomId = roomId,
message = message, message = message,
timestamp = timestamp, timestamp = timestamp,
senderId = sender?.id, senderId = sender?.id,
updatedAt = updatedAt, updatedAt = updatedAt,
editedAt = editedAt, editedAt = editedAt,
editedBy = editedBy?.id, editedBy = editedBy?.id,
senderAlias = senderAlias, senderAlias = senderAlias,
avatar = avatar, avatar = avatar,
type = type.asString(), type = type.asString(),
groupable = groupable, groupable = groupable,
parseUrls = parseUrls, parseUrls = parseUrls,
pinned = pinned, pinned = pinned,
role = role role = role,
synced = synced
) )
} }
\ No newline at end of file
...@@ -10,7 +10,7 @@ buildscript { ...@@ -10,7 +10,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-rc03' classpath 'com.android.tools.build:gradle:3.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath 'com.google.gms:google-services:4.0.2' classpath 'com.google.gms:google-services:4.0.2'
......
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