@@ -64,11 +64,16 @@ import androidx.cardview.widget.CardView
6464import androidx.compose.foundation.lazy.LazyListState
6565import androidx.compose.foundation.lazy.rememberLazyListState
6666import androidx.compose.material3.MaterialTheme
67+ import androidx.compose.runtime.Composable
6768import androidx.compose.runtime.CompositionLocalProvider
69+ import androidx.compose.runtime.LaunchedEffect
70+ import androidx.compose.runtime.MutableState
6871import androidx.compose.runtime.SideEffect
72+ import androidx.compose.runtime.derivedStateOf
6973import androidx.compose.runtime.getValue
7074import androidx.compose.runtime.mutableStateOf
7175import androidx.compose.runtime.produceState
76+ import androidx.compose.runtime.remember
7277import androidx.compose.runtime.setValue
7378import androidx.compose.ui.platform.ComposeView
7479import androidx.coordinatorlayout.widget.CoordinatorLayout
@@ -117,6 +122,8 @@ import com.nextcloud.talk.api.NcApi
117122import com.nextcloud.talk.api.NcApiCoroutines
118123import com.nextcloud.talk.application.NextcloudTalkApplication
119124import com.nextcloud.talk.chat.data.model.ChatMessage
125+ import com.nextcloud.talk.chat.data.model.FileParameters
126+ import com.nextcloud.talk.chat.ui.ShowReactionsModalBottomSheet
120127import com.nextcloud.talk.chat.ui.model.MessageTypeContent
121128import com.nextcloud.talk.chat.viewmodels.ChatViewModel
122129import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel
@@ -162,7 +169,6 @@ import com.nextcloud.talk.ui.dialog.FileAttachmentPreviewFragment
162169import com.nextcloud.talk.ui.dialog.GetPinnedOptionsDialog
163170import com.nextcloud.talk.ui.dialog.MessageActionsDialog
164171import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
165- import com.nextcloud.talk.chat.ui.ShowReactionsModalBottomSheet
166172import com.nextcloud.talk.ui.dialog.TempMessageActionsDialog
167173import com.nextcloud.talk.ui.theme.LocalMessageUtils
168174import com.nextcloud.talk.ui.theme.LocalOpenGraphFetcher
@@ -603,6 +609,7 @@ class ChatActivity :
603609 binding.messagesListViewCompose.visibility = View .VISIBLE
604610
605611 val listState = rememberLazyListState()
612+
606613 SideEffect { chatListState = listState }
607614
608615 CompositionLocalProvider (
@@ -613,21 +620,34 @@ class ChatActivity :
613620 val isOneToOneConversation = uiState.isOneToOneConversation
614621 Log .d(TAG , " isOneToOneConversation=" + isOneToOneConversation)
615622
623+ // list of the file ids of messages being downloaded
624+ val downloadingFileState = remember { mutableStateOf(listOf<String >()) }
625+
626+ // openWhenDownloaded is a derived boolean state of the visible chat message list on the condition
627+ // that if any of the messages that are present contain a fileId that is within downloadingFileState
628+ val openWhenDownloadState = remember { mutableStateOf(false ) }
629+
630+ val visibleIds = listState.visibleItemsWithThreshold()
631+ LaunchedEffect (visibleIds, downloadingFileState.value) {
632+ openWhenDownloadState.value = (downloadingFileState.value.intersect(visibleIds).isNotEmpty())
633+ }
634+
616635 ChatView (
617636 state = ChatViewState (
618637 chatItems = uiState.items,
619638 isOneToOneConversation = isOneToOneConversation,
620639 conversationThreadId = conversationThreadId,
621640 hasChatPermission = this ::participantPermissions.isInitialized &&
622- participantPermissions.hasChatPermission()
641+ participantPermissions.hasChatPermission(),
642+ downloadingFileState = downloadingFileState.value
623643 ),
624644 callbacks = ChatViewCallbacks (
625645 onLoadMore = { loadMoreMessagesCompose() },
626646 advanceLocalLastReadMessageIfNeeded = { advanceLocalLastReadMessageIfNeeded(it) },
627647 updateRemoteLastReadMessageIfNeeded = { updateRemoteLastReadMessageIfNeeded() },
628648 onLongClick = { openMessageActionsDialog(it) },
629649 onSwipeReply = { handleSwipeToReply(it) },
630- onFileClick = { downloadAndOpenFile(it) },
650+ onFileClick = { downloadAndOpenFile(it, openWhenDownloadState, downloadingFileState ) },
631651 onPollClick = { pollId, pollName -> openPollDialog(pollId, pollName) },
632652 onVoicePlayPauseClick = { onVoicePlayPauseClickCompose(it) },
633653 onVoiceSeek = { _, progress -> chatViewModel.seekToMediaPlayer(progress) },
@@ -662,6 +682,39 @@ class ChatActivity :
662682 }
663683 }
664684
685+ @Composable
686+ private fun LazyListState.visibleItemsWithThreshold (): List <String > =
687+ remember(this ) {
688+ derivedStateOf {
689+ val visibleItemsInfo = layoutInfo.visibleItemsInfo
690+ if (layoutInfo.totalItemsCount == 0 ) {
691+ emptyList()
692+ } else {
693+ visibleItemsInfo.toMutableList().map { it.key as String }
694+ }
695+ }
696+ }.value.mapNotNull { key ->
697+ val messageItem = chatViewModel.uiState.value.items.firstOrNull { it.stableKey() == key }
698+ val message = messageItem?.messageOrNull()
699+ var result: String? = null
700+ message?.let {
701+ if (message.messageParameters.isNotEmpty()) {
702+ runCatching {
703+ message.messageParameters as HashMap <String ?, HashMap <String ?, String ?>>?
704+ val fileParameters = FileParameters (message.messageParameters)
705+ result = fileParameters.id
706+ }.onFailure { e ->
707+ when (e) {
708+ is ClassCastException -> {} // weird
709+ else -> Log .e(TAG , " Error in LazyListState.visibleItemsWithThreshold $e " )
710+ }
711+ }
712+ }
713+ }
714+
715+ result
716+ }
717+
665718 private fun onLoadQuotedMessage (messageId : Int ) {
666719 // Loading and displaying surrounding messages for quotes is pending; replace flow from latestChatBlock with
667720 // other flow
@@ -730,10 +783,18 @@ class ChatActivity :
730783 chatViewModel.setVoiceMessageSpeed(messageId, nextSpeed)
731784 }
732785
733- fun downloadAndOpenFile (messageId : Int ) {
786+ fun downloadAndOpenFile (
787+ messageId : Int ,
788+ openWhenDownloadState : MutableState <Boolean >,
789+ downloadState : MutableState <List <String >>
790+ ) {
734791 lifecycleScope.launch {
735792 val chatMessage = chatViewModel.getMessageById(messageId.toLong()).first()
736- FileViewerUtils (this @ChatActivity, conversationUser).openFile(chatMessage)
793+ FileViewerUtils (this @ChatActivity, conversationUser).openFile(
794+ chatMessage,
795+ openWhenDownloadState,
796+ downloadState
797+ )
737798 }
738799 }
739800
@@ -3558,7 +3619,6 @@ class ChatActivity :
35583619
35593620 if (noteToSelfConversation != null ) {
35603621 var shareUri: Uri ? = null
3561- val data: HashMap <String , String >?
35623622 var metaData = " "
35633623 var objectId = " "
35643624 if (message.hasFileAttachment) {
0 commit comments