Selaa lähdekoodia

remove SyncableModel and SyncUtils

not needed for our requirements + it simplifies code

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe 1 vuosi sitten
vanhempi
commit
fe4bf942ab

+ 7 - 2
app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt

@@ -1,6 +1,7 @@
 /*
  * Nextcloud Talk - Android Client
  *
+ * SPDX-FileCopyrightText: 2024 Marcel Hibbe <dev@mhibbe.de>
  * SPDX-FileCopyrightText: 2024 Julius Linus <juliuslinus1@gmail.com>
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
@@ -161,7 +162,7 @@ class OfflineFirstChatRepository @Inject constructor(
 
             val loadFromServer = hasToLoadPreviousMessagesFromServer(beforeMessageId)
 
-            if (loadFromServer && monitor.isOnline.first()) {
+            if (loadFromServer) {
                 sync(withNetworkParams)
             }
 
@@ -292,7 +293,6 @@ class OfflineFirstChatRepository @Inject constructor(
         val loadFromServer = hasToLoadPreviousMessagesFromServer(messageId)
 
         if (loadFromServer) {
-
             val fieldMap = getFieldMap(
                 lookIntoFuture = false,
                 includeLastKnown = true,
@@ -368,6 +368,11 @@ class OfflineFirstChatRepository @Inject constructor(
     }
 
     private suspend fun sync(bundle: Bundle): List<ChatMessageEntity>? {
+        if (!monitor.isOnline.first()) {
+            Log.d(TAG, "Device is offline, can't load chat messages from server")
+            return null
+        }
+
         val result = getMessagesFromServer(bundle) ?: return listOf()
         var chatMessagesFromSync: List<ChatMessageEntity>? = null
 

+ 1 - 2
app/src/main/java/com/nextcloud/talk/conversationlist/data/OfflineConversationsRepository.kt

@@ -7,12 +7,11 @@
 
 package com.nextcloud.talk.conversationlist.data
 
-import com.nextcloud.talk.data.sync.Syncable
 import com.nextcloud.talk.models.domain.ConversationModel
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.Flow
 
-interface OfflineConversationsRepository : Syncable {
+interface OfflineConversationsRepository {
 
     /**
      * Stream of a list of rooms, for use in the conversation list.

+ 32 - 40
app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt

@@ -1,24 +1,23 @@
 /*
  * Nextcloud Talk - Android Client
  *
- * SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
+ * SPDX-FileCopyrightText: 2024 Julius Linus <juliuslinus1@gmail.com>
+ * SPDX-FileCopyrightText: 2024 Marcel Hibbe <dev@mhibbe.de>
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
 package com.nextcloud.talk.conversationlist.data.network
 
-import android.os.Bundle
-import androidx.core.os.bundleOf
+import android.util.Log
+import com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository
 import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository
 import com.nextcloud.talk.data.database.dao.ConversationsDao
 import com.nextcloud.talk.data.database.mappers.asEntity
 import com.nextcloud.talk.data.database.mappers.asModel
 import com.nextcloud.talk.data.database.model.ConversationEntity
-import com.nextcloud.talk.data.sync.Synchronizer
-import com.nextcloud.talk.data.sync.changeListSync
+import com.nextcloud.talk.data.network.NetworkMonitor
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.domain.ConversationModel
-import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.schedulers.Schedulers
@@ -35,9 +34,9 @@ import javax.inject.Inject
 class OfflineFirstConversationsRepository @Inject constructor(
     private val dao: ConversationsDao,
     private val network: ConversationsNetworkDataSource,
+    private val monitor: NetworkMonitor,
     private val currentUserProviderNew: CurrentUserProviderNew
-) : OfflineConversationsRepository, Synchronizer {
-
+) : OfflineConversationsRepository {
     override val roomListFlow: Flow<List<ConversationModel>>
         get() = _roomListFlow
     private val _roomListFlow: MutableSharedFlow<List<ConversationModel>> = MutableSharedFlow()
@@ -56,7 +55,7 @@ class OfflineFirstConversationsRepository @Inject constructor(
                 if (list.isNotEmpty()) {
                     _roomListFlow.emit(list)
                 }
-                this@OfflineFirstConversationsRepository.sync(bundleOf())
+                sync()
             }
         }
 
@@ -64,39 +63,28 @@ class OfflineFirstConversationsRepository @Inject constructor(
         scope.launch {
             val id = user.id!!
             val model = getConversation(id, roomToken)
-            model?.let { _conversationFlow.emit(model) }
+            model.let { _conversationFlow.emit(model) }
         }
 
-    override suspend fun syncWith(bundle: Bundle, synchronizer: Synchronizer): Boolean =
-        synchronizer.changeListSync(
-            modelFetcher = {
-                return@changeListSync getConversationsFromServer()
-            },
-            // not needed
-            versionUpdater = {},
-            modelDeleter = {},
-            modelUpdater = { models ->
-                val list = models.filterIsInstance<Conversation>().map {
-                    it.asEntity(user.id!!)
-                }
-                dao.upsertConversations(list)
-            }
-        )
+    private suspend fun sync() {
+        if (!monitor.isOnline.first()) {
+            Log.d(OfflineFirstChatRepository.TAG, "Device is offline, can't load conversations from server")
+            return
+        }
 
-    private fun getConversationsFromServer(): List<Conversation> {
-        val list = network.getRooms(user, user.baseUrl!!, false)
-            .subscribeOn(Schedulers.io())
-            .observeOn(AndroidSchedulers.mainThread())
-            .map { list ->
-                return@map list.map {
-                    it.apply {
-                        id = roomId!!.toLong()
-                    }
-                }
-            }
-            .blockingSingle()
+        try {
+            val conversationsList = network.getRooms(user, user.baseUrl!!, false)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .blockingSingle()
 
-        return list ?: listOf()
+            val list = conversationsList.map {
+                it.asEntity(user.id!!)
+            }
+            dao.upsertConversations(list)
+        } catch (e: Exception) {
+            Log.e(TAG, "Something went wrong when fetching conversations", e)
+        }
     }
 
     private suspend fun getListOfConversations(accountId: Long): List<ConversationModel> =
@@ -104,8 +92,12 @@ class OfflineFirstConversationsRepository @Inject constructor(
             it.map(ConversationEntity::asModel)
         }.first()
 
-    private suspend fun getConversation(accountId: Long, token: String): ConversationModel? {
+    private suspend fun getConversation(accountId: Long, token: String): ConversationModel {
         val entity = dao.getConversationForUser(accountId, token).first()
-        return entity?.asModel()
+        return entity.asModel()
+    }
+
+    companion object {
+        val TAG = OfflineFirstConversationsRepository::class.simpleName
     }
 }

+ 2 - 1
app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt

@@ -191,9 +191,10 @@ class RepositoryModule {
     fun provideOfflineFirstConversationsRepository(
         dao: ConversationsDao,
         dataSource: ConversationsNetworkDataSource,
+        networkMonitor: NetworkMonitor,
         currentUserProviderNew: CurrentUserProviderNew
     ): OfflineConversationsRepository {
-        return OfflineFirstConversationsRepository(dao, dataSource, currentUserProviderNew)
+        return OfflineFirstConversationsRepository(dao, dataSource, networkMonitor, currentUserProviderNew)
     }
 
     @Provides

+ 0 - 25
app/src/main/java/com/nextcloud/talk/data/changeListVersion/SyncableModel.kt

@@ -1,25 +0,0 @@
-/*
- * Nextcloud Talk - Android Client
- *
- * SPDX-FileCopyrightText: 2024 Julius Linus <juliuslinus1@gmail.com>
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-package com.nextcloud.talk.data.changeListVersion
-
-/**
- * Models any changes from the network, agnostic to what data is being modeled.
- * Implemented by Models that support offline synchronization.
- */
-interface SyncableModel {
-
-    /**
-     * Model identifier.
-     */
-    var id: Long
-
-    /**
-     * Model deletion checker.
-     */
-    var markedForDeletion: Boolean
-}

