Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions data/src/main/java/org/monogram/data/chats/ChatCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.monogram.data.chats
import org.drinkless.tdlib.TdApi
import org.monogram.data.datasource.cache.ChatsCacheDataSource
import org.monogram.data.datasource.cache.UserCacheDataSource
import java.io.File
import java.util.concurrent.ConcurrentHashMap

class ChatCache : ChatsCacheDataSource, UserCacheDataSource {
Expand Down Expand Up @@ -424,11 +425,14 @@ class ChatCache : ChatsCacheDataSource, UserCacheDataSource {
)
clientData = "mc:${entity.memberCount};oc:${entity.onlineCount}"
}
if (entity.photoId != 0) {
fileCache[entity.photoId] = TdApi.File().apply {
id = entity.photoId
local = TdApi.LocalFile().apply {
this.path = entity.avatarPath.orEmpty()
if (entity.photoId != 0 && !entity.avatarPath.isNullOrEmpty()) {
val avatarFile = File(entity.avatarPath)
if (avatarFile.exists()) {
fileCache[entity.photoId] = TdApi.File().apply {
id = entity.photoId
local = TdApi.LocalFile().apply {
this.path = entity.avatarPath
}
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions data/src/main/java/org/monogram/data/chats/ChatFileManager.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.monogram.data.chats

import org.monogram.data.core.coRunCatching
import kotlinx.coroutines.launch
import org.drinkless.tdlib.TdApi
import org.monogram.core.DispatcherProvider
import org.monogram.core.ScopeProvider
import org.monogram.data.core.coRunCatching
import org.monogram.data.gateway.TelegramGateway
import org.monogram.data.infra.FileDownloadQueue
import org.monogram.data.infra.FileUpdateHandler
import java.util.*
import java.util.concurrent.ConcurrentHashMap

Expand All @@ -15,6 +16,7 @@ class ChatFileManager(
private val gateway: TelegramGateway,
private val dispatchers: DispatcherProvider,
private val fileQueue: FileDownloadQueue,
private val fileUpdateHandler: FileUpdateHandler,
scopeProvider: ScopeProvider,
private val onUpdate: () -> Unit
) {
Expand All @@ -23,13 +25,11 @@ class ChatFileManager(
private val downloadingFiles: MutableSet<Int> = Collections.newSetFromMap(ConcurrentHashMap())
private val loadingEmojis: MutableSet<Long> = Collections.newSetFromMap(ConcurrentHashMap())
private val filePaths = ConcurrentHashMap<Int, String>()
private val emojiPathsCache = ConcurrentHashMap<Long, String>()
private val fileIdToEmojiId = ConcurrentHashMap<Int, Long>()
private val chatPhotoIds = ConcurrentHashMap<Int, Long>()
private val trackedFileIds = Collections.newSetFromMap(ConcurrentHashMap<Int, Boolean>())

fun getFilePath(fileId: Int): String? = filePaths[fileId]
fun getEmojiPath(emojiId: Long): String? = emojiPathsCache[emojiId]
fun getEmojiPath(emojiId: Long): String? = fileUpdateHandler.customEmojiPaths[emojiId]
fun getChatIdByPhotoId(fileId: Int): Long? = chatPhotoIds[fileId]

fun registerChatPhoto(fileId: Int, chatId: Long) {
Expand All @@ -51,8 +51,8 @@ class ChatFileManager(
private fun handleFileUpdated(fileId: Int, path: String): Boolean {
if (path.isEmpty()) return false
var updated = false
fileIdToEmojiId[fileId]?.let { emojiId ->
emojiPathsCache[emojiId] = path
fileUpdateHandler.fileIdToCustomEmojiId[fileId]?.let { emojiId ->
fileUpdateHandler.customEmojiPaths[emojiId] = path
updated = true
}
if (chatPhotoIds.containsKey(fileId)) updated = true
Expand All @@ -74,17 +74,17 @@ class ChatFileManager(
}

fun loadEmoji(emojiId: Long) {
if (emojiId == 0L || emojiPathsCache.containsKey(emojiId)) return
if (emojiId == 0L || fileUpdateHandler.customEmojiPaths.containsKey(emojiId)) return
if (loadingEmojis.add(emojiId)) {
scope.launch(dispatchers.io) {
coRunCatching {
val result = gateway.execute(TdApi.GetCustomEmojiStickers(longArrayOf(emojiId)))
val sticker = result.stickers.firstOrNull() ?: return@launch
val file = sticker.sticker
val path = file.local.path.ifEmpty { filePaths[file.id] ?: "" }
fileIdToEmojiId[file.id] = emojiId
fileUpdateHandler.fileIdToCustomEmojiId[file.id] = emojiId
if (path.isNotEmpty()) {
emojiPathsCache[emojiId] = path
fileUpdateHandler.customEmojiPaths[emojiId] = path
onUpdate()
} else {
downloadFile(file.id, 32)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.monogram.data.chats.ChatCache
import org.monogram.data.gateway.TdLibException
import org.monogram.data.gateway.TelegramGateway
import org.monogram.data.infra.FileDownloadQueue
import org.monogram.data.infra.FileUpdateHandler
import org.monogram.data.mapper.MessageMapper
import org.monogram.data.mapper.toApi
import org.monogram.domain.models.*
Expand All @@ -28,6 +29,7 @@ class TdMessageRemoteDataSource(
private val cache: ChatCache,
private val pollRepository: PollRepository,
private val fileDownloadQueue: FileDownloadQueue,
private val fileUpdateHandler: FileUpdateHandler,
private val dispatcherProvider: DispatcherProvider,
scopeProvider: ScopeProvider
) : MessageRemoteDataSource {
Expand Down Expand Up @@ -69,8 +71,6 @@ class TdMessageRemoteDataSource(
enum class DownloadType { VIDEO, GIF, STICKER, VIDEO_NOTE, DEFAULT }

private val fileIdToMessageMap = fileDownloadQueue.registry.fileIdToMessageMap
val customEmojiPaths = ConcurrentHashMap<Long, String>()
val fileIdToCustomEmojiId = ConcurrentHashMap<Int, Long>()
private val messageUpdateJobs = ConcurrentHashMap<Pair<Long, Long>, Job>()
private val lastProgressMap = ConcurrentHashMap<Int, Int>()
private val lastDownloadActiveMap = ConcurrentHashMap<Int, Boolean>()
Expand Down Expand Up @@ -1357,8 +1357,8 @@ class TdMessageRemoteDataSource(
if (isDC) {
fileDownloadQueue.notifyDownloadComplete(file.id)
lastProgressMap.remove(file.id)
fileIdToCustomEmojiId[file.id]?.let { customEmojiId ->
customEmojiPaths[customEmojiId] = file.local?.path ?: ""
fileUpdateHandler.fileIdToCustomEmojiId[file.id]?.let { customEmojiId ->
fileUpdateHandler.customEmojiPaths[customEmojiId] = file.local?.path ?: ""
}

val entries = fileIdToMessageMap[file.id]
Expand Down
5 changes: 3 additions & 2 deletions data/src/main/java/org/monogram/data/di/dataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,7 @@ val dataModule = module {
gateway = get(),
userRepository = get(),
chatInfoRepository = get(),
customEmojiPaths = get<FileUpdateHandler>().customEmojiPaths,
fileIdToCustomEmojiId = get<FileUpdateHandler>().fileIdToCustomEmojiId,
fileUpdateHandler = get(),
fileApi = get(),
appPreferences = get(),
cache = get(),
Expand Down Expand Up @@ -329,6 +328,7 @@ val dataModule = module {
chatFolderDao = get(),
userFullInfoDao = get(),
fileQueue = get(),
fileUpdateHandler = get(),
stringProvider = get()
)
}
Expand Down Expand Up @@ -421,6 +421,7 @@ val dataModule = module {
cache = get(),
pollRepository = get(),
fileDownloadQueue = get(),
fileUpdateHandler = get(),
dispatcherProvider = get(),
scopeProvider = get()
)
Expand Down
16 changes: 10 additions & 6 deletions data/src/main/java/org/monogram/data/mapper/MessageMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.monogram.data.chats.ChatCache
import org.monogram.data.datasource.remote.MessageFileApi
import org.monogram.data.datasource.remote.TdMessageRemoteDataSource
import org.monogram.data.gateway.TelegramGateway
import org.monogram.data.infra.FileUpdateHandler
import org.monogram.domain.models.*
import org.monogram.domain.repository.AppPreferencesProvider
import org.monogram.domain.repository.ChatInfoRepository
Expand All @@ -22,14 +23,15 @@ class MessageMapper(
private val gateway: TelegramGateway,
private val userRepository: UserRepository,
private val chatInfoRepository: ChatInfoRepository,
private val customEmojiPaths: ConcurrentHashMap<Long, String>,
private val fileIdToCustomEmojiId: ConcurrentHashMap<Int, Long>,
private val fileUpdateHandler: FileUpdateHandler,
private val fileApi: MessageFileApi,
private val appPreferences: AppPreferencesProvider,
private val cache: ChatCache,
scopeProvider: ScopeProvider
) {
val scope = scopeProvider.appScope
private val customEmojiPaths = fileUpdateHandler.customEmojiPaths
private val fileIdToCustomEmojiId = fileUpdateHandler.fileIdToCustomEmojiId

private data class SenderUserSnapshot(
val name: String,
Expand Down Expand Up @@ -125,12 +127,14 @@ class MessageMapper(
}

private fun resolveCachedPath(fileId: Int, storedPath: String?): String? {
val fromCache = fileId.takeIf { it != 0 }
?.let { cache.fileCache[it]?.local?.path }
val fromStored = storedPath
?.takeIf { it.isNotBlank() }
?.takeIf { isValidPath(it) }
if (fromCache != null) return fromCache
if (fromStored != null) return fromStored

return storedPath?.takeIf { it.isNotBlank() }?.takeIf { isValidPath(it) }
return fileId.takeIf { it != 0 }
?.let { cache.fileCache[it]?.local?.path }
?.takeIf { isValidPath(it) }
}

private fun registerCachedFile(fileId: Int, chatId: Long, messageId: Long) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.monogram.data.gateway.TelegramGateway
import org.monogram.data.gateway.UpdateDispatcher
import org.monogram.data.infra.ConnectionManager
import org.monogram.data.infra.FileDownloadQueue
import org.monogram.data.infra.FileUpdateHandler
import org.monogram.data.mapper.ChatMapper
import org.monogram.data.mapper.MessageMapper
import org.monogram.domain.models.ChatModel
Expand Down Expand Up @@ -53,6 +54,7 @@ class ChatsListRepositoryImpl(
private val chatFolderDao: ChatFolderDao,
private val userFullInfoDao: UserFullInfoDao,
private val fileQueue: FileDownloadQueue,
private val fileUpdateHandler: FileUpdateHandler,
private val stringProvider: StringProvider
) : ChatListRepository,
ChatFolderRepository,
Expand Down Expand Up @@ -96,6 +98,7 @@ class ChatsListRepositoryImpl(
dispatchers = dispatchers,
scopeProvider = scopeProvider,
fileQueue = fileQueue,
fileUpdateHandler = fileUpdateHandler,
onUpdate = {
triggerUpdate()
refreshActiveForumTopics()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.monogram.presentation.core.util

import java.io.File

fun fileCacheKey(path: String?): String? {
if (path.isNullOrBlank()) return null
val file = File(path)
if (!file.exists()) return null
return "${file.absolutePath}:${file.lastModified()}:${file.length()}"
}

fun miniThumbnailCacheKey(data: ByteArray): String {
return "mini:${data.contentHashCode()}:${data.size}"
}

fun mediaCacheKey(data: Any?): String? {
return when (data) {
null -> null
is ByteArray -> miniThumbnailCacheKey(data)
is File -> "${data.absolutePath}:${data.lastModified()}:${data.length()}"
is String -> {
when {
data.startsWith("http://", ignoreCase = true) ||
data.startsWith("https://", ignoreCase = true) ||
data.startsWith("content:", ignoreCase = true) ||
data.startsWith("file:", ignoreCase = true) -> data

else -> fileCacheKey(data) ?: data
}
}

else -> data.toString()
}
}

fun namespacedCacheKey(namespace: String, data: Any?): String? {
val key = mediaCacheKey(data) ?: return null
return "$namespace:$key"
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import kotlinx.coroutines.isActive
import org.monogram.domain.repository.PlayerDataSourceFactory
import org.monogram.presentation.core.util.LocalVideoPlayerPool
import org.monogram.presentation.core.util.getMimeType
import org.monogram.presentation.core.util.namespacedCacheKey
import java.io.File
import java.io.FileNotFoundException
import java.util.concurrent.ArrayBlockingQueue
Expand Down Expand Up @@ -252,15 +253,20 @@ fun VideoStickerPlayer(
exit = fadeOut(tween(250)),
modifier = Modifier.fillMaxSize()
) {
val thumbnailCacheKey = remember(currentPath, thumbnailData, fileId) {
namespacedCacheKey("video_sticker_thumb:$fileId", thumbnailData ?: currentPath)
}
AsyncImage(
model = ImageRequest.Builder(context)
.data(thumbnailData ?: currentPath)
.apply {
thumbnailCacheKey?.let {
memoryCacheKey(it)
diskCacheKey(it)
}
if (thumbnailData == null) {
decoderFactory(VideoFrameDecoder.Factory())
videoFrameMillis(0)
memoryCacheKey(currentPath)
diskCacheKey(currentPath)
}
}
.crossfade(false)
Expand Down
Loading