exyte / chat Goto Github PK
View Code? Open in Web Editor NEWA SwiftUI Chat UI framework with fully customizable message cells and a built-in media picker
License: MIT License
A SwiftUI Chat UI framework with fully customizable message cells and a built-in media picker
License: MIT License
Is it possible to add a 'user is typing' feature. Something like a message bubble with three dots and list of chat-users in the caption-label bellow the buble, indicating who is currently typing in the chat?
After updating to 1.2.2 from 1.0.3, I'm getting Errors during compile in the latest Xcode 15.0.1 with iOS 17:
This is the code snippet in MessagesMenu.swift > body:
var body: some View {
FloatingButton(mainButtonView: mainButton().allowsHitTesting(false), buttons: [
menuButton(title: "Reply", icon: theme.images.messageMenu.reply, action: .reply)
], isOpen: $isShowingMenu)
.straight()
.mainZStackAlignment(.top)
.initialOpacity(0)
.direction(.bottom)
.alignment(alignment)
.spacing(2)
.animation(.linear(duration: 0.2))
.menuButtonsSize($menuButtonsSize)
}
Link to code in GH repo: https://github.com/exyte/Chat/blob/main/Sources/ExyteChat/ChatView/MessageView/MessageMenu.swift#L33
I tried resetting the SPM package cache and cleaning the project but the issue persists. Any ideas?
Is there a way to only allow text as a message type? My app doesn't intend to send photos and I'd prefer not to fill out a NSPhotoLibraryUsageDescription
since it really isn't needed.
As a suggestion - it may be helpful to first time users to outline what Privacy descriptions they may need so they can avoid the crash as well.
I am interfacing with OpenAI's SSE format API, and I tried to update the content of corresponding messages. It can be confirmed that the message has been updated, but I did not see the update in the UI. Is there a problem with the way I call it?thx
My code
private func updateBotMessage(_ text: String, messageId: String?) {
DispatchQueue.main.async {
if let currentId = self.currentBotMessageId,
let index = self.messages.firstIndex(where: { $0.id == currentId }) {
var updatedMessage = self.messages[index]
updatedMessage.text += text
self.messages[index] = updatedMessage
} else {
let newId = messageId ?? UUID().uuidString
let newMessage = Message(
id: newId,
user: self.botUser,
status: .sent,
createdAt: Date(),
text: text
)
self.messages.append(newMessage)
self.currentBotMessageId = newId
}
self.objectWillChange.send()
print("Current bot message: \(self.messages.last?.text ?? "")")
}
}
Log
EventSource connection opened
Received event: message
Current bot message: Hello
Received event: message
Received event: message
Current bot message: Hello!
Current bot message: Hello! How
Received event: message
Received event: message
Current bot message: Hello! How can
Current bot message: Hello! How can I
Received event: message
Current bot message: Hello! How can I assist
Received event: message
Current bot message: Hello! How can I assist you
Received event: message
Current bot message: Hello! How can I assist you today
Received event: message
Current bot message: Hello! How can I assist you today?
Received event: message
Received event: message
Current bot message: Hello! How can I assist you today?
I am willing to implement delete the selected message.
Is there any way we can do in the current implementation.
Love this library 💯 would be really cool to see support for links, and for allowing to copy messages. Right now the long press just makes the "Reply" button show up.
I need to manage this both on my end. Please provide the release time for the same.
I'm seeking some advice regarding how I should go about adding message response buttons like we see in WhatsApp and other messaging platforms. They display convenient short answer options in a chat message as shown in the attachment. Any suggestions where I should start for implementing this capability? There can be limitations, such as a max of 3 buttons, and pressing the button only fills in the draft message and automatically sends the message. I would appreciate any thoughts about where to get started and which classes should be extended.
Is it possible to disable showing waitingForNetwork
or at least provide a custom view when offline? Or disable NetworkMonitor
at all? Thanks
Thanks!
Hi developer, Thank you for creating an excellent chat library In SwiftUI.
when I tried to delete the item at binding dataSource source, will crash immediately at performBatchUpdates
in UIList, below is the log:
Thread 1: "Invalid batch updates detected: the number of sections and/or rows returned by the data source before and/or after performing the batch updates are inconsistent with the updates.\nData source before updates = { 1 section with row counts: [3] }\nData source after updates = { 1 section with row counts: [2] }\nUpdates = [\n\n]\nTable view: <UITableView: 0x125850a00;
I check the code, and the applyInserts
function already exists to deal with delete cases.
Hi
I'm seeing occurrences of the NSInternalInconsistencyException crash, that seems to have been an issue for other users in the past based on closed issues:
Fatal Exception: NSInternalInconsistencyException Invalid batch updates detected: the number of sections and/or rows returned by the data source before and after performing the batch updates are inconsistent with the updates. Data source before updates = { 1 section with row counts: [3] } Data source after updates = { 1 section with row counts: [0] } Updates = [ Delete row (0 - 1), Delete row (0 - 0) ]
Crash coming from UIList.swift, line 104 as it attempts to performBatchUpdates
.
I've not been able to replicate in testing as yet, but getting regular reports of the crash from our production release.
Any advice welcome... Thanks.
Most pushed views allow swiping from the left side of the screen to pop them back to the previous view. This is especially helpful for chat views, where most of the screen is covered by the keyboard and the top-left back button is out of reach. It would be nice to have the option for chat views to be dismissed with this gesture.
I believe this is currently disabled due to the .navigationBarBackButtonHidden()
modifier on the ChatNavigationModifier
. A simple solution would be another field in that struct to allow the system back button instead of the themed one.
Thank you for your consideration!
The code here uses NSAttributedString for rendering markdown.
Unfortunately I'm seeing this render incorrectly: \n
in the input string does not result in a newline (or any whitespace at all) in the rendered output. **
and similar text instructions do work.
This seems like an old issue:
https://forums.developer.apple.com/forums/thread/682957
A potential workaround is to just dump the string straight into the Text
.
If I get a chance this week I'll try to test this out myself, but I figured I'd file an issue first in case you beat me to it!
Can't tap on message avatar to display user profile
Does this natively support push notifications on new messages?
Swift 5.9
Contextual closure type '(ModeSwitcher, AlbumSelectionView, Bool) -> some View' expects 3 arguments, but 2 were used in closure body
mediapicker-issue.pdf
I am trying to show the edit and delete options only to current users and for other user only show reply. I see there is no way to alter the allCases. Thanks and great library!
is there support for dark mode without having to create a theme on my own. Maybe this should be an out to the box feature.
var body: some View {
Text(text)
.font(.caption)
.foregroundColor(isCurrentUser ? .white : .black)
.opacity(0.4)
}
I think these should be pulling from one of the theme colors.
There are some other instances in the rest of that file.
Users can record for up to 60 seconds
Thanks!
Exyte Chat will throw an exemption after sending a message through the chat input text field.
The following exemption is thrown, and it is caused due to the TableView not having any cells to for which to render after NotificationCenter.default.post(name: .onScrollToBottom, object: nil)
was called upon.
Attempted to scroll the table view to an out-of-bounds section (0) when there are only 0 sections
I noticed that Exyte Chat is using Notification Center to send .scrollToBottom
event, and there is a timeout of 0.3
.
I wonder if there is a race condition happening here in which the data source is not updated on time for that scroll event to call the table view.
My pipeline is failing due to an issue on ChatView.swift file. Message from Azure Pipeline attached.
`/Users/Mac/Library/Developer/Xcode/DerivedData/Project-aitscrhvyjucyfalpoeedjqvabid/SourcePackages/checkouts/Chat/Sources/ExyteChat/ChatView/ChatView.swift:260:25: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
var list: some View {
`
Is there a way to turn off the long press?
Using the example to build my own custom input view, I'm having a hard time understanding how I would dismiss the keyboard when the user taps on the chat view
I notice the internal implementation of the ChatView has
@StateObject private var globalFocusState = GlobalFocusState()
.environmentObject(globalFocusState)
but that is not something I can access inside inputViewBuilder
. I tried defining my own
@FocusState private var isChatFocus: Bool
but i don't have a handler to use to dismiss it when the user taps on the chat view. I tried onTapGesture
on the chat view, but it doesn't fire.
ChatView(messages: viewModel.messages) { draft in
viewModel.send(draft: draft)
} inputViewBuilder: { textBinding, attachments, state, style, actionClosure in
Group {
switch style {
case .message: // input view on chat screen
VStack {
HStack {
Button("Send") { actionClosure(.send) }
Button("Attach") { actionClosure(.photo) }
}
TextField("Write your message", text: textBinding)
}
case .signature: // input view on photo selection screen
VStack {
HStack {
Button("Send") { actionClosure(.send) }
}
TextField("Compose a signature for photo", text: textBinding)
.background(Color.green)
}
}
}
}```
I want to support custom message types. For example, I have documents that I want to send as a message when they are created. The message should contain information such as: title, blurb, documentId. How can I store this inside of a Message
?
I would also want to provide custom styling, which I can assume can be done through messageBuilder
. I am wondering how we can structure the Message
so that we can switch on it inside the messageBuilder
and display accordingly.
I want to keep all the displays of the standard messages the same other than my custom message type.
Any advice is greatly appreciated!
I get the error below every time I append messages
@Observable
class AblyServiceManager {
var allUsers: Set<User> = []
var messages: [Message] = []
func addNewMSG {
messages.append(newMSG)
}
}
*** Assertion failure in -[UITableView _Bug_Detected_In_Client_Of_UITableView_Invalid_Number_Of_Rows_In_Section:], UITableView.m:2,611
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). Table view: <UITableView: 0x10b11e000; frame = (0 0; 430 718); transform = [-1, 1.2246467991473532e-16, -1.2246467991473532e-16, -1, 0, 0]; clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000cf7510>; backgroundColor = UIExtendedSRGBColorSpace 1 1 1 1; layer = <CALayer: 0x6000003248c0>; contentOffset: {0, 0}; contentSize: {429.99999999999989, 103.43333206176757}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <_TtGCV9ExyteChat6UIList11CoordinatorV7SwiftUI9EmptyView__: 0x60000330b2a0>>'
*** First throw call stack:
Love this repo. Impressive work.
How would i add dynamic font size for messages for people with bad eyes?
My users are mostly >50 years old. I see that font size of 15 is hardcoded on MessageView.swift line36. I love everything else about the MessageView, and definitely want to avoid implementing a custom messageBuilder if i can help it.
Design:
https://www.figma.com/file/mtMqPG1bTFKNMBW3pgBlax/Open-source-library-for-Exyte?node-id=606%3A2
Вопросы по дизайну направлять Юле, вопросы по фичам в канал ios-opensource
Баги:
Фичи (когда-то потом):
Amazing Library, thanks you very much
would you guys make it compatible with iOS 15?
as the required version is too new to make the usage worldwide
Hello,
I was looking at your library and I noticed you were using a UITableView in a UIList.swift instead of the List component.
Why did you do that ? What was the limitation ?
Thanks :)
After adding new items into @Published var messages: [Message] = []
get a crash :(
When add only 1 item it works fine.
*** Assertion failure in -[UITableView _Bug_Detected_In_Client_Of_UITableView_Invalid_Number_Of_Rows_In_Section:], UITableView.m:2 611 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (40) must be equal to the number of rows contained in that section before the update (20), plus or minus the number of rows inserted or deleted from that section (12 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). Table view: <UITableView: 0x11a12ee00; frame = (-3.12915e-14 0; 393 662.333); transform = [-1, 1.2246467991473532e-16, -1.2246467991473532e-16, -1, 0, 0]; clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000d573f0>; backgroundColor = UIExtendedSRGBColorSpace 1 1 1 1; layer = <CALayer: 0x600000324c00>; contentOffset: {0, 985.66666666666663}; contentSize: {392.99999999999994, 1648.1000495910644}; adjustedContentInset: {1.4210854715202004e-14, 0, 0, 0}; dataSource: <_TtGCV9ExyteChat6UIList11CoordinatorV8Futurest15ChatMessageView__: 0x60000330b0c0>>' *** First throw call stack: ( 0 CoreFoundation 0x00000001804658a8 __exceptionPreprocess + 172 1 libobjc.A.dylib 0x000000018005c09c objc_exception_throw + 56 2 Foundation 0x0000000180cf3a5c _userInfoForFileAndLine + 0 3 UIKitCore 0x000000011522f8f0 -[UITableView _Bug_Detected_In_Client_Of_UITableView_Invalid_Number_Of_Rows_In_Section:] + 92 4 UIKitCore 0x000000011522f14c -[UITableView _endCellAnimationsWithContext:] + 9676 5 UIKitCore 0x00000001152430b0 -[UITableView endUpdatesWithContext:] + 128 6 Futurest 0x00000001014112ac $s9ExyteChat6UIListV12updateUIView_7contextySo11UITableViewC_7SwiftUI0E20RepresentableContextVyACyxGGtFyyYbcfU_yyXEfU2_ + 1000 7 Futurest 0x000000010140fcec $sIg_Ieg_TR + 20 8 Futurest 0x000000010140fd10 $sIeg_IyB_TR + 24 9 libdispatch.dylib 0x00000001045cd93c _dispatch_client_callout + 16 10 libdispatch.dylib 0x00000001045de80c _dispatch_async_and_wait_invoke + 192 11 libdispatch.dylib 0x00000001045cd93c _dispatch_client_callout + 16 12 libdispatch.dylib 0x00000001045dd5e4 _dispatch_main_queue_drain + 1228 13 libdispatch.dylib 0x00000001045dd108 _dispatch_main_queue_callback_4CF + 40 14 CoreFoundation 0x00000001803c61b4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 15 CoreFoundation 0x00000001803c08cc __CFRunLoopRun + 1936 16 CoreFoundation 0x00000001803bfd28 CFRunLoopRunSpecific + 572 17 GraphicsServices 0x000000018986ebc0 GSEventRunModal + 160 18 UIKitCore 0x0000000115033fdc -[UIApplication _run] + 868 19 UIKitCore 0x0000000115037c54 UIApplicationMain + 124 20 SwiftUI 0x000000010ba40524 OUTLINED_FUNCTION_70 + 500 21 SwiftUI 0x000000010ba403c4 OUTLINED_FUNCTION_70 + 148 22 SwiftUI 0x000000010b752108 OUTLINED_FUNCTION_2 + 92 23 Futurest 0x0000000100fd5bc8 $s8Futurest0A3AppV5$mainyyFZ + 40 24 Futurest 0x0000000100fd6040 main + 12 25 dyld 0x0000000103451558 start_sim + 20 26 ??? 0x0000000102f52058 0x0 + 4344586328 27 ??? 0x0215000000000000 0x0 + 150026162586779648 ) libc++abi: terminating due to uncaught exception of type NSException
Expected: CameraStubView should be closed when tapped on Close button
I am trying this repo with cocoapod for my project, however, there is no icon loaded in the chatview, I also double check the pod source and it seems the media resource was missing. Did we miss that on pod repo or I miss something? Thank you.
I have been using the source code you created, and it's very well. Below, I have detailed what I've noticed while working with it.
PS: I translated this because I'm not proficient in English. If there are any parts you don't understand, please answer.
Working Environment:
Feature Suggestions:
1. Add Menu on Message's Long Press Gesture:
2. Add shadow to message Bubble
3. Detailed View of Image Messages:
4. Voice Message Recording:
- Provide voice spectrum instead of displaying "Recording..."
ex) https://volpato.dev/posts/speech-wave-visualization-in-swiftui/
5. When New Messages Arrive (with isScrolledToBottom = true):
- Display the number of new messages as a badge
6. Add Style to Buttons:
- Use .buttonStyle(.plain)
7. Add a Closure for Handling Message Display Animations
8. Feature to Change the Profile in the Message Window When the User Profile Changes
Things Suspected to be Bugs:
I'm using SPM inside a XCode project. I added this project and I keep getting this error
CrashReportError: App crashed because Chat.framework is missing
Not sure what is causing this, any particular idea?
Now all chat configuration like showDateHeaders, messageUseMarkdown, avatarSize, etc, are simple variables and configured through methods from ChatView
extension. It means, that it's possible to set them only locally, directly with a ChatView
. I suggest to use EnvironmentValues
instead that allows to setup all configs globally for the whole app and override them locally if needed.
Example:
extension EnvironmentValues {
public struct Chat: Equatable {
public var type: ChatType = .chat
public var showDateHeaders: Bool = true
public var avatarSize: CGFloat = 32
public var messageUseMarkdown: Bool = false
public var showMessageMenuOnLongPress: Bool = true
public var tapAvatarClosure: TapAvatarClosure?
public var mediaPickerSelectionParameters: MediaPickerParameters?
public var orientationHandler: MediaPickerOrientationHandler = {_ in}
public var chatTitle: String?
public var showMessageTimeView = true
public var messageFont = UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 15))
public var availablelInput: AvailableInputType = .full
}
private enum ChatKey: EnvironmentKey {
static let defaultValue = EnvironmentValues.Chat()
}
public var chat: Chat {
get { self[ChatKey.self] }
set { self[ChatKey.self] = newValue }
}
}
extension View {
public func chatView<T>(_ keyPath: WritableKeyPath<EnvironmentValues.Chat, T>, _ value: T) -> some View {
environment(\.chat[keyPath: keyPath], value)
}
// convenience methods for each var if needed
}
Hi! First of all, thanks for open-sourcing this package!
I would like to customize the media types selectable in the media picker (only photos / only videos / both).
I am aware that ExyteMediaPicker
allows defining a mediaSelectionType
. However, if I understand correctly, ExyteChat
only exposes the mediaSelectionLimit
property of the underlying ExyteMediaPicker
via an assetsPickerLimit
modifier; the mediaSelectionType
property is not exposed.
Is there a way for me to customize the media selection type directly from ExyteChat
?
Thank you!
I don't see a way to push a ChatView
into a text-only or text-and-audio-only mode. Is this a reasonable feature request, or am I missing something?
Hello
I am trying to use exyte chat for the first time but without success. In the most simple code:
@State var messages: [Message] = []
var body: some View {
ChatView(messages: messages) { draft in
//yourViewModel.send(draft: draft)
}
}
how can I initialize the messages array with a first sample message to be displayed when the screen first appears?
I am trying to use onAppear() to just append a simple and sample message but it is being hard to initialize it. Could you provide what to pass the the append call?
Thank you
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.