diff --git a/app/src/main/kotlin/com/github/gotify/messages/MessagesModel.kt b/app/src/main/kotlin/com/github/gotify/messages/MessagesModel.kt deleted file mode 100644 index e4ae8e4c..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/MessagesModel.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.github.gotify.messages - -import android.app.Activity -import androidx.lifecycle.ViewModel -import coil.target.Target -import com.github.gotify.Settings -import com.github.gotify.api.ClientFactory -import com.github.gotify.client.api.MessageApi -import com.github.gotify.messages.provider.ApplicationHolder -import com.github.gotify.messages.provider.MessageFacade -import com.github.gotify.messages.provider.MessageState - -internal class MessagesModel(parentView: Activity) : ViewModel() { - val settings = Settings(parentView) - val client = ClientFactory.clientToken(settings) - val appsHolder = ApplicationHolder(parentView, client) - val messages = MessageFacade(client.createService(MessageApi::class.java), appsHolder) - - // we need to keep the target references otherwise they get gc'ed before they can be called. - val targetReferences = mutableListOf() - - var appId = MessageState.ALL_MESSAGES -} diff --git a/app/src/main/kotlin/com/github/gotify/messages/MessagesModelFactory.kt b/app/src/main/kotlin/com/github/gotify/messages/MessagesModelFactory.kt deleted file mode 100644 index d22e8c4c..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/MessagesModelFactory.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.github.gotify.messages - -import android.app.Activity -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider - -internal class MessagesModelFactory( - var modelParameterActivity: Activity -) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass == MessagesModel::class.java) { - @Suppress("UNCHECKED_CAST") - return modelClass.cast(MessagesModel(modelParameterActivity)) as T - } - throw IllegalArgumentException( - "modelClass parameter must be of type ${MessagesModel::class.java.name}" - ) - } -} diff --git a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageDeletion.kt b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageDeletion.kt deleted file mode 100644 index 14cc1e4c..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageDeletion.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.gotify.messages.provider - -import com.github.gotify.client.model.Message - -internal class MessageDeletion( - val message: Message, - val allPosition: Int, - val appPosition: Int -) diff --git a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageFacade.kt b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageFacade.kt deleted file mode 100644 index 3152f79e..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageFacade.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.github.gotify.messages.provider - -import com.github.gotify.client.api.MessageApi -import com.github.gotify.client.model.Message - -internal class MessageFacade(api: MessageApi, private val applicationHolder: ApplicationHolder) { - private val requester = MessageRequester(api) - private val state = MessageStateHolder() - - @Synchronized - operator fun get(appId: Long): List { - return MessageImageCombiner.combine(state.state(appId).messages, applicationHolder.get()) - } - - @Synchronized - fun addMessages(messages: List) { - messages.forEach { - state.newMessage(it) - } - } - - @Synchronized - fun loadMore(appId: Long): List { - val state = state.state(appId) - if (state.hasNext || !state.loaded) { - val pagedMessages = requester.loadMore(state) - if (pagedMessages != null) { - this.state.newMessages(appId, pagedMessages) - } - } - return get(appId) - } - - @Synchronized - fun loadMoreIfNotPresent(appId: Long) { - val state = state.state(appId) - if (!state.loaded) { - loadMore(appId) - } - } - - @Synchronized - fun clear() { - state.clear() - } - - fun getLastReceivedMessage(): Long = state.lastReceivedMessage - - @Synchronized - fun deleteLocal(message: Message) { - // If there is already a deletion pending, that one should be executed before scheduling the - // next deletion. - if (state.deletionPending()) commitDelete() - state.deleteMessage(message) - } - - @Synchronized - fun commitDelete() { - if (state.deletionPending()) { - val deletion = state.purgePendingDeletion() - requester.asyncRemoveMessage(deletion!!.message) - } - } - - @Synchronized - fun undoDeleteLocal(): MessageDeletion? = state.undoPendingDeletion() - - @Synchronized - fun deleteAll(appId: Long): Boolean { - val success = requester.deleteAll(appId) - state.deleteAll(appId) - return success - } - - @Synchronized - fun canLoadMore(appId: Long): Boolean = state.state(appId).hasNext -} diff --git a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageImageCombiner.kt b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageImageCombiner.kt deleted file mode 100644 index ae2b8bf7..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageImageCombiner.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.github.gotify.messages.provider - -import com.github.gotify.client.model.Application -import com.github.gotify.client.model.Message - -internal object MessageImageCombiner { - fun combine(messages: List, applications: List): List { - val appIdToImage = appIdToImage(applications) - return messages.map { MessageWithImage(message = it, image = appIdToImage[it.appid]) } - } - - private fun appIdToImage(applications: List): Map { - val map = mutableMapOf() - applications.forEach { - map[it.id] = it.image - } - return map - } -} diff --git a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt deleted file mode 100644 index d2eb3f28..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.gotify.messages.provider - -import com.github.gotify.api.Api -import com.github.gotify.api.ApiException -import com.github.gotify.api.Callback -import com.github.gotify.client.api.MessageApi -import com.github.gotify.client.model.Message -import com.github.gotify.client.model.PagedMessages -import org.tinylog.kotlin.Logger - -internal class MessageRequester(private val messageApi: MessageApi) { - fun loadMore(state: MessageState): PagedMessages? { - return try { - Logger.info("Loading more messages for ${state.appId}") - if (MessageState.ALL_MESSAGES == state.appId) { - Api.execute(messageApi.getMessages(LIMIT, state.nextSince)) - } else { - Api.execute(messageApi.getAppMessages(state.appId, LIMIT, state.nextSince)) - } - } catch (apiException: ApiException) { - Logger.error(apiException, "failed requesting messages") - null - } - } - - fun asyncRemoveMessage(message: Message) { - Logger.info("Removing message with id ${message.id}") - messageApi.deleteMessage(message.id).enqueue(Callback.call()) - } - - fun deleteAll(appId: Long): Boolean { - return try { - Logger.info("Deleting all messages for $appId") - if (MessageState.ALL_MESSAGES == appId) { - Api.execute(messageApi.deleteMessages()) - } else { - Api.execute(messageApi.deleteAppMessages(appId)) - } - true - } catch (e: ApiException) { - Logger.error(e, "Could not delete messages") - false - } - } - - companion object { - private const val LIMIT = 100 - } -} diff --git a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageStateHolder.kt b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageStateHolder.kt deleted file mode 100644 index d8966ba4..00000000 --- a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageStateHolder.kt +++ /dev/null @@ -1,131 +0,0 @@ -package com.github.gotify.messages.provider - -import com.github.gotify.client.model.Message -import com.github.gotify.client.model.PagedMessages -import kotlin.math.max - -internal class MessageStateHolder { - @get:Synchronized - var lastReceivedMessage = -1L - private set - private var states = mutableMapOf() - private var pendingDeletion: MessageDeletion? = null - - @Synchronized - fun clear() { - states = mutableMapOf() - } - - @Synchronized - fun newMessages(appId: Long, pagedMessages: PagedMessages) { - val state = state(appId) - - if (!state.loaded && pagedMessages.messages.size > 0) { - lastReceivedMessage = max(pagedMessages.messages[0].id, lastReceivedMessage) - } - - state.apply { - loaded = true - messages.addAll(pagedMessages.messages) - hasNext = pagedMessages.paging.next != null - nextSince = pagedMessages.paging.since - this.appId = appId - } - states[appId] = state - - // If there is a message with pending deletion, it should not reappear in the list in case - // it is added again. - if (deletionPending()) { - deleteMessage(pendingDeletion!!.message) - } - } - - @Synchronized - fun newMessage(message: Message) { - // If there is a message with pending deletion, its indices are going to change. To keep - // them consistent the deletion is undone first and redone again after adding the new - // message. - val deletion = undoPendingDeletion() - addMessage(message, 0, 0) - lastReceivedMessage = message.id - if (deletion != null) deleteMessage(deletion.message) - } - - @Synchronized - fun state(appId: Long): MessageState = states[appId] ?: emptyState(appId) - - @Synchronized - fun deleteAll(appId: Long) { - clear() - val state = state(appId) - state.loaded = true - states[appId] = state - } - - private fun emptyState(appId: Long): MessageState { - return MessageState().apply { - loaded = false - hasNext = false - nextSince = 0 - this.appId = appId - } - } - - @Synchronized - fun deleteMessage(message: Message) { - val allMessages = state(MessageState.ALL_MESSAGES) - val appMessages = state(message.appid) - var pendingDeletedAllPosition = -1 - var pendingDeletedAppPosition = -1 - - if (allMessages.loaded) { - val allPosition = allMessages.messages.indexOf(message) - if (allPosition != -1) allMessages.messages.removeAt(allPosition) - pendingDeletedAllPosition = allPosition - } - if (appMessages.loaded) { - val appPosition = appMessages.messages.indexOf(message) - if (appPosition != -1) appMessages.messages.removeAt(appPosition) - pendingDeletedAppPosition = appPosition - } - pendingDeletion = MessageDeletion( - message, - pendingDeletedAllPosition, - pendingDeletedAppPosition - ) - } - - @Synchronized - fun undoPendingDeletion(): MessageDeletion? { - if (pendingDeletion != null) { - addMessage( - pendingDeletion!!.message, - pendingDeletion!!.allPosition, - pendingDeletion!!.appPosition - ) - } - return purgePendingDeletion() - } - - @Synchronized - fun purgePendingDeletion(): MessageDeletion? { - val result = pendingDeletion - pendingDeletion = null - return result - } - - @Synchronized - fun deletionPending(): Boolean = pendingDeletion != null - - private fun addMessage(message: Message, allPosition: Int, appPosition: Int) { - val allMessages = state(MessageState.ALL_MESSAGES) - val appMessages = state(message.appid) - - if (allMessages.loaded && allPosition != -1) { - allMessages.messages.add(allPosition, message) - } - if (appMessages.loaded && appPosition != -1) { - appMessages.messages.add(appPosition, message) - } - } -}