Skip to content

Commit 80d6468

Browse files
committed
Merge branch 'develop' into telemt-tdlib
2 parents 46aefce + 6616550 commit 80d6468

58 files changed

Lines changed: 4446 additions & 1518 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/src/main/java/org/monogram/app/components/MobileLayout.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,10 @@ fun MobileLayout(root: RootComponent) {
123123
onBack = root::onBack,
124124
fallbackAnimation = if (!swipeBackInProgress) stackAnimation(slide() + fade()) else null,
125125
),
126-
) {
127-
RenderChild(it.instance, isOverlay = false)
126+
) { child ->
127+
key(child.key) {
128+
RenderChild(child.instance, isOverlay = false)
129+
}
128130
}
129131
}
130132
}

data/src/main/java/org/monogram/data/chats/ChatCache.kt

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,8 @@ class ChatCache : ChatsCacheDataSource, UserCacheDataSource {
6262
existing.type = chat.type
6363
existing.lastMessage = chat.lastMessage
6464

65-
val newPositions = chat.positions.toMutableList()
66-
existing.positions.forEach { oldPos ->
67-
if (newPositions.none { isSameChatList(it.list, oldPos.list) }) {
68-
newPositions.add(oldPos)
69-
}
70-
}
71-
existing.positions = newPositions.toTypedArray()
65+
existing.positions =
66+
mergePositionsPreservingStronger(existing.positions, chat.positions)
7267

7368
existing.unreadCount = chat.unreadCount
7469
existing.unreadMentionCount = chat.unreadMentionCount
@@ -105,6 +100,35 @@ class ChatCache : ChatsCacheDataSource, UserCacheDataSource {
105100
}
106101
}
107102

