@@ -3,17 +3,14 @@ package xyz.flipchat.chat
33import android.annotation.SuppressLint
44import androidx.core.app.NotificationManagerCompat
55import androidx.paging.ExperimentalPagingApi
6- import androidx.paging.LoadType
76import androidx.paging.Pager
87import androidx.paging.PagingConfig
98import androidx.paging.PagingSource
109import androidx.paging.PagingState
11- import androidx.paging.RemoteMediator
1210import androidx.room.paging.util.ThreadSafeInvalidationObserver
1311import androidx.room.withTransaction
1412import com.getcode.model.ID
1513import com.getcode.model.KinAmount
16- import com.getcode.model.chat.MessageContent
1714import com.getcode.model.chat.MessageStatus
1815import com.getcode.model.uuid
1916import com.getcode.services.model.chat.OutgoingMessageContent
@@ -24,6 +21,8 @@ import kotlinx.coroutines.Dispatchers
2421import kotlinx.coroutines.flow.Flow
2522import kotlinx.coroutines.launch
2623import kotlinx.coroutines.withContext
24+ import xyz.flipchat.chat.paging.MessagingPagingSource
25+ import xyz.flipchat.chat.paging.MessagingRemoteMediator
2726import xyz.flipchat.internal.db.FcAppDatabase
2827import xyz.flipchat.notifications.getRoomNotifications
2928import xyz.flipchat.services.data.ChatIdentifier
@@ -32,7 +31,6 @@ import xyz.flipchat.services.domain.model.chat.ConversationMember
3231import xyz.flipchat.services.domain.model.chat.ConversationMessageWithMemberAndContent
3332import xyz.flipchat.services.domain.model.chat.ConversationWithMembersAndLastPointers
3433import xyz.flipchat.services.domain.model.chat.InflatedConversationMessage
35- import xyz.flipchat.services.domain.model.query.QueryOptions
3634import xyz.flipchat.services.internal.data.mapper.ConversationMemberMapper
3735import xyz.flipchat.services.internal.network.repository.chat.ChatRepository
3836import xyz.flipchat.services.internal.network.repository.messaging.MessagingRepository
@@ -199,7 +197,7 @@ class RoomController @Inject constructor(
199197 fun messages (conversationId : ID ): Pager <Int , InflatedConversationMessage > =
200198 Pager (
201199 config = pagingConfig,
202- remoteMediator = MessagesRemoteMediator (
200+ remoteMediator = MessagingRemoteMediator (
203201 chatId = conversationId,
204202 repository = messagingRepository,
205203 conversationMessageMapper = conversationMessageMapper,
@@ -334,118 +332,3 @@ class RoomController @Inject constructor(
334332 }
335333}
336334
337- private class MessagingPagingSource (
338- private val chatId : ID ,
339- private val userId : () -> ID ? ,
340- private val db : FcAppDatabase
341- ) : PagingSource<Int, InflatedConversationMessage>() {
342-
343- @SuppressLint(" RestrictedApi" )
344- private val observer =
345- ThreadSafeInvalidationObserver (arrayOf(" conversations" , " messages" , " members" )) {
346- invalidate()
347- }
348-
349- override fun getRefreshKey (state : PagingState <Int , InflatedConversationMessage >): Int? {
350- val anchorPos = state.anchorPosition ? : return null
351- val anchorItem = state.closestItemToPosition(anchorPos) ? : return null
352- // The anchor item *knows* which page it was loaded from:
353- return anchorItem.pageIndex
354- }
355-
356- @SuppressLint(" RestrictedApi" )
357- override suspend fun load (params : LoadParams <Int >): LoadResult <Int , InflatedConversationMessage > {
358- observer.registerIfNecessary(db)
359- val currentPage = params.key ? : 0
360- val pageSize = params.loadSize
361- val offset = currentPage * pageSize
362-
363- return withContext(Dispatchers .Default ) {
364- try {
365- val messages =
366- db.conversationMessageDao()
367- .getPagedMessagesWithDetails(chatId, pageSize, offset, userId())
368- .map { it.copy(pageIndex = currentPage) }
369-
370- val prevKey = if (currentPage > 0 && messages.isNotEmpty()) currentPage - 1 else null
371- val nextKey = if (messages.size < pageSize) null else currentPage + 1
372-
373- LoadResult .Page (
374- data = messages,
375- prevKey = prevKey,
376- nextKey = nextKey,
377- )
378- } catch (e: Exception ) {
379- LoadResult .Error (e)
380- }
381- }
382- }
383- }
384-
385- @OptIn(ExperimentalPagingApi ::class )
386- private class MessagesRemoteMediator (
387- private val chatId : ID ,
388- private val repository : MessagingRepository ,
389- private val conversationMessageMapper : ConversationMessageMapper ,
390- private val userId : () -> ID ?
391- ) : RemoteMediator<Int, InflatedConversationMessage>() {
392-
393- private val db = FcAppDatabase .requireInstance()
394-
395- override suspend fun initialize (): InitializeAction {
396- return InitializeAction .SKIP_INITIAL_REFRESH
397- }
398-
399- override suspend fun load (
400- loadType : LoadType ,
401- state : PagingState <Int , InflatedConversationMessage >
402- ): MediatorResult {
403- return try {
404- val loadKey = when (loadType) {
405- LoadType .REFRESH -> {
406- null
407- }
408-
409- LoadType .PREPEND -> {
410- return MediatorResult .Success (true ) // Don't load newer messages
411- }
412-
413- LoadType .APPEND -> {
414- // Get the last item from our data
415- state.lastItemOrNull()?.message?.id
416- }
417- }
418-
419- val limit = state.config.pageSize
420-
421- val query = QueryOptions (
422- limit = limit,
423- token = loadKey,
424- descending = true
425- )
426-
427- val response = withContext(Dispatchers .IO ) { repository.getMessages(chatId, query) }
428- val messages = response.getOrNull().orEmpty()
429-
430- val conversationMessages =
431- messages.map { conversationMessageMapper.map(chatId to it) }
432-
433- if (conversationMessages.isEmpty()) {
434- return MediatorResult .Success (true )
435- }
436-
437- withContext(Dispatchers .IO ) {
438- if (loadType == LoadType .REFRESH ) {
439- db.conversationMessageDao().clearMessagesForChat(chatId)
440- }
441-
442- db.conversationMessageDao()
443- .upsertMessages(messages = conversationMessages, selfID = userId())
444- }
445-
446- MediatorResult .Success (endOfPaginationReached = messages.size < limit)
447- } catch (e: Exception ) {
448- MediatorResult .Error (e)
449- }
450- }
451- }
0 commit comments