+ 0 - 93
app/src/main/java/com/nextcloud/talk/data/sync/SyncUtils.kt

@@ -1,93 +0,0 @@
-/*
- * Nextcloud Talk - Android Client
- *
- * SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-package com.nextcloud.talk.data.sync
-
-import android.os.Bundle
-import android.util.Log
-import com.nextcloud.talk.data.changeListVersion.SyncableModel
-import kotlin.coroutines.cancellation.CancellationException
-
-/**
- * Interface marker for a class that manages synchronization between local data and a remote
- * source for a [Syncable].
- */
-interface Synchronizer {
-
-    // TODO include any other helper functions here that the Synchronizer needs
-
-    /**
-     * Syntactic sugar to call [Syncable.syncWith] while omitting the synchronizer argument
-     */
-    suspend fun Syncable.sync(bundle: Bundle) = this@sync.syncWith(bundle, this@Synchronizer)
-}
-
-/**
- * Interface marker for a class that is synchronized with a remote source. Syncing must not be
- * performed concurrently and it is the [Synchronizer]'s responsibility to ensure this.
- */
-interface Syncable {
-    /**
-     * Synchronizes the local database backing the repository with the network.
-     * Takes in a [bundle] to retrieve other metadata needed
-     *
-     * Returns if the sync was successful or not.
-     */
-    suspend fun syncWith(bundle: Bundle, synchronizer: Synchronizer): Boolean
-}
-
-/**
- * Attempts [block], returning a successful [Result] if it succeeds, otherwise a [Result.Failure]
- * taking care not to break structured concurrency
- */
-private suspend fun <T> suspendRunCatching(block: suspend () -> T): Result<T> =
-    try {
-        Result.success(block())
-    } catch (cancellationException: CancellationException) {
-        throw cancellationException
-    } catch (exception: Exception) {
-        Log.e(
-            "suspendRunCatching",
-            "Failed to evaluate a suspendRunCatchingBlock. Returning failure Result",
-            exception
-        )
-        Result.failure(exception)
-    }
-
-/**
- * Utility function for syncing a repository with the network.
- * [modelFetcher] Fetches the change list for the model
- * [versionUpdater] Updates the version after a successful sync
- * [modelDeleter] Deletes models by consuming the ids of the models that have been deleted.
- * [modelUpdater] Updates models by consuming the ids of the models that have changed.
- *
- * Note that the blocks defined above are never run concurrently, and the [Synchronizer]
- * implementation must guarantee this.
- */
-suspend fun Synchronizer.changeListSync(
-    modelFetcher: suspend () -> List<SyncableModel>,
-    versionUpdater: (Long) -> Unit,
-    modelDeleter: suspend (List<Long>) -> Unit,
-    modelUpdater: suspend (List<SyncableModel>) -> Unit
-) = suspendRunCatching {
-    // Fetch the change list since last sync (akin to a git fetch)
-    val changeList = modelFetcher()
-    if (changeList.isEmpty()) return@suspendRunCatching true
-
-    // Splits the models marked for deletion from the ones that are updated or new
-    val (deleted, updated) = changeList.partition(SyncableModel::markedForDeletion)
-
-    // Delete models that have been deleted server-side
-    modelDeleter(deleted.map(SyncableModel::id))
-
-    // Using the fetch list, pull down and upsert the changes (akin to a git pull)
-    modelUpdater(updated)
-
-    // Update the last synced version (akin to updating local git HEAD)
-    val latestVersion = changeList.last().id
-    versionUpdater(latestVersion)
-}.isSuccess