103+
private fun mergePositionsPreservingStronger(
104+
existingPositions: Array<TdApi.ChatPosition>,
105+
incomingPositions: Array<TdApi.ChatPosition>
106+
): Array<TdApi.ChatPosition> {
107+
val merged = incomingPositions.toMutableList()
108+
existingPositions.forEach { oldPos ->
109+
val sameListIndex = merged.indexOfFirst { isSameChatList(it.list, oldPos.list) }
110+
if (sameListIndex == -1) {
111+
merged.add(oldPos)
112+
} else {
113+
val incomingPos = merged[sameListIndex]
114+
if (shouldPreferExistingPosition(oldPos, incomingPos)) {
115+
merged[sameListIndex] = oldPos
116+
}
117+
}
118+
}
119+
return merged.toTypedArray()
120+
}
121+
122+
private fun shouldPreferExistingPosition(
123+
existing: TdApi.ChatPosition,
124+
incoming: TdApi.ChatPosition
125+
): Boolean {
126+
if (existing.order == 0L) return false
127+
if (incoming.order == 0L) return true
128+
if (existing.isPinned && !incoming.isPinned) return true
129+
return existing.order > incoming.order
130+
}
131+
108132
private fun indexChatByType(chat: TdApi.Chat) {
109133
when (val type = chat.type) {
110134
is TdApi.ChatTypePrivate -> if (type.userId != 0L) {
@@ -221,6 +245,14 @@ class ChatCache : ChatsCacheDataSource, UserCacheDataSource {
221245
}
222246

223247
override fun getMessage(chatId: Long, messageId: Long): TdApi.Message? = messages[chatId]?.get(messageId)
248+
fun getMessages(chatId: Long): List<TdApi.Message> =
249+
messages[chatId]?.values?.toList().orEmpty()
250+
251+
fun getAlbumMessages(chatId: Long, mediaAlbumId: Long): List<TdApi.Message> {
252+
if (mediaAlbumId == 0L) return emptyList()
253+
return getMessages(chatId).filter { it.mediaAlbumId == mediaAlbumId }
254+
}
255+
224256
override fun putMessage(message: TdApi.Message) {
225257
val chatMessages = messages.getOrPut(message.chatId) { ConcurrentHashMap() }
226258
val existing = chatMessages[message.id]
@@ -352,17 +384,85 @@ class ChatCache : ChatsCacheDataSource, UserCacheDataSource {
352384
selfDestructType = null
353385
}
354386

387+
"gif" -> TdApi.MessageAnimation().apply {
388+
animation = TdApi.Animation()
389+
caption = TdApi.FormattedText(entity.lastMessageText, emptyArray())
390+
showCaptionAboveMedia = false
391+
hasSpoiler = false
392+
}
393+
355394
"voice" -> TdApi.MessageVoiceNote().apply {
356395
voiceNote = TdApi.VoiceNote()
357396
caption = TdApi.FormattedText(entity.lastMessageText, emptyArray())
358397
isListened = false
359398
}
360399

400+
"video_note" -> TdApi.MessageVideoNote().apply {
401+
videoNote = TdApi.VideoNote()
402+
isViewed = false
403+
}
404+
361405
"sticker" -> TdApi.MessageSticker().apply {
362406
sticker = TdApi.Sticker()
363407
isPremium = false
364408
}
365409

410+
"document" -> TdApi.MessageDocument().apply {
411+
document = TdApi.Document()
412+
caption = TdApi.FormattedText(entity.lastMessageText, emptyArray())
413+
}
414+
415+
"audio" -> TdApi.MessageAudio().apply {
416+
audio = TdApi.Audio()
417+
caption = TdApi.FormattedText(entity.lastMessageText, emptyArray())
418+
}
419+
420+
"contact" -> TdApi.MessageContact().apply {
421+
contact = TdApi.Contact()
422+
val parts = entity.lastMessageText.split(" ", limit = 2)
423+
contact.firstName = parts.firstOrNull().orEmpty()
424+
contact.lastName = parts.getOrNull(1).orEmpty()
425+
}
426+
427+
"poll" -> TdApi.MessagePoll().apply {
428+
poll = TdApi.Poll().apply {
429+
question = TdApi.FormattedText(entity.lastMessageText, emptyArray())
430+
options = emptyArray()
431+
}
432+
}
433+
434+
"location" -> TdApi.MessageLocation().apply {
435+
location = TdApi.Location()
436+
}
437+
438+
"call" -> TdApi.MessageCall().apply {
439+
discardReason = null
440+
duration = 0
441+
isVideo = false
442+
}
443+
444+
"game" -> TdApi.MessageGame().apply {
445+
game = TdApi.Game().apply {
446+
title = entity.lastMessageText
447+
}
448+
}
449+
450+
"invoice" -> TdApi.MessageInvoice().apply {
451+
productInfo = TdApi.ProductInfo().apply {
452+
title = entity.lastMessageText
453+
}
454+
}
455+
456+
"story" -> TdApi.MessageStory().apply {
457+
storyPosterChatId = 0L
458+
storyId = 0
459+
viaMention = false
460+
}
461+
462+
"pinned" -> TdApi.MessagePinMessage().apply {
463+
messageId = 0L
464+
}
465+
366466
else -> TdApi.MessageText()
367467
.apply { text = TdApi.FormattedText(entity.lastMessageText, emptyArray()) }
368468
}

data/src/main/java/org/monogram/data/chats/ChatListManager.kt

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,8 @@ class ChatListManager(
3232
compareByDescending<Pair<Long, TdApi.ChatPosition>> { it.second.order }
3333
.thenByDescending { it.first }
3434
)
35-
val otherLastMessageDates = HashMap<Long, Long>(otherEntries.size)
36-
otherEntries.forEach { (chatId, _) ->
37-
otherLastMessageDates[chatId] = cache.allChats[chatId]?.lastMessage?.date?.toLong() ?: 0L
38-
}
3935
otherEntries.sortWith(
40-
compareByDescending<Pair<Long, TdApi.ChatPosition>> { (chatId, _) ->
41-
otherLastMessageDates[chatId] ?: 0L
42-
}
43-
.thenByDescending { it.second.order }
36+
compareByDescending<Pair<Long, TdApi.ChatPosition>> { it.second.order }
4437
.thenByDescending { it.first }
4538
)
4639

@@ -188,18 +181,109 @@ class ChatListManager(
188181
): Boolean {
189182
val newPos = positions.find { isSameChatList(it.list, activeChatList) }
190183
return if (newPos != null && newPos.order != 0L) {
191-
val oldPos = cache.activeListPositions.put(chatId, newPos)
192-
if (newPos.isPinned) {
193-
cache.protectedPinnedChatIds.add(chatId)
184+
val oldPos = cache.activeListPositions[chatId]
185+
if (oldPos != null && shouldPreserveProtectedPinned(
186+
chatId,
187+
oldPos,
188+
newPos,
189+
activeChatList,
190+
"bulk_active"
191+
)
192+
) {
193+
false
194194
} else {
195-
cache.protectedPinnedChatIds.remove(chatId)
195+
val previous = cache.activeListPositions.put(chatId, newPos)
196+
if (newPos.isPinned) {
197+
cache.protectedPinnedChatIds.add(chatId)
198+
} else {
199+
cache.protectedPinnedChatIds.remove(chatId)
200+
}
201+
previous == null || previous.order != newPos.order || previous.isPinned != newPos.isPinned
196202
}
197-
oldPos == null || oldPos.order != newPos.order || oldPos.isPinned != newPos.isPinned
198203
} else {
204+
val oldPos = cache.activeListPositions[chatId]
205+
if (oldPos?.isPinned == true && cache.protectedPinnedChatIds.contains(chatId)) {
206+
Log.w(
207+
tag,
208+
"ignore active removal from bulk chatId=$chatId source=bulk_active oldOrder=${oldPos.order} oldPinned=${oldPos.isPinned} protected=true authoritative=${
209+
cache.authoritativeActiveListChatIds.contains(
210+
chatId
211+
)
212+
}"
213+
)
214+
}
199215
false
200216
}
201217
}
202218

219+
fun sanitizePositionsForActiveList(
220+
chatId: Long,
221+
currentPositions: Array<TdApi.ChatPosition>,
222+
incomingPositions: Array<TdApi.ChatPosition>,
223+
activeChatList: TdApi.ChatList,
224+
source: String
225+
): Array<TdApi.ChatPosition> {
226+
if (incomingPositions.isEmpty()) return currentPositions
227+
228+
val mergedPositions = incomingPositions.toMutableList()
229+
currentPositions.forEach { oldPos ->
230+
if (oldPos.order == 0L) return@forEach
231+
232+
val existingIndex =
233+
mergedPositions.indexOfFirst { isSameChatList(it.list, oldPos.list) }
234+
if (existingIndex == -1) {
235+
mergedPositions.add(oldPos)
236+
return@forEach
237+
}
238+
239+
val incomingPos = mergedPositions[existingIndex]
240+
if (shouldPreserveProtectedPinned(
241+
chatId,
242+
oldPos,
243+
incomingPos,
244+
activeChatList,
245+
source
246+
)
247+
) {
248+
mergedPositions[existingIndex] = oldPos
249+
}
250+
}
251+
252+
return mergedPositions.toTypedArray()
253+
}
254+
255+
private fun shouldPreserveProtectedPinned(
256+
chatId: Long,
257+
oldPos: TdApi.ChatPosition,
258+
newPos: TdApi.ChatPosition,
259+
activeChatList: TdApi.ChatList,
260+
source: String
261+
): Boolean {
262+
if (!isSameChatList(oldPos.list, activeChatList) || !isSameChatList(
263+
newPos.list,
264+
activeChatList
265+
)
266+
) {
267+
return false
268+
}
269+
if (oldPos.order == 0L || !oldPos.isPinned) return false
270+
if (!cache.protectedPinnedChatIds.contains(chatId)) return false
271+
272+
val pinnedDowngraded = !newPos.isPinned
273+
val orderCleared = newPos.order == 0L
274+
if (!pinnedDowngraded && !orderCleared) return false
275+
276+
Log.w(
277+
tag,
278+
"preserve protected pinned chatId=$chatId source=$source oldOrder=${oldPos.order} newOrder=${newPos.order} oldPinned=${oldPos.isPinned} newPinned=${newPos.isPinned} protected=true authoritative=${
279+
cache.authoritativeActiveListChatIds.contains(
280+
chatId
281+
)
282+
}"
283+
)
284+
return true
285+
}
286+
203287
fun isSameChatList(a: TdApi.ChatList?, b: TdApi.ChatList?): Boolean {
204288
if (a === b) return true
205289
if (a == null || b == null) return false

0 commit comments

Comments
 (0)