feat(talk): меню сообщения — Переслать… в любую комнату (пикер) [P1]
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
<ID>LongMethod:TalkComponents.kt$@Composable fun TalkRoomRow( room: TalkRoom, session: AuthSession, modifier: Modifier = Modifier, onClick: () -> Unit, onToggleFavorite: () -> Unit = {}, onMarkUnread: () -> Unit = {}, )</ID>
|
||||
<ID>LongMethod:TalkComponents.kt$@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @Composable fun TalkCreateRoomSheet( visible: Boolean, session: AuthSession, mode: CreateRoomMode, roomName: String, userSearchQuery: String, userSearchResults: List<TalkUserCandidate>, selectedUsers: List<TalkUserCandidate>, userSearchLoading: Boolean, creating: Boolean, onDismiss: () -> Unit, onModeChange: (CreateRoomMode) -> Unit, onRoomNameChange: (String) -> Unit, onUserSearchChange: (String) -> Unit, onUserToggle: (TalkUserCandidate) -> Unit, onCreate: () -> Unit, )</ID>
|
||||
<ID>LongMethod:TalkScreen.kt$@Composable fun TalkScreen( session: AuthSession, modifier: Modifier = Modifier, openRoomToken: String? = null, scrollToMessageId: Long? = null, chatsListRequest: Int = 0, pushSyncRequest: Int = 0, pushRoomToken: String? = null, onOpenRoomConsumed: () -> Unit = {}, onRoomOpenStateChange: (Boolean) -> Unit = {}, onOpenCalendar: () -> Unit = {}, onUnauthorized: () -> Unit = {}, )</ID>
|
||||
<ID>LongMethod:TalkScreen.kt$@Composable private fun ChatContent( session: AuthSession, state: TalkUiState, draft: String, onDraftChange: (String) -> Unit, onSend: () -> Unit, onAttach: () -> Unit, onVoiceToggle: () -> Unit, voiceRecording: Boolean, onRetry: () -> Unit, onStartCall: () -> Unit, onBackClick: () -> Unit, onOpenRoomInfo: () -> Unit, onScheduleMeeting: () -> Unit, onToggleSystemMessages: () -> Unit, onReply: (TalkMessage) -> Unit, onReplyPrivately: (TalkMessage) -> Unit, onReaction: (TalkMessage, String) -> Unit, onDeleteMessage: (TalkMessage) -> Unit, onEditMessage: (TalkMessage, String) -> Unit, onForwardNoteToSelf: (TalkMessage) -> Unit, onSetReminder: (TalkMessage, ReminderPreset) -> Unit, onMentionQuery: (String?) -> Unit, onMentionSelected: (TalkMention) -> Unit, onClearReply: () -> Unit, onClearHighlight: () -> Unit, )</ID>
|
||||
<ID>LongMethod:TalkScreen.kt$@Composable private fun ChatContent( session: AuthSession, state: TalkUiState, draft: String, onDraftChange: (String) -> Unit, onSend: () -> Unit, onAttach: () -> Unit, onVoiceToggle: () -> Unit, voiceRecording: Boolean, onRetry: () -> Unit, onStartCall: () -> Unit, onBackClick: () -> Unit, onOpenRoomInfo: () -> Unit, onScheduleMeeting: () -> Unit, onToggleSystemMessages: () -> Unit, onReply: (TalkMessage) -> Unit, onReplyPrivately: (TalkMessage) -> Unit, onReaction: (TalkMessage, String) -> Unit, onDeleteMessage: (TalkMessage) -> Unit, onEditMessage: (TalkMessage, String) -> Unit, onForwardNoteToSelf: (TalkMessage) -> Unit, onForwardToRoom: (TalkMessage, String) -> Unit, onSetReminder: (TalkMessage, ReminderPreset) -> Unit, onMentionQuery: (String?) -> Unit, onMentionSelected: (TalkMention) -> Unit, onClearReply: () -> Unit, onClearHighlight: () -> Unit, )</ID>
|
||||
<ID>LoopWithTooManyJumpStatements:TalkRepository.kt$TalkRepository$for</ID>
|
||||
<ID>LoopWithTooManyJumpStatements:TalkViewModel.kt$TalkViewModel$while</ID>
|
||||
<ID>MatchingDeclarationName:TalkFilters.kt$TalkRoomFilter</ID>
|
||||
|
||||
@@ -794,6 +794,39 @@ fun TalkUnreadMarker(modifier: Modifier = Modifier) {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ForwardTargetSheet(
|
||||
message: TalkMessage?,
|
||||
rooms: List<TalkRoom>,
|
||||
onDismiss: () -> Unit,
|
||||
onPick: (TalkMessage, TalkRoom) -> Unit,
|
||||
) {
|
||||
if (message == null) return
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = F7Colors.Surface) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
"Переслать в…",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = F7Colors.TextSecondary,
|
||||
)
|
||||
LazyColumn(modifier = Modifier.heightIn(max = 360.dp)) {
|
||||
items(rooms, key = { it.token }) { room ->
|
||||
F7TextButton(text = room.displayName, onClick = { onPick(message, room) })
|
||||
}
|
||||
}
|
||||
F7TextButton(text = "Отмена", onClick = onDismiss)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TalkMessageActionSheet(
|
||||
@@ -809,6 +842,7 @@ fun TalkMessageActionSheet(
|
||||
onCopy: (TalkMessage) -> Unit,
|
||||
onCopyLink: (TalkMessage) -> Unit,
|
||||
onForwardNoteToSelf: (TalkMessage) -> Unit,
|
||||
onForward: (TalkMessage) -> Unit,
|
||||
onSetReminder: (TalkMessage, ReminderPreset) -> Unit,
|
||||
) {
|
||||
if (message == null) return
|
||||
@@ -847,6 +881,7 @@ fun TalkMessageActionSheet(
|
||||
text = "Переслать в «Личные заметки»",
|
||||
onClick = { onForwardNoteToSelf(message) },
|
||||
)
|
||||
F7TextButton(text = "Переслать…", onClick = { onForward(message) })
|
||||
Text(
|
||||
"Напоминание:",
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
|
||||
@@ -297,6 +297,7 @@ fun TalkScreen(
|
||||
onDeleteMessage = { vm.deleteMessage(session, it.id) },
|
||||
onEditMessage = { msg, text -> vm.editMessage(session, msg.id, text) },
|
||||
onForwardNoteToSelf = { vm.forwardToNoteToSelf(session, it) },
|
||||
onForwardToRoom = { msg, token -> vm.forwardToRoom(session, msg, token) },
|
||||
onSetReminder = { msg, preset -> vm.setMessageReminder(session, msg.id, preset) },
|
||||
onMentionQuery = { vm.setMentionQuery(session, it) },
|
||||
onMentionSelected = { mention ->
|
||||
@@ -416,16 +417,42 @@ private fun RoomListContent(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConfirmDeleteMessageDialog(
|
||||
message: TalkMessage?,
|
||||
onConfirm: (TalkMessage) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
if (message == null) return
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text("Удалить сообщение?") },
|
||||
text = { Text("Сообщение будет удалено для всех участников.") },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { onConfirm(message) }) {
|
||||
Text("Удалить", color = F7Colors.Primary)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text("Отмена")
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageActionOverlays(
|
||||
actionMessage: TalkMessage?,
|
||||
session: AuthSession,
|
||||
roomToken: String?,
|
||||
rooms: List<TalkRoom>,
|
||||
onClearAction: () -> Unit,
|
||||
onReply: (TalkMessage) -> Unit,
|
||||
onReplyPrivately: (TalkMessage) -> Unit,
|
||||
onReaction: (TalkMessage, String) -> Unit,
|
||||
onForwardNoteToSelf: (TalkMessage) -> Unit,
|
||||
onForwardToRoom: (TalkMessage, String) -> Unit,
|
||||
onSetReminder: (TalkMessage, ReminderPreset) -> Unit,
|
||||
onEditMessage: (TalkMessage, String) -> Unit,
|
||||
onDeleteMessage: (TalkMessage) -> Unit,
|
||||
@@ -435,6 +462,7 @@ private fun MessageActionOverlays(
|
||||
var editingMessage by remember { mutableStateOf<TalkMessage?>(null) }
|
||||
var editDraft by remember { mutableStateOf("") }
|
||||
var pendingDelete by remember { mutableStateOf<TalkMessage?>(null) }
|
||||
var forwardMessage by remember { mutableStateOf<TalkMessage?>(null) }
|
||||
|
||||
TalkMessageActionSheet(
|
||||
message = actionMessage,
|
||||
@@ -483,6 +511,10 @@ private fun MessageActionOverlays(
|
||||
Toast.makeText(context, "Переслано в «Личные заметки»", Toast.LENGTH_SHORT).show()
|
||||
onClearAction()
|
||||
},
|
||||
onForward = { msg ->
|
||||
forwardMessage = msg
|
||||
onClearAction()
|
||||
},
|
||||
onSetReminder = { msg, preset ->
|
||||
onSetReminder(msg, preset)
|
||||
Toast.makeText(context, "Напоминание установлено", Toast.LENGTH_SHORT).show()
|
||||
@@ -518,26 +550,25 @@ private fun MessageActionOverlays(
|
||||
)
|
||||
}
|
||||
|
||||
pendingDelete?.let { message ->
|
||||
AlertDialog(
|
||||
onDismissRequest = { pendingDelete = null },
|
||||
title = { Text("Удалить сообщение?") },
|
||||
text = { Text("Сообщение будет удалено для всех участников.") },
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
onDeleteMessage(message)
|
||||
pendingDelete = null
|
||||
}) {
|
||||
Text("Удалить", color = F7Colors.Primary)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { pendingDelete = null }) {
|
||||
Text("Отмена")
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
ConfirmDeleteMessageDialog(
|
||||
message = pendingDelete,
|
||||
onConfirm = {
|
||||
onDeleteMessage(it)
|
||||
pendingDelete = null
|
||||
},
|
||||
onDismiss = { pendingDelete = null },
|
||||
)
|
||||
|
||||
ForwardTargetSheet(
|
||||
message = forwardMessage,
|
||||
rooms = rooms.filter { it.token != roomToken },
|
||||
onDismiss = { forwardMessage = null },
|
||||
onPick = { msg, room ->
|
||||
onForwardToRoom(msg, room.token)
|
||||
forwardMessage = null
|
||||
Toast.makeText(context, "Переслано", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -562,6 +593,7 @@ private fun ChatContent(
|
||||
onDeleteMessage: (TalkMessage) -> Unit,
|
||||
onEditMessage: (TalkMessage, String) -> Unit,
|
||||
onForwardNoteToSelf: (TalkMessage) -> Unit,
|
||||
onForwardToRoom: (TalkMessage, String) -> Unit,
|
||||
onSetReminder: (TalkMessage, ReminderPreset) -> Unit,
|
||||
onMentionQuery: (String?) -> Unit,
|
||||
onMentionSelected: (TalkMention) -> Unit,
|
||||
@@ -618,11 +650,13 @@ private fun ChatContent(
|
||||
actionMessage = actionMessage,
|
||||
session = session,
|
||||
roomToken = state.selectedRoomToken,
|
||||
rooms = state.rooms,
|
||||
onClearAction = { actionMessage = null },
|
||||
onReply = onReply,
|
||||
onReplyPrivately = onReplyPrivately,
|
||||
onReaction = onReaction,
|
||||
onForwardNoteToSelf = onForwardNoteToSelf,
|
||||
onForwardToRoom = onForwardToRoom,
|
||||
onSetReminder = onSetReminder,
|
||||
onEditMessage = onEditMessage,
|
||||
onDeleteMessage = onDeleteMessage,
|
||||
|
||||
@@ -625,6 +625,21 @@ class TalkViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/** Переслать текст сообщения в выбранную комнату. */
|
||||
fun forwardToRoom(session: AuthSession, message: TalkMessage, targetToken: String) {
|
||||
val text = message.displayText.trim()
|
||||
if (text.isEmpty() || targetToken.isBlank()) return
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
runCatching { repository.sendMessage(session, targetToken, text) }
|
||||
.onFailure { t ->
|
||||
_state.value = _state.value.copy(
|
||||
error = t.message ?: "Не удалось переслать",
|
||||
unauthorized = t is UnauthorizedException,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Ответить лично: открыть (или создать) 1:1 с автором сообщения. */
|
||||
fun replyPrivately(session: AuthSession, message: TalkMessage) {
|
||||
val userId = message.actorId
|
||||
|
||||
Reference in New Issue
Block a user