+ 1 - 4
app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt

@@ -7,7 +7,6 @@
  */
 package com.nextcloud.talk.models.domain
 
-import com.nextcloud.talk.data.changeListVersion.SyncableModel
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.json.chat.ChatMessageJson
 import com.nextcloud.talk.models.json.conversations.Conversation
@@ -62,9 +61,7 @@ class ConversationModel(
     var recordingConsentRequired: Int = 0,
     var remoteServer: String? = null,
     var remoteToken: String? = null,
-    override var id: Long = roomId?.toLong() ?: 0,
-    override var markedForDeletion: Boolean = false
-) : SyncableModel {
+) {
 
     companion object {
         fun mapToConversationModel(conversation: Conversation, user: User): ConversationModel {

+ 1 - 2
app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessageJson.kt

@@ -1,7 +1,7 @@
 /*
  * Nextcloud Talk - Android Client
  *
- * SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
+ * SPDX-FileCopyrightText: 2024 Marcel Hibbe <dev@mhibbe.de>
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
@@ -10,7 +10,6 @@ package com.nextcloud.talk.models.json.chat
 import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
-import com.nextcloud.talk.data.changeListVersion.SyncableModel
 import com.nextcloud.talk.chat.data.model.ChatMessage.SystemMessageType
 import com.nextcloud.talk.models.json.converters.EnumSystemMessageTypeConverter
 import kotlinx.parcelize.Parcelize

+ 2 - 6
app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt

@@ -12,10 +12,9 @@ package com.nextcloud.talk.models.json.conversations
 import android.os.Parcelable
 import com.bluelinelabs.logansquare.annotation.JsonField
 import com.bluelinelabs.logansquare.annotation.JsonObject
-import com.nextcloud.talk.models.json.chat.ChatMessageJson
-import com.nextcloud.talk.data.changeListVersion.SyncableModel
 import com.nextcloud.talk.data.user.model.User
 import com.nextcloud.talk.models.domain.ConversationModel
+import com.nextcloud.talk.models.json.chat.ChatMessageJson
 import com.nextcloud.talk.models.json.converters.ConversationObjectTypeConverter
 import com.nextcloud.talk.models.json.converters.EnumLobbyStateConverter
 import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter
@@ -156,10 +155,7 @@ data class Conversation(
     @JsonField(name = ["remoteToken"])
     var remoteToken: String? = null,
 
-    override var id: Long = 0,
-    override var markedForDeletion: Boolean = false
-
-) : Parcelable, SyncableModel {
+) : Parcelable {
     @Deprecated("Use ConversationUtil")
     val isPublic: Boolean
         get() = ConversationEnums.ConversationType.ROOM_PUBLIC_CALL == type