-
Notifications
You must be signed in to change notification settings - Fork 317
Expand file tree
/
Copy pathChatBuilderParameters.swift
More file actions
100 lines (90 loc) · 5.07 KB
/
ChatBuilderParameters.swift
File metadata and controls
100 lines (90 loc) · 5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//
// SwiftUIView.swift
//
//
// Created by Alisa Mylnikova on 06.12.2023.
//
import SwiftUI
/// To build a custom message view use the following parameters passed by builder closure:
/// - message containing user, attachments, etc.
/// - position of message in its continuous group of messages from the same user
/// - position of message in the section of messages from that day
/// - position of message in its continuous group of comments (only works for .answer ReplyMode, nil for .quote mode)
/// - closure to show message context menu
/// - closure to pass user interaction, .reply for example
/// - pass attachment to this closure to use ChatView's fullscreen media viewer
public struct MessageBuilderParameters {
public let message: Message
public let positionInGroup: PositionInUserGroup
public let positionInMessagesSection: PositionInMessagesSection
public let positionInCommentsGroup: CommentsPosition?
public let showContextMenuClosure: () -> Void
public let messageActionClosure: (Message, DefaultMessageMenuAction) -> Void
public let showAttachmentClosure: (Attachment) -> Void
@MainActor public func defaultMessageView() -> some View {
DefaultMessageView(params: self)
}
}
/// To build a custom input view use the following parameters passed by builder closure:
/// - binding to the text in input view
/// - InputViewAttachments to store the attachments from external pickers
/// - current input view state: .message for main input view mode and .signature for input view in media picker mode
/// - closure to pass user interaction, .recordAudioTap for example
/// - dismiss keyboard closure
public struct InputViewBuilderParameters {
public let text: Binding<String>
public let attachments: InputViewAttachments
public let inputViewState: InputViewState
public let inputViewStyle: InputViewStyle
public let inputViewActionClosure: (InputViewAction) -> Void
public let dismissKeyboardClosure: ()->()
}
extension ChatView {
public typealias MessageBuilderParamsClosure = (_ params: MessageBuilderParameters) -> MessageContent
public typealias InputViewBuilderParamsClosure = (_ params: InputViewBuilderParameters) -> InputViewContent
/// To define custom message menu actions declare an enum conforming to MessageMenuAction. The library will show your custom menu options on long tap on message. Once the action is selected the following callback will be called:
/// - action selected by the user from the menu. NOTE: when declaring this variable, specify its type (your custom descendant of MessageMenuAction) explicitly
/// - a closure taking a case of default implementation of MessageMenuAction which provides simple actions handlers; you call this closure passing the selected message and choosing one of the default actions if you need them; or you can write a custom implementation for all your actions, in that case just ignore this closure
/// - message for which the menu is displayed
/// When implementing your own MessageMenuActionClosure, write a switch statement passing through all the cases of your MessageMenuAction, inside each case write your own action handler, or call the default one. NOTE: not all default actions work out of the box - e.g. for .edit you'll still need to provide a closure to save the edited text on your BE. Please see CommentsExampleView in ChatExample project for MessageMenuActionClosure usage example.
public typealias MessageMenuActionClosure = (
_ selectedMenuAction: MenuAction,
_ defaultActionClosure: @escaping (Message, DefaultMessageMenuAction) -> Void,
_ message: Message
) -> Void
public init(
messages: [Message],
chatType: ChatType = .conversation,
replyMode: ReplyMode = .quote,
didSendMessage: @escaping (DraftMessage) -> Void,
@ViewBuilder messageBuilder: @escaping (_ params: MessageBuilderParameters) -> MessageContent = { _ in
DummyView()
},
@ViewBuilder inputViewBuilder: @escaping (_ params: InputViewBuilderParameters) -> InputViewContent = { _ in
DummyView()
},
messageMenuAction: @escaping (
_ selectedMenuAction: MenuAction,
_ defaultActionClosure: @escaping (Message, DefaultMessageMenuAction) -> Void,
_ message: Message
) -> Void = { (selectedMenuAction: DefaultMessageMenuAction, defaultActionClosure, message) in
defaultActionClosure(message, selectedMenuAction)
},
didUpdateAttachmentStatus: ((AttachmentUploadUpdate) -> Void)? = nil
) {
self.type = chatType
self.sections = ChatView.mapMessages(messages, chatType: chatType, replyMode: replyMode)
self.ids = messages.map { $0.id }
self.didSendMessage = didSendMessage
self.messageBuilder = messageBuilder
self.inputViewBuilder = inputViewBuilder
self.messageMenuAction = messageMenuAction
self.didUpdateAttachmentStatus = didUpdateAttachmentStatus
}
}
public struct DummyView: View {
public init() {}
public var body: some View {
EmptyView()
}
}