Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
### 🐞 Fixed

### ⬆️ Improved
- Fix `StrictMode` violations in the `AttachmentsPicker`. [#6029](https://github.com/GetStream/stream-chat-android/pull/6029)

### ✅ Added

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
Expand All @@ -61,6 +62,7 @@ import io.getstream.chat.android.compose.viewmodel.messages.AttachmentsPickerVie
import io.getstream.chat.android.models.Attachment
import io.getstream.chat.android.models.Channel
import io.getstream.chat.android.ui.common.state.messages.MessageMode
import kotlinx.coroutines.flow.collectLatest

/**
* Represents the bottom bar UI that allows users to pick attachments. The picker renders its
Expand Down Expand Up @@ -90,10 +92,16 @@ public fun AttachmentsPicker(
shape: Shape = ChatTheme.shapes.bottomSheet,
messageMode: MessageMode = MessageMode.Normal,
) {
// Listen for attachments to be ready for upload
LaunchedEffect(attachmentsPickerViewModel) {
attachmentsPickerViewModel.attachmentsForUpload.collectLatest {
onAttachmentsSelected(it)
}
}
val saveAttachmentsOnDismiss = ChatTheme.attachmentPickerTheme.saveAttachmentsOnDismiss
val dismissAction = {
if (saveAttachmentsOnDismiss) {
onAttachmentsSelected(attachmentsPickerViewModel.getSelectedAttachments())
attachmentsPickerViewModel.getSelectedAttachmentsAsync()
}
onDismiss()
}
Expand Down Expand Up @@ -144,7 +152,7 @@ public fun AttachmentsPicker(
attachmentsPickerViewModel.changeAttachmentPickerMode(attachmentPickerMode) { false }
},
onSendAttachmentsClick = {
onAttachmentsSelected(attachmentsPickerViewModel.getSelectedAttachments())
attachmentsPickerViewModel.getSelectedAttachmentsAsync()
},
)
}
Expand All @@ -171,7 +179,7 @@ public fun AttachmentsPicker(
onAttachmentItemSelected = attachmentsPickerViewModel::changeSelectedAttachments,
onAttachmentsChanged = { attachmentsPickerViewModel.attachments = it },
onAttachmentsSubmitted = {
onAttachmentsSelected(attachmentsPickerViewModel.getAttachmentsFromMetaData(it))
attachmentsPickerViewModel.getAttachmentsFromMetadataAsync(it)
},
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import io.getstream.chat.android.compose.R
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentPickerItemState
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentsPickerMode
Expand All @@ -55,6 +56,7 @@ import io.getstream.chat.android.ui.common.permissions.FilesAccess
import io.getstream.chat.android.ui.common.permissions.Permissions
import io.getstream.chat.android.ui.common.state.messages.composer.AttachmentMetaData
import io.getstream.chat.android.uiutils.util.openSystemSettings
import kotlinx.coroutines.flow.collectLatest

/**
* Holds the information required to add support for "files" tab in the attachment picker.
Expand Down Expand Up @@ -96,6 +98,7 @@ public class AttachmentsPickerFilesTabFactory : AttachmentsPickerTabFactory {
* @param onAttachmentItemSelected Handler when the item selection state changes.
* @param onAttachmentsSubmitted Handler to submit the selected attachments to the message composer.
*/
@Suppress("LongMethod")
@Composable
override fun PickerTabContent(
onAttachmentPickerAction: (AttachmentPickerAction) -> Unit,
Expand All @@ -106,8 +109,27 @@ public class AttachmentsPickerFilesTabFactory : AttachmentsPickerTabFactory {
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val storageHelper: StorageHelperWrapper = remember {
StorageHelperWrapper(context)
val processingViewModel = viewModel<AttachmentsProcessingViewModel>(
factory = AttachmentsProcessingViewModelFactory(StorageHelperWrapper(context.applicationContext)),
)
LaunchedEffect(processingViewModel) {
processingViewModel.attachmentsMetadataFromUris.collectLatest { metadata ->
// Check if some of the files were filtered out due to upload config
if (metadata.uris.size != metadata.attachmentsMetadata.size) {
Toast.makeText(
context,
R.string.stream_compose_message_composer_file_not_supported,
Toast.LENGTH_SHORT,
).show()
}
onAttachmentsSubmitted(metadata.attachmentsMetadata)
}
}
LaunchedEffect(processingViewModel) {
processingViewModel.filesMetadata.collectLatest { metaData ->
val items = metaData.map { AttachmentPickerItemState(it, false) }
onAttachmentsChanged(items)
}
}
var showPermanentlyDeniedSnackBar by remember { mutableStateOf(false) }
val permissionLauncher =
Expand All @@ -118,9 +140,7 @@ public class AttachmentsPickerFilesTabFactory : AttachmentsPickerTabFactory {
}
val filesAccess by filesAccessAsState(context, lifecycleOwner) { value ->
if (value != FilesAccess.DENIED) {
onAttachmentsChanged(
storageHelper.getFiles().map { AttachmentPickerItemState(it, false) },
)
processingViewModel.getFilesAsync()
}
}

Expand All @@ -135,17 +155,7 @@ public class AttachmentsPickerFilesTabFactory : AttachmentsPickerTabFactory {
files = attachments,
onItemSelected = onAttachmentItemSelected,
onBrowseFilesResult = { uris ->
val attachments = storageHelper.getAttachmentsMetadataFromUris(uris)
// Check if some of the files were filtered out due to upload config
if (uris.size != attachments.size) {
Toast.makeText(
context,
R.string.stream_compose_message_composer_file_not_supported,
Toast.LENGTH_SHORT,
).show()
}

onAttachmentsSubmitted(attachments)
processingViewModel.getAttachmentsMetadataFromUrisAsync(uris)
},
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import io.getstream.chat.android.compose.R
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentPickerItemState
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentsPickerMode
Expand All @@ -46,6 +47,7 @@ import io.getstream.chat.android.ui.common.permissions.Permissions
import io.getstream.chat.android.ui.common.permissions.VisualMediaAccess
import io.getstream.chat.android.ui.common.state.messages.composer.AttachmentMetaData
import io.getstream.chat.android.uiutils.util.openSystemSettings
import kotlinx.coroutines.flow.collectLatest

/**
* Holds the information required to add support for "images" tab in the attachment picker.
Expand Down Expand Up @@ -98,13 +100,18 @@ public class AttachmentsPickerImagesTabFactory : AttachmentsPickerTabFactory {
val permissions = Permissions.visualMediaPermissions()
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val storageHelper: StorageHelperWrapper =
remember { StorageHelperWrapper(context) }
val processingViewModel = viewModel<AttachmentsProcessingViewModel>(
factory = AttachmentsProcessingViewModelFactory(StorageHelperWrapper(context.applicationContext)),
)
LaunchedEffect(processingViewModel) {
processingViewModel.mediaMetadata.collectLatest { metaData ->
val items = metaData.map { AttachmentPickerItemState(it, false) }
onAttachmentsChanged(items)
}
}
val mediaAccess by visualMediaAccessAsState(context, lifecycleOwner) { value ->
if (value != VisualMediaAccess.DENIED) {
val media = storageHelper.getMedia()
val mediaAttachments = media.map { AttachmentPickerItemState(it, false) }
onAttachmentsChanged(mediaAttachments)
processingViewModel.getMediaAsync()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
Expand All @@ -81,6 +82,7 @@
import io.getstream.chat.android.ui.common.permissions.toContractVisualMediaType
import io.getstream.chat.android.ui.common.state.messages.composer.AttachmentMetaData
import io.getstream.chat.android.ui.common.utils.isPermissionDeclared
import kotlinx.coroutines.flow.collectLatest

/**
* Holds the information required to add support for "files" tab in the attachment picker.
Expand Down Expand Up @@ -200,7 +202,7 @@
@OptIn(ExperimentalPermissionsApi::class)
@Suppress("LongMethod")
@Composable
override fun PickerTabContent(

Check failure on line 205 in stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/factory/AttachmentsPickerSystemTabFactory.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-android&issues=AZrbjBvbtBD369zxRxXk&open=AZrbjBvbtBD369zxRxXk&pullRequest=6029
onAttachmentPickerAction: (AttachmentPickerAction) -> Unit,
attachments: List<AttachmentPickerItemState>,
onAttachmentsChanged: (List<AttachmentPickerItemState>) -> Unit,
Expand All @@ -208,27 +210,33 @@
onAttachmentsSubmitted: (List<AttachmentMetaData>) -> Unit,
) {
val context = LocalContext.current
val storageHelper: StorageHelperWrapper = remember {
StorageHelperWrapper(context)

val processingViewModel = viewModel<AttachmentsProcessingViewModel>(
factory = AttachmentsProcessingViewModelFactory(StorageHelperWrapper(context.applicationContext)),
)

LaunchedEffect(processingViewModel) {
processingViewModel.attachmentsMetadataFromUris.collectLatest { metadata ->
// Check if some of the files were filtered out due to upload config
if (metadata.uris.size != metadata.attachmentsMetadata.size) {
Toast.makeText(
context,
R.string.stream_compose_message_composer_file_not_supported,
Toast.LENGTH_SHORT,
).show()
}
onAttachmentsSubmitted(metadata.attachmentsMetadata)
}
}

val filePickerLauncher = rememberFilePickerLauncher { uri ->
val uris = listOf(uri)
val attachments = storageHelper.getAttachmentsMetadataFromUris(uris)
// Check if some of the files were filtered out due to upload config
if (uris.size != attachments.size) {
Toast.makeText(
context,
R.string.stream_compose_message_composer_file_not_supported,
Toast.LENGTH_SHORT,
).show()
}
onAttachmentsSubmitted(attachments)
processingViewModel.getAttachmentsMetadataFromUrisAsync(uris)
}

val imagePickerLauncher =
rememberVisualMediaPickerLauncher(config.visualMediaAllowMultiple) { uris ->
onAttachmentsSubmitted(storageHelper.getAttachmentsMetadataFromUris(uris))
processingViewModel.getAttachmentsMetadataFromUrisAsync(uris)
}

val captureLauncher = rememberCaptureMediaLauncher(
Expand Down
Loading
Loading