From 28cb80fbb8d4fff487896a9181908e3c1fce5e1d Mon Sep 17 00:00:00 2001 From: benya Date: Wed, 11 Mar 2026 23:10:56 +0300 Subject: [PATCH] Reduce ChatScreen parameter footprint to avoid verifier crash --- .../messenger/ui/chat/ChatScreen.kt | 305 ++++++++++-------- 1 file changed, 175 insertions(+), 130 deletions(-) diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt index 093ed08..d10f080 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt @@ -311,100 +311,102 @@ fun ChatRoute( ChatScreen( state = state, - onBack = onBack, - onInputChanged = viewModel::onInputChanged, - onSendClick = viewModel::onSendClick, - onSelectMessage = viewModel::onSelectMessage, - onEnterMultiSelect = viewModel::onEnterMultiSelect, - onToggleMessageMultiSelection = viewModel::onToggleMessageMultiSelection, - onClearSelection = viewModel::onClearSelection, - onReplySelected = viewModel::onReplySelected, - onEditSelected = viewModel::onEditSelected, - onDeleteSelected = viewModel::onDeleteSelected, - onForwardSelected = viewModel::onForwardSelected, - onForwardDismiss = viewModel::onForwardDismiss, - onForwardTargetSelected = viewModel::onForwardTargetSelected, - onToggleReaction = viewModel::onToggleReaction, - onCancelComposeAction = viewModel::onCancelComposeAction, - onLoadMore = viewModel::loadMore, - onPickMedia = { pickMediaLauncher.launch("*/*") }, - onCapturePhoto = { takePhotoLauncher.launch(null) }, - onCaptureVideo = { - val file = createTempCaptureFile(context = context, prefix = "camera_video_", suffix = ".mp4") - val uri = FileProvider.getUriForFile( - context, - "${context.packageName}.fileprovider", - file, - ) - pendingCaptureVideoFile = file - pendingCaptureVideoUri = uri - captureVideoLauncher.launch(uri) - }, - onCaptureCircleVideo = { - if (hasCameraPermission) { - showCircleRecorder = true - } else { - openCircleAfterPermissionGrant = true - circlePermissionLauncher.launch( - arrayOf( - Manifest.permission.CAMERA, - Manifest.permission.RECORD_AUDIO, - ), + actions = ChatScreenActions( + onBack = onBack, + onInputChanged = viewModel::onInputChanged, + onSendClick = viewModel::onSendClick, + onSelectMessage = viewModel::onSelectMessage, + onEnterMultiSelect = viewModel::onEnterMultiSelect, + onToggleMessageMultiSelection = viewModel::onToggleMessageMultiSelection, + onClearSelection = viewModel::onClearSelection, + onReplySelected = viewModel::onReplySelected, + onEditSelected = viewModel::onEditSelected, + onDeleteSelected = viewModel::onDeleteSelected, + onForwardSelected = viewModel::onForwardSelected, + onForwardDismiss = viewModel::onForwardDismiss, + onForwardTargetSelected = viewModel::onForwardTargetSelected, + onToggleReaction = viewModel::onToggleReaction, + onCancelComposeAction = viewModel::onCancelComposeAction, + onLoadMore = viewModel::loadMore, + onPickMedia = { pickMediaLauncher.launch("*/*") }, + onCapturePhoto = { takePhotoLauncher.launch(null) }, + onCaptureVideo = { + val file = createTempCaptureFile(context = context, prefix = "camera_video_", suffix = ".mp4") + val uri = FileProvider.getUriForFile( + context, + "${context.packageName}.fileprovider", + file, ) - } - }, - onSendRemoteMedia = { fileName, mimeType, bytes -> - viewModel.onMediaPicked( - fileName = fileName, - mimeType = mimeType, - bytes = bytes, - ) - }, - onSendPresetMediaUrl = viewModel::onSendPresetMediaUrl, - onVoiceRecordStart = { - if (!hasAudioPermission) { - startRecordingAfterPermissionGrant = true - audioPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO) - } else { - startVoiceRecording() - } - }, - onVoiceRecordTick = { - viewModel.onVoiceRecordTick(voiceRecorder.elapsedMillis()) - }, - onVoiceRecordLock = viewModel::onVoiceRecordLocked, - onVoiceRecordCancel = { - voiceRecorder.cancel() - AppAudioFocusCoordinator.release("voice-recording") - viewModel.onVoiceRecordCancelled() - }, - onVoiceRecordSend = { - val duration = voiceRecorder.elapsedMillis() - val bytes = voiceRecorder.stopAndReadBytes() - AppAudioFocusCoordinator.release("voice-recording") - if (bytes != null && bytes.isNotEmpty()) { - viewModel.onVoiceRecordFinish( - fileName = "voice_${System.currentTimeMillis()}.m4a", - mimeType = "audio/mp4", + pendingCaptureVideoFile = file + pendingCaptureVideoUri = uri + captureVideoLauncher.launch(uri) + }, + onCaptureCircleVideo = { + if (hasCameraPermission) { + showCircleRecorder = true + } else { + openCircleAfterPermissionGrant = true + circlePermissionLauncher.launch( + arrayOf( + Manifest.permission.CAMERA, + Manifest.permission.RECORD_AUDIO, + ), + ) + } + }, + onSendRemoteMedia = { fileName, mimeType, bytes -> + viewModel.onMediaPicked( + fileName = fileName, + mimeType = mimeType, bytes = bytes, - durationMs = duration, ) - } else { + }, + onSendPresetMediaUrl = viewModel::onSendPresetMediaUrl, + onVoiceRecordStart = { + if (!hasAudioPermission) { + startRecordingAfterPermissionGrant = true + audioPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO) + } else { + startVoiceRecording() + } + }, + onVoiceRecordTick = { + viewModel.onVoiceRecordTick(voiceRecorder.elapsedMillis()) + }, + onVoiceRecordLock = viewModel::onVoiceRecordLocked, + onVoiceRecordCancel = { + voiceRecorder.cancel() + AppAudioFocusCoordinator.release("voice-recording") viewModel.onVoiceRecordCancelled() - } - }, - onInlineSearchChanged = viewModel::onInlineSearchChanged, - onJumpInlineSearch = viewModel::jumpInlineSearch, - onVisibleIncomingMessageId = viewModel::onVisibleIncomingMessageId, - onToggleChatNotifications = viewModel::onToggleChatNotifications, - onClearHistory = viewModel::onClearHistory, - onDeleteChat = viewModel::onDeleteOrLeaveChat, - onPromoteMember = viewModel::promoteMember, - onDemoteMember = viewModel::demoteMember, - onBanMember = viewModel::banMember, - onKickMember = viewModel::kickMember, - onTransferOwnership = viewModel::transferOwnership, - onUnbanMember = viewModel::unbanMember, + }, + onVoiceRecordSend = { + val duration = voiceRecorder.elapsedMillis() + val bytes = voiceRecorder.stopAndReadBytes() + AppAudioFocusCoordinator.release("voice-recording") + if (bytes != null && bytes.isNotEmpty()) { + viewModel.onVoiceRecordFinish( + fileName = "voice_${System.currentTimeMillis()}.m4a", + mimeType = "audio/mp4", + bytes = bytes, + durationMs = duration, + ) + } else { + viewModel.onVoiceRecordCancelled() + } + }, + onInlineSearchChanged = viewModel::onInlineSearchChanged, + onJumpInlineSearch = viewModel::jumpInlineSearch, + onVisibleIncomingMessageId = viewModel::onVisibleIncomingMessageId, + onToggleChatNotifications = viewModel::onToggleChatNotifications, + onClearHistory = viewModel::onClearHistory, + onDeleteChat = viewModel::onDeleteOrLeaveChat, + onPromoteMember = viewModel::promoteMember, + onDemoteMember = viewModel::demoteMember, + onBanMember = viewModel::banMember, + onKickMember = viewModel::kickMember, + onTransferOwnership = viewModel::transferOwnership, + onUnbanMember = viewModel::unbanMember, + ), ) if (showCircleRecorder) { CircleVideoRecorderDialog( @@ -422,50 +424,93 @@ fun ChatRoute( } } +private data class ChatScreenActions( + val onBack: () -> Unit, + val onInputChanged: (String) -> Unit, + val onSendClick: () -> Unit, + val onSelectMessage: (MessageItem?) -> Unit, + val onEnterMultiSelect: (MessageItem) -> Unit, + val onToggleMessageMultiSelection: (MessageItem) -> Unit, + val onClearSelection: () -> Unit, + val onReplySelected: (MessageItem) -> Unit, + val onEditSelected: (MessageItem) -> Unit, + val onDeleteSelected: (Boolean) -> Unit, + val onForwardSelected: () -> Unit, + val onForwardDismiss: () -> Unit, + val onForwardTargetSelected: (Long) -> Unit, + val onToggleReaction: (String) -> Unit, + val onCancelComposeAction: () -> Unit, + val onLoadMore: () -> Unit, + val onPickMedia: () -> Unit, + val onCapturePhoto: () -> Unit, + val onCaptureVideo: () -> Unit, + val onCaptureCircleVideo: () -> Unit, + val onSendRemoteMedia: (String, String, ByteArray) -> Unit, + val onSendPresetMediaUrl: (String) -> Unit, + val onVoiceRecordStart: () -> Unit, + val onVoiceRecordTick: () -> Unit, + val onVoiceRecordLock: () -> Unit, + val onVoiceRecordCancel: () -> Unit, + val onVoiceRecordSend: () -> Unit, + val onInlineSearchChanged: (String) -> Unit, + val onJumpInlineSearch: (Boolean) -> Unit, + val onVisibleIncomingMessageId: (Long?) -> Unit, + val onToggleChatNotifications: () -> Unit, + val onClearHistory: () -> Unit, + val onDeleteChat: () -> Unit, + val onPromoteMember: (Long) -> Unit, + val onDemoteMember: (Long) -> Unit, + val onBanMember: (Long) -> Unit, + val onKickMember: (Long) -> Unit, + val onTransferOwnership: (Long) -> Unit, + val onUnbanMember: (Long) -> Unit, +) + @OptIn(ExperimentalMaterial3Api::class) @Composable -fun ChatScreen( +private fun ChatScreen( state: MessageUiState, - onBack: () -> Unit, - onInputChanged: (String) -> Unit, - onSendClick: () -> Unit, - onSelectMessage: (MessageItem?) -> Unit, - onEnterMultiSelect: (MessageItem) -> Unit, - onToggleMessageMultiSelection: (MessageItem) -> Unit, - onClearSelection: () -> Unit, - onReplySelected: (MessageItem) -> Unit, - onEditSelected: (MessageItem) -> Unit, - onDeleteSelected: (Boolean) -> Unit, - onForwardSelected: () -> Unit, - onForwardDismiss: () -> Unit, - onForwardTargetSelected: (Long) -> Unit, - onToggleReaction: (String) -> Unit, - onCancelComposeAction: () -> Unit, - onLoadMore: () -> Unit, - onPickMedia: () -> Unit, - onCapturePhoto: () -> Unit, - onCaptureVideo: () -> Unit, - onCaptureCircleVideo: () -> Unit, - onSendRemoteMedia: (String, String, ByteArray) -> Unit, - onSendPresetMediaUrl: (String) -> Unit, - onVoiceRecordStart: () -> Unit, - onVoiceRecordTick: () -> Unit, - onVoiceRecordLock: () -> Unit, - onVoiceRecordCancel: () -> Unit, - onVoiceRecordSend: () -> Unit, - onInlineSearchChanged: (String) -> Unit, - onJumpInlineSearch: (Boolean) -> Unit, - onVisibleIncomingMessageId: (Long?) -> Unit, - onToggleChatNotifications: () -> Unit, - onClearHistory: () -> Unit, - onDeleteChat: () -> Unit, - onPromoteMember: (Long) -> Unit, - onDemoteMember: (Long) -> Unit, - onBanMember: (Long) -> Unit, - onKickMember: (Long) -> Unit, - onTransferOwnership: (Long) -> Unit, - onUnbanMember: (Long) -> Unit, + actions: ChatScreenActions, ) { + val onBack = actions.onBack + val onInputChanged = actions.onInputChanged + val onSendClick = actions.onSendClick + val onSelectMessage = actions.onSelectMessage + val onEnterMultiSelect = actions.onEnterMultiSelect + val onToggleMessageMultiSelection = actions.onToggleMessageMultiSelection + val onClearSelection = actions.onClearSelection + val onReplySelected = actions.onReplySelected + val onEditSelected = actions.onEditSelected + val onDeleteSelected = actions.onDeleteSelected + val onForwardSelected = actions.onForwardSelected + val onForwardDismiss = actions.onForwardDismiss + val onForwardTargetSelected = actions.onForwardTargetSelected + val onToggleReaction = actions.onToggleReaction + val onCancelComposeAction = actions.onCancelComposeAction + val onLoadMore = actions.onLoadMore + val onPickMedia = actions.onPickMedia + val onCapturePhoto = actions.onCapturePhoto + val onCaptureVideo = actions.onCaptureVideo + val onCaptureCircleVideo = actions.onCaptureCircleVideo + val onSendRemoteMedia = actions.onSendRemoteMedia + val onSendPresetMediaUrl = actions.onSendPresetMediaUrl + val onVoiceRecordStart = actions.onVoiceRecordStart + val onVoiceRecordTick = actions.onVoiceRecordTick + val onVoiceRecordLock = actions.onVoiceRecordLock + val onVoiceRecordCancel = actions.onVoiceRecordCancel + val onVoiceRecordSend = actions.onVoiceRecordSend + val onInlineSearchChanged = actions.onInlineSearchChanged + val onJumpInlineSearch = actions.onJumpInlineSearch + val onVisibleIncomingMessageId = actions.onVisibleIncomingMessageId + val onToggleChatNotifications = actions.onToggleChatNotifications + val onClearHistory = actions.onClearHistory + val onDeleteChat = actions.onDeleteChat + val onPromoteMember = actions.onPromoteMember + val onDemoteMember = actions.onDemoteMember + val onBanMember = actions.onBanMember + val onKickMember = actions.onKickMember + val onTransferOwnership = actions.onTransferOwnership + val onUnbanMember = actions.onUnbanMember val context = LocalContext.current val view = LocalView.current val listState = rememberLazyListState()