@@ -67,11 +67,17 @@ import androidx.compose.foundation.gestures.scrollBy
6767import androidx.compose.foundation.lazy.LazyListState
6868import androidx.compose.foundation.lazy.rememberLazyListState
6969import androidx.compose.material3.MaterialTheme
70+ import androidx.compose.runtime.Composable
7071import androidx.compose.runtime.CompositionLocalProvider
72+ import androidx.compose.runtime.LaunchedEffect
73+ import androidx.compose.runtime.MutableState
7174import androidx.compose.runtime.SideEffect
75+ import androidx.compose.runtime.collectAsState
76+ import androidx.compose.runtime.derivedStateOf
7277import androidx.compose.runtime.getValue
7378import androidx.compose.runtime.mutableStateOf
7479import androidx.compose.runtime.produceState
80+ import androidx.compose.runtime.remember
7581import androidx.compose.runtime.rememberCoroutineScope
7682import androidx.compose.runtime.setValue
7783import androidx.compose.ui.platform.ComposeView
@@ -121,6 +127,7 @@ import com.nextcloud.talk.api.NcApi
121127import com.nextcloud.talk.api.NcApiCoroutines
122128import com.nextcloud.talk.application.NextcloudTalkApplication
123129import com.nextcloud.talk.chat.data.model.ChatMessage
130+ import com.nextcloud.talk.chat.data.model.FileParameters
124131import com.nextcloud.talk.chat.ui.ShowReactionsModalBottomSheet
125132import com.nextcloud.talk.chat.ui.model.MessageTypeContent
126133import com.nextcloud.talk.chat.viewmodels.ChatViewModel
@@ -220,9 +227,9 @@ import kotlinx.coroutines.FlowPreview
220227import kotlinx.coroutines.Job
221228import kotlinx.coroutines.delay
222229import kotlinx.coroutines.flow.collect
223- import kotlinx.coroutines.flow.first
224230import kotlinx.coroutines.flow.collectLatest
225231import kotlinx.coroutines.flow.distinctUntilChanged
232+ import kotlinx.coroutines.flow.first
226233import kotlinx.coroutines.flow.map
227234import kotlinx.coroutines.flow.onEach
228235import kotlinx.coroutines.launch
@@ -725,6 +732,8 @@ class ChatActivity :
725732 chatListComposeScope = composeScope
726733 }
727734
735+ SideEffect { chatListState = listState }
736+
728737 CompositionLocalProvider (
729738 LocalViewThemeUtils provides viewThemeUtils,
730739 LocalMessageUtils provides messageUtils,
@@ -733,6 +742,18 @@ class ChatActivity :
733742 val isOneToOneConversation = uiState.isOneToOneConversation
734743 Log .d(TAG , " isOneToOneConversation=" + isOneToOneConversation)
735744
745+ // list of the file ids of messages being downloaded
746+ val downloadingFileState = remember { mutableStateOf(listOf<String >()) }
747+
748+ // openWhenDownloaded is a derived boolean state of the visible chat message list on the condition
749+ // that if any of the messages that are present contain a fileId that is within downloadingFileState
750+ val openWhenDownloadState = remember { mutableStateOf(false ) }
751+
752+ val visibleIds = listState.visibleItemsWithThreshold()
753+ LaunchedEffect (visibleIds, downloadingFileState.value) {
754+ openWhenDownloadState.value = (downloadingFileState.value.intersect(visibleIds).isNotEmpty())
755+ }
756+
736757 ChatView (
737758 state = ChatViewState (
738759 chatItems = uiState.items,
@@ -742,7 +763,8 @@ class ChatActivity :
742763 highlightedMessageId = uiState.highlightedMessageId,
743764 highlightedSearchTerm = uiState.highlightedSearchTerm,
744765 hasChatPermission = this ::participantPermissions.isInitialized &&
745- participantPermissions.hasChatPermission()
766+ participantPermissions.hasChatPermission(),
767+ downloadingFileState = downloadingFileState.value
746768 ),
747769 callbacks = ChatViewCallbacks (
748770 onLoadMore = { messageId, direction -> loadMoreMessages(messageId, direction) },
@@ -753,7 +775,7 @@ class ChatActivity :
753775 messageCallbacks = ChatMessageCallbacks (
754776 onLongClick = { openMessageActionsDialog(it) },
755777 onSwipeReply = { handleSwipeToReply(it) },
756- onFileClick = { downloadAndOpenFile(it) },
778+ onFileClick = { downloadAndOpenFile(it, openWhenDownloadState, downloadingFileState ) },
757779 onPollClick = { pollId, pollName -> openPollDialog(pollId, pollName) },
758780 onVoicePlayPauseClick = { onVoicePlayPauseClickCompose(it) },
759781 onVoiceSeek = { _, progress -> chatViewModel.seekToMediaPlayer(progress) },
@@ -791,6 +813,39 @@ class ChatActivity :
791813 }
792814 }
793815
816+ @Composable
817+ private fun LazyListState.visibleItemsWithThreshold (): List <String > =
818+ remember(this ) {
819+ derivedStateOf {
820+ val visibleItemsInfo = layoutInfo.visibleItemsInfo
821+ if (layoutInfo.totalItemsCount == 0 ) {
822+ emptyList()
823+ } else {
824+ visibleItemsInfo.mapNotNull { it.key as ? String }
825+ }
826+ }
827+ }.value.mapNotNull { key ->
828+ val messageItem = chatViewModel.uiState.collectAsState().value.items.firstOrNull { it.stableKey() == key }
829+ val message = messageItem?.messageOrNull()
830+ var result: String? = null
831+ message?.let {
832+ if (message.messageParameters.isNotEmpty()) {
833+ runCatching {
834+ message.messageParameters as HashMap <String ?, HashMap <String ?, String ?>>?
835+ val fileParameters = FileParameters (message.messageParameters)
836+ result = fileParameters.id
837+ }.onFailure { e ->
838+ when (e) {
839+ is ClassCastException -> {} // weird
840+ else -> Log .e(TAG , " Error in LazyListState.visibleItemsWithThreshold $e " )
841+ }
842+ }
843+ }
844+ }
845+
846+ result
847+ }
848+
794849 private fun onLoadQuotedMessage (messageId : Int ) {
795850 chatViewModel.jumpToQuotedMessage(messageId.toLong())
796851 }
@@ -856,10 +911,18 @@ class ChatActivity :
856911 chatViewModel.setVoiceMessageSpeed(messageId, nextSpeed)
857912 }
858913
859- fun downloadAndOpenFile (messageId : Int ) {
914+ fun downloadAndOpenFile (
915+ messageId : Int ,
916+ openWhenDownloadState : MutableState <Boolean >,
917+ downloadState : MutableState <List <String >>
918+ ) {
860919 lifecycleScope.launch {
861920 val chatMessage = chatViewModel.getMessageById(messageId.toLong()).first()
862- FileViewerUtils (this @ChatActivity, conversationUser).openFile(chatMessage)
921+ FileViewerUtils (this @ChatActivity, conversationUser).openFile(
922+ chatMessage,
923+ openWhenDownloadState,
924+ downloadState
925+ )
863926 }
864927 }
865928
0 commit comments