From 1f6c199a63c9ae1cd806c40d8d0c29b0d189be61 Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Fri, 4 May 2018 00:14:57 +0200 Subject: [PATCH] Correctly handle backlog requests, Fixes #68 #64 #56 Signed-off-by: Janne Koschinski <janne@kuschku.de> --- .../quasseldroid/service/BacklogRequester.kt | 63 +++++++++++++++++++ .../service/QuasselNotificationBackend.kt | 8 ++- .../ui/chat/messages/MessageListFragment.kt | 26 +++++--- .../quassel/syncables/BacklogManager.kt | 58 +++++++++++++---- 4 files changed, 132 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt b/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt new file mode 100644 index 000000000..7ee4ddaa9 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/service/BacklogRequester.kt @@ -0,0 +1,63 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2018 Janne Koschinski + * Copyright (c) 2018 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.service + +import de.kuschku.libquassel.protocol.BufferId +import de.kuschku.libquassel.protocol.Message +import de.kuschku.libquassel.protocol.MsgId +import de.kuschku.libquassel.util.helpers.value +import de.kuschku.quasseldroid.persistence.QuasselDatabase +import de.kuschku.quasseldroid.viewmodel.QuasselViewModel + +class BacklogRequester( + private val viewModel: QuasselViewModel, + private val database: QuasselDatabase +) { + fun loadMore(accountId: Long, buffer: BufferId, amount: Int, pageSize: Int, + lastMessageId: MsgId? = null, + untilVisible: Boolean = false, + finishCallback: () -> Unit) { + var missing = amount + viewModel.session.value?.orNull()?.backlogManager?.let { + it.requestBacklog( + bufferId = buffer, + last = lastMessageId ?: database.message().findFirstByBufferId( + buffer + )?.messageId ?: -1, + limit = amount + ) { + if (untilVisible && it.isNotEmpty()) { + val filtered = database.filtered().get(accountId, buffer) ?: 0 + missing -= it.count { + (it.type.value and filtered.inv()) != 0 + } + val messageId = it.map(Message::messageId).min() + if (missing > 0) { + loadMore(accountId, buffer, missing, pageSize, messageId, untilVisible, finishCallback) + } else { + finishCallback() + } + } else { + finishCallback() + } + } + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt index 80456bf45..b9a452c90 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselNotificationBackend.kt @@ -107,7 +107,9 @@ class QuasselNotificationBackend @Inject constructor( Message_Type.Action, Message_Type.Notice).toInt(), 0 - ) + ) { + processMessages(session, *it.toTypedArray()) + } } NotificationSettings.Level.HIGHLIGHT -> { val highlightCount = session.bufferSyncer.highlightCount(buffer.bufferId) @@ -118,7 +120,9 @@ class QuasselNotificationBackend @Inject constructor( Message_Type.Action, Message_Type.Notice).toInt(), Message_Flag.of(Message_Flag.Highlight).toInt() - ) + ) { + processMessages(session, *it.toTypedArray()) + } } } NotificationSettings.Level.NONE -> { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt index 46c74aa9a..2784a57f4 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt @@ -51,6 +51,7 @@ import de.kuschku.libquassel.util.irc.HostmaskHelper import de.kuschku.quasseldroid.GlideApp import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.persistence.QuasselDatabase +import de.kuschku.quasseldroid.service.BacklogRequester import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.AutoCompleteSettings import de.kuschku.quasseldroid.settings.BacklogSettings @@ -100,6 +101,8 @@ class MessageListFragment : ServiceBoundFragment() { private lateinit var linearLayoutManager: LinearLayoutManager + private lateinit var backlogRequester: BacklogRequester + private var lastBuffer: BufferId? = null private var previousMessageId: MsgId? = null @@ -207,6 +210,8 @@ class MessageListFragment : ServiceBoundFragment() { linearLayoutManager = LinearLayoutManager(context) linearLayoutManager.reverseLayout = true + backlogRequester = BacklogRequester(viewModel, database) + adapter.setOnClickListener { msg -> if (actionMode != null) { if (!viewModel.selectedMessagesToggle(msg.id, msg)) { @@ -481,14 +486,19 @@ class MessageListFragment : ServiceBoundFragment() { if (bufferId > 0 && bufferId != Int.MAX_VALUE) { if (initial) swipeRefreshLayout.isRefreshing = true runInBackground { - viewModel.session { - it.orNull()?.backlogManager?.requestBacklog( - bufferId = bufferId, - last = lastMessageId ?: database.message().findFirstByBufferId( - bufferId - )?.messageId ?: -1, - limit = if (initial) backlogSettings.initialAmount else backlogSettings.pageSize - ) + backlogRequester.loadMore( + accountId = accountId, + buffer = bufferId, + amount = if (initial) backlogSettings.initialAmount else backlogSettings.pageSize, + pageSize = backlogSettings.pageSize, + lastMessageId = lastMessageId + ?: database.message().findFirstByBufferId(bufferId)?.messageId ?: -1, + untilVisible = initial + ) { + Throwable().printStackTrace() + requireActivity().runOnUiThread { + swipeRefreshLayout.isRefreshing = false + } } } } diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BacklogManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BacklogManager.kt index f8fcdbfc8..8dd80345c 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BacklogManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BacklogManager.kt @@ -30,19 +30,8 @@ class BacklogManager( private val notificationManager: NotificationManager?, private val backlogStorage: BacklogStorage ) : SyncableObject(session, "BacklogManager"), IBacklogManager { - override fun receiveBacklogFiltered(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, - additional: Int, type: Int, flags: Int, - messages: QVariantList) { - val actualMessages = messages.mapNotNull { it.value<Message?>(null) } - notificationManager?.processMessages( - session, *actualMessages.toTypedArray() - ) - } - - override fun receiveBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, - type: Int, flags: Int, messages: QVariantList) { - // TODO: Not implemented - } + private val loading = mutableMapOf<BufferId, (List<Message>) -> Unit>() + private val loadingFiltered = mutableMapOf<BufferId, (List<Message>) -> Unit>() init { initialized = true @@ -50,14 +39,57 @@ class BacklogManager( fun updateIgnoreRules() = backlogStorage.updateIgnoreRules(session) + fun requestBacklog(bufferId: BufferId, first: MsgId = -1, last: MsgId = -1, limit: Int = -1, + additional: Int = 0, callback: (List<Message>) -> Unit) { + if (loading.contains(bufferId)) return + loading[bufferId] = callback + requestBacklog(bufferId, first, last, limit, additional) + } + + fun requestBacklogFiltered(bufferId: BufferId, first: MsgId = -1, last: MsgId = -1, + limit: Int = -1, additional: Int = 0, type: Int = -1, flags: Int = -1, + callback: (List<Message>) -> Unit) { + if (loadingFiltered.contains(bufferId)) return + loadingFiltered[bufferId] = callback + requestBacklogFiltered(bufferId, first, last, limit, additional, type, flags) + } + + fun requestBacklogAll(first: MsgId = -1, last: MsgId = -1, limit: Int = -1, additional: Int = 0, + callback: (List<Message>) -> Unit) { + if (loading.contains(-1)) return + loading[-1] = callback + requestBacklogAll(first, last, limit, additional) + } + + fun requestBacklogAllFiltered(first: MsgId = -1, last: MsgId = -1, limit: Int = -1, + additional: Int = 0, type: Int = -1, flags: Int = -1, + callback: (List<Message>) -> Unit) { + if (loading.contains(-1)) return + loadingFiltered[-1] = callback + requestBacklogAllFiltered(first, last, limit, additional, type, flags) + } + override fun receiveBacklog(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList) { backlogStorage.storeMessages(session, messages.mapNotNull(QVariant_::value), initialLoad = true) + loading.remove(bufferId)?.invoke(messages.mapNotNull { it.value<Message?>(null) }) } override fun receiveBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList) { backlogStorage.storeMessages(session, messages.mapNotNull(QVariant_::value), initialLoad = true) + loading.remove(-1)?.invoke(messages.mapNotNull { it.value<Message?>(null) }) + } + + override fun receiveBacklogFiltered(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, + additional: Int, type: Int, flags: Int, + messages: QVariantList) { + loadingFiltered.remove(bufferId)?.invoke(messages.mapNotNull { it.value<Message?>(null) }) + } + + override fun receiveBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, + type: Int, flags: Int, messages: QVariantList) { + loadingFiltered.remove(-1)?.invoke(messages.mapNotNull { it.value<Message?>(null) }) } fun removeBuffer(buffer: BufferId) { -- GitLab