Better database syncing... maybe
This commit is contained in:
@@ -17,6 +17,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -24,6 +25,22 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import net.buzzert.kordophone.backend.model.Conversation
|
import net.buzzert.kordophone.backend.model.Conversation
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
fun formatDateTime(dateTime: LocalDateTime): String {
|
||||||
|
val formatter: DateTimeFormatter = if (LocalDate.now().isEqual(dateTime.toLocalDate())) {
|
||||||
|
DateTimeFormatter.ofPattern("HH:mm") // show just the time
|
||||||
|
} else {
|
||||||
|
DateTimeFormatter.ofPattern("M/d/yy") // show day/month/year
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateTime.format(formatter)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationListScreen(
|
fun ConversationListScreen(
|
||||||
@@ -58,6 +75,7 @@ fun ConversationListView(
|
|||||||
id = conversation.guid,
|
id = conversation.guid,
|
||||||
isUnread = conversation.unreadCount > 0,
|
isUnread = conversation.unreadCount > 0,
|
||||||
lastMessagePreview = conversation.lastMessagePreview ?: "",
|
lastMessagePreview = conversation.lastMessagePreview ?: "",
|
||||||
|
date = conversation.date,
|
||||||
onClick = { onConversationSelected(conversation.guid) }
|
onClick = { onConversationSelected(conversation.guid) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -71,11 +89,12 @@ fun ConversationListItem(
|
|||||||
id: String,
|
id: String,
|
||||||
isUnread: Boolean,
|
isUnread: Boolean,
|
||||||
lastMessagePreview: String,
|
lastMessagePreview: String,
|
||||||
|
date: Date,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
val unreadSize = 12.dp
|
val unreadSize = 12.dp
|
||||||
val horizontalPadding = 8.dp
|
val horizontalPadding = 8.dp
|
||||||
val verticalPadding = 12.dp
|
val verticalPadding = 14.dp
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier
|
||||||
@@ -108,7 +127,12 @@ fun ConversationListItem(
|
|||||||
|
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
|
|
||||||
Text("13:37",
|
Text(
|
||||||
|
formatDateTime(
|
||||||
|
date.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDateTime()
|
||||||
|
),
|
||||||
modifier = Modifier.align(Alignment.CenterVertically),
|
modifier = Modifier.align(Alignment.CenterVertically),
|
||||||
color = MaterialTheme.colors.onBackground.copy(alpha = 0.4f)
|
color = MaterialTheme.colors.onBackground.copy(alpha = 0.4f)
|
||||||
)
|
)
|
||||||
@@ -116,7 +140,7 @@ fun ConversationListItem(
|
|||||||
Spacer(Modifier.width(horizontalPadding))
|
Spacer(Modifier.width(horizontalPadding))
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(lastMessagePreview)
|
Text(lastMessagePreview, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
|
|
||||||
Spacer(Modifier.height(verticalPadding))
|
Spacer(Modifier.height(verticalPadding))
|
||||||
Divider()
|
Divider()
|
||||||
@@ -142,7 +166,7 @@ fun UnreadIndicator(size: Dp, modifier: Modifier = Modifier) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun ConversationListItemPreview() {
|
fun ConversationListItemPreview() {
|
||||||
Column(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
Column(modifier = Modifier.background(MaterialTheme.colors.background)) {
|
||||||
ConversationListItem(name = "James Magahern", id = "asdf", lastMessagePreview = "This is a test", isUnread = true) {}
|
ConversationListItem(name = "James Magahern", id = "asdf", lastMessagePreview = "This is a test", date = Date(), isUnread = true) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import android.util.Log
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import net.buzzert.kordophone.backend.model.Conversation
|
import net.buzzert.kordophone.backend.model.Conversation
|
||||||
import net.buzzert.kordophone.backend.server.ChatRepository
|
import net.buzzert.kordophone.backend.server.ChatRepository
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ConversationListViewModel @Inject constructor(
|
class ConversationListViewModel @Inject constructor(
|
||||||
@@ -28,7 +31,9 @@ class ConversationListViewModel @Inject constructor(
|
|||||||
// TODO: Need error handling (exceptions thrown below)
|
// TODO: Need error handling (exceptions thrown below)
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.synchronize()
|
withContext(Dispatchers.IO) {
|
||||||
|
repository.synchronize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package net.buzzert.kordophone.backend.db
|
package net.buzzert.kordophone.backend.db
|
||||||
|
|
||||||
|
import io.realm.kotlin.MutableRealm
|
||||||
import io.realm.kotlin.Realm
|
import io.realm.kotlin.Realm
|
||||||
import io.realm.kotlin.RealmConfiguration
|
import io.realm.kotlin.RealmConfiguration
|
||||||
import io.realm.kotlin.UpdatePolicy
|
import io.realm.kotlin.UpdatePolicy
|
||||||
import io.realm.kotlin.ext.toRealmList
|
import io.realm.kotlin.ext.toRealmList
|
||||||
|
import io.realm.kotlin.query.find
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@@ -44,7 +46,8 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
|||||||
// Flow for watching changes to the database
|
// Flow for watching changes to the database
|
||||||
val conversationChanges: Flow<List<ModelConversation>>
|
val conversationChanges: Flow<List<ModelConversation>>
|
||||||
get() = realm.query(Conversation::class).find().asFlow().map {
|
get() = realm.query(Conversation::class).find().asFlow().map {
|
||||||
it.list.map { it.toConversation() }
|
realm.copyFromRealm(it.list)
|
||||||
|
.map { it.toConversation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow for watching for message changes for a given conversation
|
// Flow for watching for message changes for a given conversation
|
||||||
@@ -57,37 +60,45 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
|||||||
.map { it.list.map { it.toMessage(conversation) } }
|
.map { it.list.map { it.toMessage(conversation) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeConversations(conversations: List<ModelConversation>) = realm.writeBlocking {
|
fun updateConversations(incomingConversations: List<ModelConversation>) = realm.writeBlocking {
|
||||||
val dbConversations = conversations
|
val incomingDatabaseConversations = incomingConversations.map { it.toDatabaseConversation() }
|
||||||
// Convert to database conversations
|
|
||||||
.map { it.toDatabaseConversation() }
|
|
||||||
|
|
||||||
// Look for existing conversations, if applicable
|
var deletedConversations = realm.query(Conversation::class).find()
|
||||||
.map {
|
.minus(incomingDatabaseConversations)
|
||||||
try {
|
|
||||||
val existingConvo = getConversationByGuid(it.guid)
|
|
||||||
|
|
||||||
// Update existing record
|
deletedConversations.forEach { conversation ->
|
||||||
findLatest(existingConvo)?.apply {
|
findLatest(conversation)?.let {
|
||||||
displayName = it.displayName
|
delete(it)
|
||||||
participants = it.participants
|
|
||||||
date = it.date
|
|
||||||
unreadCount = it.unreadCount
|
|
||||||
} ?: existingConvo
|
|
||||||
} catch (e: NoSuchElementException) {
|
|
||||||
// This means object is unmanaged (i.e. it's new)
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dbConversations.forEach {
|
writeManagedConversations(this, incomingDatabaseConversations)
|
||||||
copyToRealm(it, updatePolicy = UpdatePolicy.ALL)
|
}
|
||||||
|
|
||||||
|
fun writeConversations(conversations: List<ModelConversation>) = realm.writeBlocking {
|
||||||
|
writeManagedConversations(this, conversations.map { it.toDatabaseConversation() })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeManagedConversations(mutableRealm: MutableRealm, conversations: List<Conversation>) {
|
||||||
|
conversations.forEach {conversation ->
|
||||||
|
try {
|
||||||
|
val managedConversation = getManagedConversationByGuid(conversation.guid)
|
||||||
|
mutableRealm.findLatest(managedConversation)?.apply {
|
||||||
|
displayName = conversation.displayName
|
||||||
|
participants = conversation.participants
|
||||||
|
date = conversation.date
|
||||||
|
unreadCount = conversation.unreadCount
|
||||||
|
}
|
||||||
|
} catch (e: NoSuchElementException) {
|
||||||
|
// Conversation does not exist. Copy it to the realm.
|
||||||
|
mutableRealm.copyToRealm(conversation, updatePolicy = UpdatePolicy.ALL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteConversations(conversations: List<ModelConversation>) = realm.writeBlocking {
|
fun deleteConversations(conversations: List<ModelConversation>) = realm.writeBlocking {
|
||||||
conversations.forEach { inConversation ->
|
conversations.forEach { inConversation ->
|
||||||
val conversation = getConversationByGuid(inConversation.guid)
|
val conversation = getManagedConversationByGuid(inConversation.guid)
|
||||||
findLatest(conversation)?.let {
|
findLatest(conversation)?.let {
|
||||||
delete(it)
|
delete(it)
|
||||||
}
|
}
|
||||||
@@ -95,12 +106,13 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fetchConversations(): List<ModelConversation> {
|
fun fetchConversations(): List<ModelConversation> {
|
||||||
val items = realm.query(Conversation::class).find()
|
val itemResults = realm.query(Conversation::class).find()
|
||||||
|
val items = realm.copyFromRealm(itemResults)
|
||||||
return items.map { it.toConversation() }
|
return items.map { it.toConversation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeMessages(messages: List<ModelMessage>, conversation: ModelConversation) {
|
fun writeMessages(messages: List<ModelMessage>, conversation: ModelConversation) {
|
||||||
val dbConversation = getConversationByGuid(conversation.guid)
|
val dbConversation = getManagedConversationByGuid(conversation.guid)
|
||||||
realm.writeBlocking {
|
realm.writeBlocking {
|
||||||
val dbMessages = messages
|
val dbMessages = messages
|
||||||
.map { it.toDatabaseMessage() }
|
.map { it.toDatabaseMessage() }
|
||||||
@@ -120,9 +132,13 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
|||||||
realm.close()
|
realm.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConversationByGuid(guid: GUID): Conversation {
|
private fun getManagedConversationByGuid(guid: GUID): Conversation {
|
||||||
return realm.query(Conversation::class, "guid == '$guid'")
|
return realm.query(Conversation::class, "guid == '$guid'")
|
||||||
.find()
|
.find()
|
||||||
.first()
|
.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getConversationByGuid(guid: GUID): Conversation {
|
||||||
|
return realm.copyFromRealm(getManagedConversationByGuid(guid))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@ open class Conversation(
|
|||||||
var date: RealmInstant,
|
var date: RealmInstant,
|
||||||
var unreadCount: Int,
|
var unreadCount: Int,
|
||||||
|
|
||||||
|
var lastMessagePreview: String?,
|
||||||
var messages: RealmList<Message>,
|
var messages: RealmList<Message>,
|
||||||
): RealmObject
|
): RealmObject
|
||||||
{
|
{
|
||||||
@@ -32,6 +33,7 @@ open class Conversation(
|
|||||||
participants = realmListOf<String>(),
|
participants = realmListOf<String>(),
|
||||||
date = RealmInstant.now(),
|
date = RealmInstant.now(),
|
||||||
unreadCount = 0,
|
unreadCount = 0,
|
||||||
|
lastMessagePreview = null,
|
||||||
|
|
||||||
messages = realmListOf<Message>()
|
messages = realmListOf<Message>()
|
||||||
)
|
)
|
||||||
@@ -43,17 +45,29 @@ open class Conversation(
|
|||||||
date = Date.from(date.toInstant()),
|
date = Date.from(date.toInstant()),
|
||||||
unreadCount = unreadCount,
|
unreadCount = unreadCount,
|
||||||
guid = guid,
|
guid = guid,
|
||||||
|
lastMessagePreview = lastMessagePreview,
|
||||||
lastMessage = null,
|
lastMessage = null,
|
||||||
lastMessagePreview = null,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (messages.isNotEmpty()) {
|
if (messages.isNotEmpty()) {
|
||||||
conversation.lastMessage = messages.last().toMessage(conversation)
|
val lastMessage = sortedMessages().last()
|
||||||
conversation.lastMessagePreview = messages.last().text
|
conversation.lastMessage = lastMessage.toMessage(conversation)
|
||||||
|
conversation.lastMessagePreview = lastMessage.text
|
||||||
}
|
}
|
||||||
|
|
||||||
return conversation
|
return conversation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun sortedMessages(): List<Message> {
|
||||||
|
return messages.sortedBy { it.date }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other == null || javaClass != other.javaClass) return false
|
||||||
|
|
||||||
|
val o = other as Conversation
|
||||||
|
return guid == o.guid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ModelConversation.toDatabaseConversation(): Conversation {
|
fun ModelConversation.toDatabaseConversation(): Conversation {
|
||||||
@@ -63,6 +77,7 @@ fun ModelConversation.toDatabaseConversation(): Conversation {
|
|||||||
participants = from.participants.toRealmList()
|
participants = from.participants.toRealmList()
|
||||||
date = from.date.toInstant().toRealmInstant()
|
date = from.date.toInstant().toRealmInstant()
|
||||||
unreadCount = from.unreadCount
|
unreadCount = from.unreadCount
|
||||||
|
lastMessagePreview = from.lastMessagePreview
|
||||||
guid = from.guid
|
guid = from.guid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ data class Message(
|
|||||||
text == o.text &&
|
text == o.text &&
|
||||||
sender == o.sender &&
|
sender == o.sender &&
|
||||||
date == o.date &&
|
date == o.date &&
|
||||||
conversation == o.conversation
|
conversation.guid == o.conversation.guid
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package net.buzzert.kordophone.backend.server
|
|||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import net.buzzert.kordophone.backend.model.Conversation
|
import net.buzzert.kordophone.backend.model.Conversation
|
||||||
|
import net.buzzert.kordophone.backend.model.GUID
|
||||||
import net.buzzert.kordophone.backend.model.Message
|
import net.buzzert.kordophone.backend.model.Message
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
@@ -32,7 +33,12 @@ interface APIInterface {
|
|||||||
suspend fun getConversations(): Response<List<Conversation>>
|
suspend fun getConversations(): Response<List<Conversation>>
|
||||||
|
|
||||||
@GET("/messages")
|
@GET("/messages")
|
||||||
suspend fun getMessages(@Query("guid") conversationGUID: String): Response<List<Message>>
|
suspend fun getMessages(
|
||||||
|
@Query("guid") conversationGUID: String,
|
||||||
|
@Query("limit") limit: Int? = null,
|
||||||
|
@Query("beforeMessageGUID") beforeMessageGUID: GUID? = null,
|
||||||
|
@Query("afterMessageGUID") afterMessageGUID: GUID? = null,
|
||||||
|
): Response<List<Message>>
|
||||||
|
|
||||||
@POST("/sendMessage")
|
@POST("/sendMessage")
|
||||||
suspend fun sendMessage(@Body request: SendMessageRequest): Response<Void>
|
suspend fun sendMessage(@Body request: SendMessageRequest): Response<Void>
|
||||||
|
|||||||
@@ -122,16 +122,13 @@ class ChatRepository(
|
|||||||
|
|
||||||
// Sync conversations
|
// Sync conversations
|
||||||
val serverConversations = fetchConversations()
|
val serverConversations = fetchConversations()
|
||||||
val deletedConversations = conversations.minus(serverConversations)
|
database.updateConversations(serverConversations)
|
||||||
|
|
||||||
database.deleteConversations(deletedConversations)
|
|
||||||
database.writeConversations(serverConversations)
|
|
||||||
|
|
||||||
// Sync top N number of conversations' message content
|
// Sync top N number of conversations' message content
|
||||||
Log.d(REPO_LOG, "Synchronizing messages")
|
Log.d(REPO_LOG, "Synchronizing messages")
|
||||||
val sortedConversations = conversations.sortedBy { it.date }.reversed()
|
val sortedConversations = conversations.sortedBy { it.date }.reversed()
|
||||||
for (conversation in sortedConversations.take(CONVERSATION_MESSAGE_SYNC_COUNT)) {
|
for (conversation in sortedConversations.take(CONVERSATION_MESSAGE_SYNC_COUNT)) {
|
||||||
val messages = fetchMessages(conversation)
|
val messages = fetchMessages(conversation, limit = 15)
|
||||||
database.writeMessages(messages, conversation)
|
database.writeMessages(messages, conversation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,15 +143,20 @@ class ChatRepository(
|
|||||||
return apiInterface.getConversations().bodyOnSuccessOrThrow()
|
return apiInterface.getConversations().bodyOnSuccessOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchMessages(conversation: Conversation): List<Message> {
|
private suspend fun fetchMessages(
|
||||||
return apiInterface.getMessages(conversation.guid)
|
conversation: Conversation,
|
||||||
|
limit: Int? = null,
|
||||||
|
before: Message? = null,
|
||||||
|
after: Message? = null,
|
||||||
|
): List<Message> {
|
||||||
|
return apiInterface.getMessages(conversation.guid, limit, before?.guid, after?.guid)
|
||||||
.bodyOnSuccessOrThrow()
|
.bodyOnSuccessOrThrow()
|
||||||
.onEach { it.conversation = conversation }
|
.onEach { it.conversation = conversation }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleConversationChangedUpdate(conversation: Conversation) {
|
private fun handleConversationChangedUpdate(conversation: Conversation) {
|
||||||
Log.d(REPO_LOG, "Handling conversation changed update")
|
Log.d(REPO_LOG, "Handling conversation changed update")
|
||||||
database.writeConversations(conversations)
|
database.writeConversations(listOf(conversation))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleMessageAddedUpdate(message: Message) {
|
private fun handleMessageAddedUpdate(message: Message) {
|
||||||
|
|||||||
@@ -105,13 +105,13 @@ class BackendTests {
|
|||||||
repo.synchronize()
|
repo.synchronize()
|
||||||
|
|
||||||
// Check our count.
|
// Check our count.
|
||||||
assertEquals(repo.conversations.count(), 10)
|
assertEquals(10, repo.conversations.count())
|
||||||
|
|
||||||
// Sync again: let's ensure we're de-duplicating conversations.
|
// Sync again: let's ensure we're de-duplicating conversations.
|
||||||
repo.synchronize()
|
repo.synchronize()
|
||||||
|
|
||||||
// Should be no change...
|
// Should be no change...
|
||||||
assertEquals(repo.conversations.count(), 10)
|
assertEquals(10, repo.conversations.count())
|
||||||
|
|
||||||
// Say unread count + lastMessage preview changes on server.
|
// Say unread count + lastMessage preview changes on server.
|
||||||
val someConversation = conversations.first().apply {
|
val someConversation = conversations.first().apply {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class DatabaseTests {
|
|||||||
val readMessages = db.fetchMessages(conversation)
|
val readMessages = db.fetchMessages(conversation)
|
||||||
|
|
||||||
assertEquals(readMessages, messages)
|
assertEquals(readMessages, messages)
|
||||||
assertEquals(readMessages[0].conversation, conversation)
|
assertEquals(readMessages[0].conversation.guid, conversation.guid)
|
||||||
|
|
||||||
db.close()
|
db.close()
|
||||||
}
|
}
|
||||||
@@ -72,5 +72,7 @@ class DatabaseTests {
|
|||||||
|
|
||||||
// Make sure our new name was written
|
// Make sure our new name was written
|
||||||
assertEquals(nowConversations.first().displayName, "wow")
|
assertEquals(nowConversations.first().displayName, "wow")
|
||||||
|
|
||||||
|
db.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,12 @@ class MockServerInterface(private val server: MockServer): APIInterface {
|
|||||||
return Response.success(server.conversations)
|
return Response.success(server.conversations)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMessages(conversationGUID: String): Response<List<Message>> {
|
override suspend fun getMessages(
|
||||||
|
conversationGUID: String,
|
||||||
|
limit: Int?,
|
||||||
|
beforeMessageGUID: GUID?,
|
||||||
|
afterMessageGUID: GUID?
|
||||||
|
): Response<List<Message>> {
|
||||||
val messages = server.getMessagesForConversationGUID(conversationGUID)
|
val messages = server.getMessagesForConversationGUID(conversationGUID)
|
||||||
|
|
||||||
return if (messages != null) {
|
return if (messages != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user