forked from gotify/android
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMessageStateHolder.kt
More file actions
138 lines (120 loc) · 4.31 KB
/
Copy pathMessageStateHolder.kt
File metadata and controls
138 lines (120 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.github.gotify.messages.provider
import com.github.gotify.client.model.Message
import com.github.gotify.client.model.PagedMessages
import kotlin.math.max
import org.tinylog.kotlin.Logger
internal class MessageStateHolder {
@get:Synchronized
var lastReceivedMessage = -1L
private set
private var states = mutableMapOf<Long, MessageState>()
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 (lastReceivedMessage >= message.id) {
Logger.warn {
"Skipping processing message with id ${message.id} as it's already processed (lastReceivedMessage: $lastReceivedMessage)"
}
return
}
// 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)
}
}
}