diff --git a/docs.json b/docs.json index 3bf464a9c..e78066dd7 100644 --- a/docs.json +++ b/docs.json @@ -1223,11 +1223,11 @@ "group": "Chat", "pages": [ "ui-kit/ios/core-features", - "ui-kit/ios/extensions" + "ui-kit/ios/extensions", + "ui-kit/ios/ai-features" ] }, - "ui-kit/ios/call-features", - "ui-kit/ios/ai-features" + "ui-kit/ios/call-features" ] }, { @@ -1291,10 +1291,10 @@ { "group": "Migration Guide", "pages": [ - "ui-kit/ios/upgrading-from-v4", - "ui-kit/ios/property-changes" + "ui-kit/ios/upgrading-from-v4" ] }, + "ui-kit/ios/troubleshooting", "ui-kit/ios/link/sample", "ui-kit/ios/link/figma", "ui-kit/ios/link/changelog" @@ -5247,6 +5247,10 @@ "source": "/ui-kit/android/property-changes", "destination": "/ui-kit/android/upgrading-from-v4" }, + { + "source": "/ui-kit/ios/property-changes", + "destination": "/ui-kit/ios/upgrading-from-v4" + }, { "source": "/ui-kit/react-native/property-changes", "destination": "/ui-kit/react-native/upgrading-from-v4" diff --git a/sdk/ios/default-calling.mdx b/sdk/ios/default-calling.mdx index 7b5f18618..c7d9c8d8b 100644 --- a/sdk/ios/default-calling.mdx +++ b/sdk/ios/default-calling.mdx @@ -34,6 +34,7 @@ let callType: CometChat.CallType = .video // or .audio let newCall = Call(receiverId: receiverID, callType: callType, receiverType: receiverType) CometChat.initiateCall(call: newCall, onSuccess: { call in + guard let call = call else { return } // Call initiated, show outgoing call UI // Store call.sessionID for later use print("Call initiated successfully") diff --git a/ui-kit/ios/ai-assistant-chat-history.mdx b/ui-kit/ios/ai-assistant-chat-history.mdx index cc24e42a4..cd10a4427 100644 --- a/ui-kit/ios/ai-assistant-chat-history.mdx +++ b/ui-kit/ios/ai-assistant-chat-history.mdx @@ -1,424 +1,887 @@ --- title: "AI Assistant Chat History" +sidebarTitle: "AI Assistant Chat History" +description: "Complete guide to displaying AI assistant conversation history in iOS apps - production-ready code included" --- -## Overview - -The `AI Assistant Chat History` component is a pre-built user interface component designed to display the conversation history between users and an AI assistant within a chat application. It provides a structured and visually appealing way to present past interactions, making it easy for users to review previous messages and context. +The `CometChatAIAssistanceChatHistory` component displays past conversations between users and AI assistants. Users can review previous AI interactions and start new conversations. -## Usage - -### Integration - -##### Using Navigation Controller to Present `CometChatAIAssistantChatHistory` - -The `CometChatAIAssistanceChatHistory` component can be launched using a navigation controller. -This approach is ideal when you want to present the chat history as a standalone screen within your app’s navigation flow - - - -```swift -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. -self.navigationController?.pushViewController(chatHistory, animated: true) + +```json +{ + "component": "CometChatAIAssistanceChatHistory", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays past conversations between users and AI assistants", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onItemClick", + "type": "(AIConversation) -> Void" + }, + "props": { + "data": { + "user": { "type": "User?", "default": "nil" }, + "group": { "type": "Group?", "default": "nil" } + }, + "callbacks": { + "onItemClick": "(AIConversation) -> Void", + "onBack": "() -> Void", + "onError": "(CometChatException) -> Void" + } + }, + "events": [], + "sdkListeners": [], + "compositionExample": { + "description": "AIAssistanceChatHistory shows previous AI conversations for a user or group", + "components": ["CometChatAIAssistanceChatHistory", "CometChatMessages"], + "flow": "User opens AI history → selects conversation → views full AI chat" + } +} ``` - - + - - -Simply adding the CometChatAIAssistanceChatHistory component to your view hierarchy without providing a User or Group object will only display a loading indicator. -To fetch and display actual messages, you must assign either a User or a Group object to the component. - - - -*** +| Field | Value | +|-------|-------| +| Component | `CometChatAIAssistantChatHistory` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | +--- -### Actions +## Prerequisites -[Actions](/ui-kit/ios/components-overview#actions) define how a component behaves and responds to user interactions. + + +Add to your Podfile: +```ruby +pod 'CometChatUIKitSwift', '5.1.7' +``` +Run `pod install` + + + +Go to [CometChat Dashboard](https://app.cometchat.com) → AI → Enable AI features + + + +```swift lines +import CometChatUIKitSwift + +let uikitSettings = UIKitSettings() + .set(appID: "YOUR_APP_ID") + .set(authKey: "YOUR_AUTH_KEY") + .set(region: "YOUR_REGION") + .build() + +CometChatUIKit.init(uiKitSettings: uikitSettings) { result in + switch result { + case .success: + CometChatUIKit.login(uid: "USER_ID") { _ in } + case .failure(let error): + print(error.localizedDescription) + } +} +``` + + -##### onNewChatButtonClicked +--- -`onNewChatButtonClicked` The `onNewChatButtonClicked` action is triggered when the user taps on the “New Chat” button. -You can override it to define custom functionality, such as navigating to a new chat creation screen or initiating a new AI chat session. +## Basic Implementation - -```swift -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. - -chatHistory.onNewChatButtonClicked = { - // TODO: Implement custom behavior here + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ViewController: UIViewController { + + var user: CometChat.User! + + func showAIChatHistory() { + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = user // Required! + + navigationController?.pushViewController(chatHistory, animated: true) + } } ``` - - -*** + +You **must** set either `user` or `group`. Without this, only a loading indicator will display. + + +--- -##### onMessageClicked +## Production-Ready Implementation -You can customize this behavior by using the provided code snippet to override the onMessageClicked callback. -This allows you to define custom actions when a user taps on a message inside the AI Assistant Chat History component. +Complete implementation with all features: - -```swift -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. -chatHistory.onMessageClicked = { message in -// TODO: Implement custom behavior when a message is clicked + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class AIAssistantViewController: UIViewController { + + // MARK: - Properties + private var user: CometChat.User! + private var chatHistoryComponent: CometChatAIAssistanceChatHistory! + + // MARK: - Initialization + convenience init(user: CometChat.User) { + self.init() + self.user = user + } + + // MARK: - Lifecycle + override func viewDidLoad() { + super.viewDidLoad() + setupChatHistory() + } + + // MARK: - Setup + private func setupChatHistory() { + chatHistoryComponent = CometChatAIAssistanceChatHistory() + chatHistoryComponent.user = user + + // Configure callbacks + setupCallbacks() + + // Configure styling + setupStyling() + + // Configure date formatting + setupDateFormatting() + + // Configure empty/error states + setupStateViews() + + // Present + navigationController?.pushViewController(chatHistoryComponent, animated: true) + } + + // MARK: - Callbacks + private func setupCallbacks() { + // New chat button tapped + chatHistoryComponent.onNewChatButtonClicked = { [weak self] user in + self?.startNewAIChat() + } + + // Message tapped + chatHistoryComponent.onMessageClicked = { [weak self] message in + self?.handleMessageTap(message) + } + + // Data loaded successfully + chatHistoryComponent.set(onLoad: { messages in + print("✅ Loaded \(messages.count) AI messages") + }) + + // No data available + chatHistoryComponent.set(onEmpty: { [weak self] in + print("📭 No AI chat history") + }) + + // Error occurred + chatHistoryComponent.set(onError: { [weak self] error in + self?.showError(error.localizedDescription) + }) + } + + // MARK: - Styling + private func setupStyling() { + let style = AiAssistantChatHistoryStyle() + + // Background + style.backgroundColor = .systemBackground + + // Item text + style.itemTextFont = UIFont.systemFont(ofSize: 16, weight: .medium) + style.itemTextColor = .label + + // New chat button + style.newChatTitleFont = UIFont.systemFont(ofSize: 18, weight: .bold) + style.newChatTitleColor = .systemBlue + + chatHistoryComponent.style = style + } + + // MARK: - Date Formatting + private func setupDateFormatting() { + // Today's messages + chatHistoryComponent.dateTimeFormatter.today = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.timeStyle = .short + return "Today at \(formatter.string(from: date))" + } + + // Yesterday's messages + chatHistoryComponent.dateTimeFormatter.yesterday = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.timeStyle = .short + return "Yesterday at \(formatter.string(from: date))" + } + + // Older messages + chatHistoryComponent.dateTimeFormatter.otherDay = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "MMM d, yyyy 'at' h:mm a" + return formatter.string(from: date) + } + } + + // MARK: - State Views + private func setupStateViews() { + // Empty state text + chatHistoryComponent.emptyStateText = "No AI conversations yet" + chatHistoryComponent.emptyStateSubtitleText = "Tap 'New Chat' to start talking with AI" + + // Error state text + chatHistoryComponent.errorStateText = "Couldn't load history" + chatHistoryComponent.errorStateSubtitleText = "Please check your connection and try again" + } + + // MARK: - Actions + private func startNewAIChat() { + // Option 1: Open messages view for new AI chat + let messagesVC = CometChatMessages() + messagesVC.user = user + navigationController?.pushViewController(messagesVC, animated: true) + + // Option 2: Show action sheet with options + // showNewChatOptions() + } + + private func handleMessageTap(_ message: BaseMessage) { + print("Tapped message ID: \(message.id)") + print("Message text: \(message.text ?? "No text")") + + // Show message details or continue conversation + let alert = UIAlertController( + title: "Message", + message: message.text, + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "Continue Chat", style: .default) { [weak self] _ in + self?.continueChat(from: message) + }) + alert.addAction(UIAlertAction(title: "Close", style: .cancel)) + present(alert, animated: true) + } + + private func continueChat(from message: BaseMessage) { + let messagesVC = CometChatMessages() + messagesVC.user = user + navigationController?.pushViewController(messagesVC, animated: true) + } + + private func showError(_ message: String) { + let alert = UIAlertController( + title: "Error", + message: message, + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "Retry", style: .default) { [weak self] _ in + self?.setupChatHistory() + }) + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + present(alert, animated: true) + } } ``` - - -*** +--- -##### onError +## Custom Views -You can customize this behavior by overriding the `onError` callback to improve error handling within the component. -This is useful for displaying custom error messages or performing recovery actions when data fetching fails. +### Custom Loading View - -```swift + +```swift lines let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. +chatHistory.user = user -chatHistory.set(onError: { error in - // Override on error -}) -``` +// Custom loading indicator +let loadingView = UIActivityIndicatorView(style: .large) +loadingView.color = .systemBlue +loadingView.startAnimating() +chatHistory.set(loadingView: loadingView) +``` - -##### onLoad - -The `onLoad` callback is invoked when the message list is successfully fetched and loaded. -This can be used to track component readiness or perform actions once messages are displayed. +### Custom Empty State View - -```swift -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. - -chatHistory.set(onLoad: { history in - // Handle loaded ai chat history -}) -``` - - + +```swift lines +import UIKit +import CometChatUIKitSwift + +class CustomEmptyView: UIView { + + private let imageView: UIImageView = { + let iv = UIImageView() + iv.image = UIImage(systemName: "sparkles") + iv.tintColor = .systemBlue + iv.contentMode = .scaleAspectFit + iv.translatesAutoresizingMaskIntoConstraints = false + return iv + }() + + private let titleLabel: UILabel = { + let label = UILabel() + label.text = "No AI Conversations" + label.font = .systemFont(ofSize: 20, weight: .bold) + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private let subtitleLabel: UILabel = { + let label = UILabel() + label.text = "Start a conversation with AI to see it here" + label.font = .systemFont(ofSize: 16) + label.textColor = .secondaryLabel + label.textAlignment = .center + label.numberOfLines = 0 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + let startChatButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Start New Chat", for: .normal) + button.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold) + button.backgroundColor = .systemBlue + button.setTitleColor(.white, for: .normal) + button.layer.cornerRadius = 12 + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(imageView) + addSubview(titleLabel) + addSubview(subtitleLabel) + addSubview(startChatButton) + + NSLayoutConstraint.activate([ + imageView.centerXAnchor.constraint(equalTo: centerXAnchor), + imageView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -80), + imageView.widthAnchor.constraint(equalToConstant: 80), + imageView.heightAnchor.constraint(equalToConstant: 80), + + titleLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 24), + titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32), + titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32), + + subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8), + subtitleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32), + subtitleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32), + + startChatButton.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 24), + startChatButton.centerXAnchor.constraint(equalTo: centerXAnchor), + startChatButton.widthAnchor.constraint(equalToConstant: 180), + startChatButton.heightAnchor.constraint(equalToConstant: 48) + ]) + } +} - +// Usage +let chatHistory = CometChatAIAssistanceChatHistory() +chatHistory.user = user -*** +let emptyView = CustomEmptyView() +emptyView.startChatButton.addTarget(self, action: #selector(startNewChat), for: .touchUpInside) -##### onEmpty +chatHistory.set(emptyView: emptyView) +``` + + -The `onEmpty` callback is triggered when no messages are available. -You can use this to show placeholder content, such as an empty state message or an illustration. +### Custom Error State View - -```swift + +```swift lines +import UIKit +import CometChatUIKitSwift + +class CustomErrorView: UIView { + + private let iconView: UIImageView = { + let iv = UIImageView() + iv.image = UIImage(systemName: "exclamationmark.triangle") + iv.tintColor = .systemRed + iv.contentMode = .scaleAspectFit + iv.translatesAutoresizingMaskIntoConstraints = false + return iv + }() + + private let titleLabel: UILabel = { + let label = UILabel() + label.text = "Something went wrong" + label.font = .systemFont(ofSize: 18, weight: .semibold) + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private let messageLabel: UILabel = { + let label = UILabel() + label.text = "We couldn't load your AI chat history.\nPlease check your connection." + label.font = .systemFont(ofSize: 14) + label.textColor = .secondaryLabel + label.textAlignment = .center + label.numberOfLines = 0 + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + let retryButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("Try Again", for: .normal) + button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium) + button.backgroundColor = .systemBlue + button.setTitleColor(.white, for: .normal) + button.layer.cornerRadius = 10 + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(iconView) + addSubview(titleLabel) + addSubview(messageLabel) + addSubview(retryButton) + + NSLayoutConstraint.activate([ + iconView.centerXAnchor.constraint(equalTo: centerXAnchor), + iconView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -60), + iconView.widthAnchor.constraint(equalToConstant: 60), + iconView.heightAnchor.constraint(equalToConstant: 60), + + titleLabel.topAnchor.constraint(equalTo: iconView.bottomAnchor, constant: 16), + titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24), + titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24), + + messageLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8), + messageLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24), + messageLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24), + + retryButton.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 20), + retryButton.centerXAnchor.constraint(equalTo: centerXAnchor), + retryButton.widthAnchor.constraint(equalToConstant: 140), + retryButton.heightAnchor.constraint(equalToConstant: 44) + ]) + } +} + +// Usage let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. +chatHistory.user = user -chatHistory.set(onEmpty: { - // Handle empty state -}) -``` +let errorView = CustomErrorView() +errorView.retryButton.addTarget(self, action: #selector(retryLoading), for: .touchUpInside) +chatHistory.set(errorView: errorView) +``` - -*** - -### Filters +--- -You can customize the message list displayed in the `CometChatAIAssistanceChatHistory` component by modifying the `MessagesRequestBuilder`. -This allows you to filter messages according to your app’s needs — for example, fetching messages that match a search term or belong to a specific user or group. +## Filter Messages -In the example below, we are applying a filter to the messages based on a search substring and for a specific user. This means that only messages that contain the search term and are associated with the specified user will be displayed +Customize which messages are displayed: - -```swift -swift let builder = MessagesRequest.MessageRequestBuilder() - .set(uid: user.uid) // Example: filter messages by user UID + +```swift lines +import CometChatSDK +import CometChatUIKitSwift let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. +chatHistory.user = user + +// Create custom message request builder +let builder = MessagesRequest.MessageRequestBuilder() + .set(uid: user.uid ?? "") + .set(limit: 50) + chatHistory.set(messagesRequestBuilder: builder) ``` - - - -The following parameters in `messagesRequestBuilder` will always be modified internally by the component: - -1. `uid` -2. `guid` -3. `types` -4. `categories` - +These parameters are **always overridden** by the component: +- `uid` / `guid` +- `types` +- `categories` -*** - -### Events - -[Events](/ui-kit/flutter/components-overview#events) are emitted by a `Component`. - -By using events, you can extend existing functionality. Since events are global in nature, they can be added or removed from multiple locations within the app. -The CometChatAIAssistanceChatHistory component does not emit any events of its own. - -*** - -## Customization - -To meet your app’s design and UX requirements, you can customize the appearance and functionality of the `CometChatAIAssistanceChatHistory` component. -We provide multiple exposed properties and methods that allow you to modify both the visual style and interactive behavior according to your needs. - -### Style - -The style property allows you to customize the look and feel of the component in your app. -These parameters control key design aspects such as colors, fonts, text styles, and background appearance for various subviews like headers, date separators, and message items - -##### 1. AiAssistantChatHistoryStyle +--- -You can assign a custom `AiAssistantChatHistoryStyle` to the component to override the default visual theme. +## Embed in Your App -**Global level styling** +### As a Tab -```swift -CometChatAIAssistanceChatHistory.style.backgroundColor = -CometChatAIAssistanceChatHistory.style.itemTextFont = -CometChatAIAssistanceChatHistory.style.newChatTitleFont = +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class MainTabBarController: UITabBarController { + + var currentUser: CometChat.User! + + override func viewDidLoad() { + super.viewDidLoad() + fetchUserAndSetupTabs() + } + + private func fetchUserAndSetupTabs() { + // Get current logged in user + guard let user = CometChat.getLoggedInUser() else { return } + currentUser = user + setupTabs() + } + + private func setupTabs() { + // Chats Tab + let chatsVC = CometChatConversationsWithMessages() + let chatsNav = UINavigationController(rootViewController: chatsVC) + chatsNav.tabBarItem = UITabBarItem( + title: "Chats", + image: UIImage(systemName: "message"), + selectedImage: UIImage(systemName: "message.fill") + ) + + // AI Assistant Tab + let aiVC = CometChatAIAssistanceChatHistory() + aiVC.user = currentUser + aiVC.onNewChatButtonClicked = { [weak self] user in + self?.startNewAIChat() + } + let aiNav = UINavigationController(rootViewController: aiVC) + aiNav.tabBarItem = UITabBarItem( + title: "AI Assistant", + image: UIImage(systemName: "sparkles"), + selectedImage: UIImage(systemName: "sparkles") + ) + + // Users Tab + let usersVC = CometChatUsersWithMessages() + let usersNav = UINavigationController(rootViewController: usersVC) + usersNav.tabBarItem = UITabBarItem( + title: "Users", + image: UIImage(systemName: "person.2"), + selectedImage: UIImage(systemName: "person.2.fill") + ) + + viewControllers = [chatsNav, aiNav, usersNav] + } + + private func startNewAIChat() { + let messagesVC = CometChatMessages() + messagesVC.user = currentUser + + if let nav = selectedViewController as? UINavigationController { + nav.pushViewController(messagesVC, animated: true) + } + } +} ``` - - -**Instance level styling** +### As a Button Action -```swift -let aiAssistantChatHistoryStyle = AiAssistantChatHistoryStyle() -aiAssistantChatHistoryStyle.backgroundColor = -aiAssistantChatHistoryStyle.itemTextFont = -aiAssistantChatHistoryStyle.newChatTitleFont = - -let aIAssistanceChatHistory = CometChatAIAssistanceChatHistory() -aIAssistanceChatHistory.style = aiAssistantChatHistoryStyle +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ProfileViewController: UIViewController { + + var user: CometChat.User! + + private let aiHistoryButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("View AI Chat History", for: .normal) + button.setImage(UIImage(systemName: "sparkles"), for: .normal) + button.backgroundColor = .systemBlue + button.tintColor = .white + button.layer.cornerRadius = 12 + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + private func setupUI() { + view.backgroundColor = .systemBackground + view.addSubview(aiHistoryButton) + + NSLayoutConstraint.activate([ + aiHistoryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + aiHistoryButton.centerYAnchor.constraint(equalTo: view.centerYAnchor), + aiHistoryButton.widthAnchor.constraint(equalToConstant: 250), + aiHistoryButton.heightAnchor.constraint(equalToConstant: 50) + ]) + + aiHistoryButton.addTarget(self, action: #selector(showAIHistory), for: .touchUpInside) + } + + @objc private func showAIHistory() { + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = user + + chatHistory.onNewChatButtonClicked = { [weak self] selectedUser in + let messagesVC = CometChatMessages() + messagesVC.user = selectedUser + self?.navigationController?.pushViewController(messagesVC, animated: true) + } + + navigationController?.pushViewController(chatHistory, animated: true) + } +} ``` - - - - - - -*** - -### Functionality - -These functional customizations allow you to fine-tune the overall behavior and user experience of the component. -With these options, you can modify text, customize icons, and toggle visibility for specific UI elements within the `CometChatAIAssistanceChatHistory` component. - - - -```swift -swift let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. - -// Example: Adding a custom back button -let backButton = UIButton(type: .system) -backButton.setImage(UIImage(systemName: "snowflake"), for: .normal) -backButton.tintColor = .systemRed -backButton.addTarget(self, action: #selector(didTapBackButton), for: .touchUpInside) -chatHistory.backButton = backButton -``` - - - - - -## CometChatMessageList Properties - -Below is a list of customizations along with corresponding code snippets: - -| **Property** | **Description** | **Code** | -| -------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -| **User** | Used to set the user for displaying their AI chat history. | `CometChatAIAssistantChatHistory.set(user: user)` | -| **Group** | Used to set the group for displaying its AI chat history. | `CometChatAIAssistantChatHistory.set(group: group)` | -| **Messages Request Builder** | Used to pass a custom message request builder to fetch AI chat history. | `CometChatAIAssistantChatHistory.set(messagesRequestBuilder: customBuilder)` | -| **Loading State View** | Used to set a custom loading view when fetching AI chat history. | `CometChatAIAssistantChatHistory.set(loadingStateView: customLoadingView)` | -| **Empty State View** | Used to set a custom view when no messages are available. | `CometChatAIAssistantChatHistory.set(emptyStateView: customEmptyView)` | -| **Error State View** | Used to set a custom error view when message fetching fails. | `CometChatAIAssistantChatHistory.set(errorStateView: customErrorView)` | -| **On Message Clicked** | Used to handle actions when a message is clicked. | `CometChatAIAssistantChatHistory.set(onMessageClicked: { message in })` | -| **On Error** | Used to handle actions when an error occurs while fetching data. | `CometChatAIAssistantChatHistory.set(onError: { })` | -| **On Load** | Used to handle actions when chat history is successfully loaded. | `CometChatAIAssistantChatHistory.set(onLoad: { })` | -| **On Empty** | Used to handle actions when chat history is empty. | `CometChatAIAssistantChatHistory.set(onEmpty: { })` | -| **On New Chat Button Clicked** | Used to handle actions when the “New Chat” button is clicked. | `CometChatAIAssistantChatHistory.set(onNewChatButtonClicked: { user in })` | -| **On Close** | Used to handle actions when the back button is pressed. | `CometChatAIAssistantChatHistory.set(onClose: { })` | -| **Empty State Text** | Used to set the text when the chat history list is empty. | `CometChatAIAssistantChatHistory.emptyStateText = "No conversations yet"` | -| **Empty State Subtitle Text** | Used to set a subtitle when the chat history list is empty. | `CometChatAIAssistantChatHistory.emptyStateSubtitleText = "Start a new chat to begin"` | -| **Error State Text** | Used to set the text when an error occurs. | `CometChatAIAssistantChatHistory.errorStateText = "Failed to load history"` | -| **Error State Subtitle Text** | Used to set a subtitle when an error occurs. | `CometChatAIAssistantChatHistory.errorStateSubtitleText = "Please try again later"` | -| **Hide Date Separator** | Used to hide or show the date separator in the chat history list. | `CometChatAIAssistantChatHistory.hideDateSeparator = true` | -*** - -### Advance +--- -For advanced-level customization, you can inject custom views or functions into the component. -This allows you to tailor the `CometChatAIAssistanceChatHistory` experience to align perfectly with your app’s interface and logic. +## API Reference + +### Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `user` | `CometChat.User` | Yes* | User for AI chat history | +| `group` | `CometChat.Group` | Yes* | Group for AI chat history | +| `style` | `AiAssistantChatHistoryStyle` | No | Custom styling | +| `emptyStateText` | `String` | No | Empty state title | +| `emptyStateSubtitleText` | `String` | No | Empty state subtitle | +| `errorStateText` | `String` | No | Error state title | +| `errorStateSubtitleText` | `String` | No | Error state subtitle | +| `hideDateSeparator` | `Bool` | No | Hide date separators | +| `backButton` | `UIButton` | No | Custom back button | + +*Either `user` or `group` is required + +### Callbacks + +| Method | Parameters | Description | +|--------|------------|-------------| +| `onNewChatButtonClicked` | `(User) -> Void` | New chat button tapped | +| `onMessageClicked` | `(BaseMessage) -> Void` | Message tapped | +| `set(onLoad:)` | `([BaseMessage]) -> Void` | Data loaded | +| `set(onEmpty:)` | `() -> Void` | No data | +| `set(onError:)` | `(Error) -> Void` | Error occurred | + +### Custom Views + +| Method | Parameters | Description | +|--------|------------|-------------| +| `set(loadingView:)` | `UIView` | Custom loading view | +| `set(emptyView:)` | `UIView` | Custom empty state | +| `set(errorView:)` | `UIView` | Custom error state | +| `set(messagesRequestBuilder:)` | `MessagesRequestBuilder` | Filter messages | + +### Style Properties (AiAssistantChatHistoryStyle) + +| Property | Type | Description | +|----------|------|-------------| +| `backgroundColor` | `UIColor` | Background color | +| `itemTextFont` | `UIFont` | Message text font | +| `itemTextColor` | `UIColor` | Message text color | +| `newChatTitleFont` | `UIFont` | New chat button font | +| `newChatTitleColor` | `UIColor` | New chat button color | -#### dateSeparatorPattern +--- -You can modify the format of the date separator displayed between messages using the `dateSeparatorPattern` property. -This closure accepts a `Date` object and returns a formatted `String`. +## Common Patterns -**Example** +### Present AI Chat History from Profile -Here is the complete example for reference: +Show AI chat history when user taps a button in their profile: - -```swift -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.user = user // A User or Group object is required to launch this component. -chatHistory.dateTimeFormatter.time = { timestamp in - return "at " + DateFormatter.localizedString(from: Date(timeIntervalSince1970: TimeInterval(timestamp)), dateStyle: .none, timeStyle: .short) -} -chatHistory.dateTimeFormatter.today = { timestamp in - return "Today • \(formattedTime(from: timestamp))" -} - -// for global level -CometChatAIAssistanceChatHistory.dateTimeFormatter.otherDay = { timestamp in // This will display older dates as "24 Apr 2025" instead of the default relative format. - let formatter = DateFormatter() - formatter.dateFormat = "dd MMM yyyy" - return formatter.string(from: Date(timeIntervalSince1970: TimeInterval(timestamp))) + +```swift lines +@objc func showAIChatHistory() { + guard let currentUser = CometChat.getLoggedInUser() else { return } + + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = currentUser + + chatHistory.onNewChatButtonClicked = { [weak self] user in + let messagesVC = CometChatMessages() + messagesVC.user = user + self?.navigationController?.pushViewController(messagesVC, animated: true) + } + + navigationController?.pushViewController(chatHistory, animated: true) } ``` - - -*** - -#### loadingStateView - -Customize the loading view displayed when messages are being fetched. -Use this property to show a spinner, skeleton loader, or a custom loading message for better UX. +### Handle Message Selection from History -Use Cases: - -* Show a spinner or skeleton loader for smooth UX. -* Display a "Fetching history..." text. +Navigate to the full conversation when a message is tapped: - -```swift -let loadingView = UIActivityIndicatorView(style: .large) -loadingView.startAnimating() - + +```swift lines let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.set(loadingView: loadingView) -``` +chatHistory.user = user +chatHistory.onMessageClicked = { [weak self] message in + // Open the messages view to continue the conversation + let messagesVC = CometChatMessages() + messagesVC.user = self?.user + self?.navigationController?.pushViewController(messagesVC, animated: true) +} +``` - -*** +### Custom Date Formatting for AI History -#### emptyStateView +Format dates to show relative time for recent conversations: -Customize the view displayed when there are no messages in the chat history. -This is typically used to show a friendly placeholder or an illustration.. - -Use Cases: + + +```swift lines +let chatHistory = CometChatAIAssistanceChatHistory() +chatHistory.user = user -* Display “No chat history yet” text. -* Add a button prompting users to start a new chat. +// Instance-level date formatting +chatHistory.dateTimeFormatter.today = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.timeStyle = .short + return "Today at \(formatter.string(from: date))" +} - - -```swift -let emptyView = UILabel() -emptyView.text = "No chat history yet." -emptyView.textAlignment = .center -emptyView.textColor = .gray +chatHistory.dateTimeFormatter.yesterday = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.timeStyle = .short + return "Yesterday at \(formatter.string(from: date))" +} -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.set(emptyView: emptyView) +// Or use global-level formatting +CometChatAIAssistanceChatHistory.dateTimeFormatter.otherDay = { timestamp in + let formatter = DateFormatter() + formatter.dateFormat = "MMM d, yyyy" + return formatter.string(from: Date(timeIntervalSince1970: TimeInterval(timestamp))) +} ``` - - -*** - -#### errorStateView - -You can define a custom view to display when an error occurs during message loading. -This could include a retry button or a helpful error message for better recovery.. +### AI History as Tab in Main Navigation -Use Cases: - -* Show a retry option on network failure. -* Display “Unable to load messages. Check your connection.". +Add AI chat history as a dedicated tab: - -```swift -let errorView = UIView() -let errorLabel = UILabel() -errorLabel.text = "Couldn't load history. Check your connection." -errorLabel.textAlignment = .center -errorLabel.textColor = .systemRed -errorView.addSubview(errorLabel) -errorLabel.translatesAutoresizingMaskIntoConstraints = false -NSLayoutConstraint.activate([ -errorLabel.centerXAnchor.constraint(equalTo: errorView.centerXAnchor), -errorLabel.centerYAnchor.constraint(equalTo: errorView.centerYAnchor) -]) - -let chatHistory = CometChatAIAssistanceChatHistory() -chatHistory.set(errorView: errorView) + +```swift lines +class MainTabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + + guard let currentUser = CometChat.getLoggedInUser() else { return } + + let aiHistory = CometChatAIAssistanceChatHistory() + aiHistory.user = currentUser + + aiHistory.onNewChatButtonClicked = { [weak self] user in + let messagesVC = CometChatMessages() + messagesVC.user = user + if let nav = self?.selectedViewController as? UINavigationController { + nav.pushViewController(messagesVC, animated: true) + } + } + + let aiNav = UINavigationController(rootViewController: aiHistory) + aiNav.tabBarItem = UITabBarItem( + title: "AI Assistant", + image: UIImage(systemName: "sparkles"), + selectedImage: UIImage(systemName: "sparkles") + ) + + viewControllers = [/* other tabs */, aiNav] + } +} ``` - - -*** \ No newline at end of file +--- + +## Related + + + + All AI features + + + Chat message display + + + Message input + + + All components + + diff --git a/ui-kit/ios/ai-features.mdx b/ui-kit/ios/ai-features.mdx index 90f86183c..fbb20b85e 100644 --- a/ui-kit/ios/ai-features.mdx +++ b/ui-kit/ios/ai-features.mdx @@ -1,47 +1,516 @@ --- -title: "AI" +title: "AI Features" +sidebarTitle: "Smart Chat Features" +description: "Complete guide to AI-powered chat features in iOS apps - conversation starters, smart replies, and summaries" --- + +```json +{ + "category": "ai", + "features": [ + {"name": "aiAgentChat", "description": "Chat with AI-powered assistants", "component": "CometChatMessages", "enabledByDefault": false}, + {"name": "chatHistory", "description": "Browse and resume previous AI sessions", "component": "CometChatAIAssistanceChatHistory", "enabledByDefault": false}, + {"name": "streamingResponses", "description": "Real-time AI message streaming", "component": "CometChatMessageList", "enabledByDefault": false}, + {"name": "suggestedMessages", "description": "AI-powered conversation starters and smart replies", "component": "CometChatMessageComposer", "enabledByDefault": false} + ], + "dashboardSetup": { + "location": "CometChat Dashboard → AI", + "features": ["Conversation Starter", "Smart Replies", "Conversation Summary"] + }, + "relatedComponents": ["CometChatMessages", "CometChatAIAssistanceChatHistory", "CometChatMessageList", "CometChatMessageComposer"] +} +``` + + ## Overview -CometChat's AI capabilities greatly enhance user interaction and engagement in your application. Let's understand how the iOS UI Kit achieves these features. +CometChat AI features enhance your chat experience with intelligent suggestions and summaries. Once enabled in your dashboard, they integrate automatically into the UI Kit components. -## Conversation Starters +| Feature | What It Does | Where It Appears | +|---------|--------------|------------------| +| Conversation Starters | Suggests opening messages for new chats | `CometChatMessageList` | +| Smart Replies | Suggests responses based on context | `CometChatMessageComposer` | +| Conversation Summary | Summarizes long conversations | `CometChatMessageComposer` | +| AI Assistant | Chat with AI bot | `CometChatAIAssistanceChatHistory` | + +--- -When a user initiates a new chat, the UI kit displays a list of suggested opening lines that users can select, making it easier for them to start a conversation. These suggestions are powered by CometChat's AI, which predicts contextually relevant conversation starters. +## Enable AI Features -For a comprehensive understanding and guide on implementing and using the Conversation Starters, refer to our specific guide on the [Conversation Starter](/fundamentals/ai-user-copilot/conversation-starter). + + +Go to [app.cometchat.com](https://app.cometchat.com) and select your app. + -Once you have successfully activated the [Conversation Starter](/fundamentals/ai-user-copilot/conversation-starter) from your CometChat Dashboard, the feature will automatically be incorporated into the [MessageList](/ui-kit/ios/message-list) Component of UI Kits. + +Click **AI** in the sidebar, then enable the features you want: +- ✅ Conversation Starter +- ✅ Smart Replies +- ✅ Conversation Summary + + + +Customize AI behavior, response style, and triggers in the dashboard settings. + + + +**That's it!** AI features now work automatically in your app. + +--- + +## Conversation Starters + +When a user opens a new chat with no message history, AI suggests conversation openers. -## Smart Replies +### How It Works + +1. User opens chat with someone they haven't messaged before +2. AI analyzes user profiles and context +3. Suggested messages appear in the message list +4. User taps a suggestion to send it + +### Implementation + +Conversation starters appear automatically in `CometChatMessages`: -Smart Replies are AI-generated responses to messages. They can predict what a user might want to say next by analyzing the context of the conversation. This allows for quicker and more convenient responses, especially on mobile devices. + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -For a comprehensive understanding and guide on implementing and using the Smart Replies, refer to our specific guide on the [Smart Replies](/fundamentals/ai-user-copilot/smart-replies). +class ChatViewController: UIViewController { + + func openChatWithUser(uid: String) { + CometChat.getUser(UID: uid) { [weak self] user in + DispatchQueue.main.async { + let messagesVC = CometChatMessages() + messagesVC.user = user + + // Conversation starters appear automatically + // if enabled in dashboard and no previous messages exist + + self?.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + + -Once you have successfully activated the [Smart Replies](/fundamentals/ai-user-copilot/smart-replies) from your CometChat Dashboard, the feature will automatically be incorporated into the Action sheet of [MessageComposer](/ui-kit/ios/message-composer) Component of UI Kits. +--- + +## Smart Replies + +AI suggests contextual responses based on the conversation. -## Conversation Summary +### How It Works + +1. User receives a message +2. AI analyzes the message and conversation context +3. Smart reply suggestions appear in the composer action sheet +4. User taps a suggestion to insert it -The Conversation Summary feature provides concise summaries of long conversations, allowing users to catch up quickly on missed chats. This feature uses natural language processing to determine the main points in a conversation. +### Implementation -For a comprehensive understanding and guide on implementing and using the Conversation Summary, refer to our specific guide on the [Conversation Summary](/fundamentals/ai-user-copilot/conversation-summary). +Smart replies appear automatically in `CometChatMessageComposer`: -Once you have successfully activated the [Smart Replies](/fundamentals/ai-user-copilot/smart-replies) from your CometChat Dashboard, the feature will automatically be incorporated into the Action sheet of [MessageComposer](/ui-kit/ios/message-composer) Component of UI Kits. + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatViewController: UIViewController { + + func openChat(with user: CometChat.User) { + let messagesVC = CometChatMessages() + messagesVC.user = user + + // Smart replies appear automatically in the composer + // when enabled in dashboard + + navigationController?.pushViewController(messagesVC, animated: true) + } +} +``` + + + +--- + +## Conversation Summary + +AI generates summaries of long conversations so users can catch up quickly. + +### How It Works + +1. User opens a conversation with many messages +2. User taps the summary option in composer action sheet +3. AI processes the conversation +4. Summary of key points is displayed + +### Implementation + +Conversation summary is available automatically: + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatViewController: UIViewController { + + func openChat(with user: CometChat.User) { + let messagesVC = CometChatMessages() + messagesVC.user = user + + // Conversation summary option appears in composer action sheet + // when enabled in dashboard and sufficient messages exist + + navigationController?.pushViewController(messagesVC, animated: true) + } +} +``` + + + +--- + +## AI Assistant Chat History + +View and continue conversations with AI assistants. + +### Basic Implementation + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class AIAssistantViewController: UIViewController { + + var user: CometChat.User! + + func showAIChatHistory() { + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = user // Required + + navigationController?.pushViewController(chatHistory, animated: true) + } +} +``` + + + +### Full Implementation with Callbacks + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class AIAssistantViewController: UIViewController { + + var user: CometChat.User! + + func showAIChatHistory() { + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = user + + // Handle new chat button + chatHistory.onNewChatButtonClicked = { [weak self] in + self?.startNewAIChat() + } + + // Handle message tap + chatHistory.onMessageClicked = { message in + print("Tapped message: \(message.text ?? "")") + } + + // Handle load success + chatHistory.set(onLoad: { messages in + print("Loaded \(messages.count) AI messages") + }) + + // Handle empty state + chatHistory.set(onEmpty: { + print("No AI chat history") + }) + + // Handle errors + chatHistory.set(onError: { [weak self] error in + self?.showError(error.localizedDescription) + }) + + navigationController?.pushViewController(chatHistory, animated: true) + } + + private func startNewAIChat() { + // Navigate to new AI chat + print("Starting new AI conversation") + } + + private func showError(_ message: String) { + let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } +} +``` + + + +### Customize AI Chat History Styling + + + +```swift lines +import UIKit +import CometChatUIKitSwift + +class AIAssistantViewController: UIViewController { + + var user: CometChat.User! + + func showStyledAIChatHistory() { + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = user + + // Custom styling + let style = AiAssistantChatHistoryStyle() + style.backgroundColor = .systemBackground + style.itemTextFont = UIFont.systemFont(ofSize: 16, weight: .medium) + style.itemTextColor = .label + style.newChatTitleFont = UIFont.systemFont(ofSize: 18, weight: .bold) + style.newChatTitleColor = .systemBlue + chatHistory.style = style + + // Custom empty state + chatHistory.emptyStateText = "No AI conversations yet" + chatHistory.emptyStateSubtitleText = "Tap 'New Chat' to start" + + // Custom date formatting + chatHistory.dateTimeFormatter.today = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.timeStyle = .short + return "Today at \(formatter.string(from: date))" + } + + navigationController?.pushViewController(chatHistory, animated: true) + } +} +``` + + + +{/* --- + +## Complete App with AI Features + +Full implementation showing all AI features: + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +// MARK: - Scene Delegate +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let windowScene = (scene as? UIWindowScene) else { return } + + let uikitSettings = UIKitSettings() + .set(appID: "YOUR_APP_ID") + .set(authKey: "YOUR_AUTH_KEY") + .set(region: "YOUR_REGION") + .subscribePresenceForAllUsers() + .build() + + CometChatUIKit.init(uiKitSettings: uikitSettings) { [weak self] result in + switch result { + case .success: + CometChatUIKit.login(uid: "cometchat-uid-1") { loginResult in + switch loginResult { + case .success: + DispatchQueue.main.async { + self?.setupUI(windowScene: windowScene) + } + case .onError(let error): + print("Login failed: \(error.description)") + @unknown default: + break + } + } + case .failure(let error): + print("Init failed: \(error.localizedDescription)") + } + } + } + + private func setupUI(windowScene: UIWindowScene) { + let tabBar = AIEnabledTabBarController() + window = UIWindow(windowScene: windowScene) + window?.rootViewController = tabBar + window?.makeKeyAndVisible() + } +} + +// MARK: - Tab Bar Controller +class AIEnabledTabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + setupTabs() + } + + private func setupTabs() { + // Chats - AI features (starters, smart replies, summary) work automatically + let chatsVC = CometChatConversationsWithMessages() + let chatsNav = UINavigationController(rootViewController: chatsVC) + chatsNav.tabBarItem = UITabBarItem( + title: "Chats", + image: UIImage(systemName: "message"), + selectedImage: UIImage(systemName: "message.fill") + ) + + // AI Assistant + let aiVC = AIAssistantListViewController() + let aiNav = UINavigationController(rootViewController: aiVC) + aiNav.tabBarItem = UITabBarItem( + title: "AI Assistant", + image: UIImage(systemName: "sparkles"), + selectedImage: UIImage(systemName: "sparkles") + ) + + // Users + let usersVC = CometChatUsersWithMessages() + let usersNav = UINavigationController(rootViewController: usersVC) + usersNav.tabBarItem = UITabBarItem( + title: "Users", + image: UIImage(systemName: "person.2"), + selectedImage: UIImage(systemName: "person.2.fill") + ) + + viewControllers = [chatsNav, aiNav, usersNav] + } +} + +// MARK: - AI Assistant List +class AIAssistantListViewController: UIViewController { + + private let tableView = UITableView() + private var users: [CometChat.User] = [] + + override func viewDidLoad() { + super.viewDidLoad() + title = "AI Assistant" + setupTableView() + fetchUsers() + } + + private func setupTableView() { + view.addSubview(tableView) + tableView.frame = view.bounds + tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + tableView.delegate = self + tableView.dataSource = self + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") + } + + private func fetchUsers() { + let request = UsersRequest.UsersRequestBuilder() + .set(limit: 30) + .build() + + request.fetchNext { [weak self] users in + self?.users = users + DispatchQueue.main.async { + self?.tableView.reloadData() + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} + +extension AIAssistantListViewController: UITableViewDelegate, UITableViewDataSource { + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return users.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) + let user = users[indexPath.row] + cell.textLabel?.text = user.name + cell.accessoryType = .disclosureIndicator + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let user = users[indexPath.row] + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.user = user + + chatHistory.onNewChatButtonClicked = { [weak self] in + // Start new AI chat + let messagesVC = CometChatMessages() + messagesVC.user = user + self?.navigationController?.pushViewController(messagesVC, animated: true) + } + + navigationController?.pushViewController(chatHistory, animated: true) + } +} +``` + + + +--- + +--- + +## Related + +- [AI Assistant Chat History](/ui-kit/ios/ai-assistant-chat-history) - Full component documentation +- [Message List](/ui-kit/ios/message-list) - Where conversation starters appear +- [Message Composer](/ui-kit/ios/message-composer) - Where smart replies appear +- [Conversation Starter Guide](/fundamentals/ai-user-copilot/conversation-starter) - Platform configuration +- [Smart Replies Guide](/fundamentals/ai-user-copilot/smart-replies) - Platform configuration */} diff --git a/ui-kit/ios/call-buttons.mdx b/ui-kit/ios/call-buttons.mdx index 7f790d10e..0c906c607 100644 --- a/ui-kit/ios/call-buttons.mdx +++ b/ui-kit/ios/call-buttons.mdx @@ -1,15 +1,63 @@ --- title: "Call Buttons" +description: "Provides voice and video call buttons for initiating calls with users or groups" --- -## Overview - -The `Call Button` is a [Component](/ui-kit/ios/components-overview#components) provides users with the ability to make calls, access call-related functionalities, and control call settings. Clicking this button typically triggers the call to be placed to the desired recipient. +The `CometChatCallButtons` component provides users with the ability to make calls, access call-related functionalities, and control call settings. Clicking this button typically triggers the call to be placed to the desired recipient. - + CometChatCallButtons showing voice and video call buttons for initiating calls + +```json +{ + "component": "CometChatCallButtons", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Provides voice and video call buttons for initiating calls with users or groups", + "inherits": "UIView", + "primaryOutput": { + "callback": "onVoiceCallClick", + "type": "(User?, Group?) -> Void" + }, + "props": { + "data": { + "user": { "type": "User?", "default": "nil" }, + "group": { "type": "Group?", "default": "nil" } + }, + "callbacks": { + "onVoiceCallClick": "(User?, Group?) -> Void", + "onVideoCallClick": "(User?, Group?) -> Void", + "onError": "(CometChatException) -> Void" + }, + "visibility": { + "hideVoiceCallButton": { "type": "Bool", "default": false }, + "hideVideoCallButton": { "type": "Bool", "default": false } + } + }, + "events": [ + { "name": "onOutgoingCallAccepted", "payload": "Call", "description": "Fires when outgoing call is accepted" }, + { "name": "onOutgoingCallRejected", "payload": "Call", "description": "Fires when outgoing call is rejected" } + ], + "sdkListeners": [], + "compositionExample": { + "description": "CallButtons is typically used in MessageHeader or as standalone call controls", + "components": ["CometChatCallButtons", "CometChatOutgoingCall"], + "flow": "User taps call button → OutgoingCall screen appears → Call connects or is rejected" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatCallButtons` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIView` | + +--- + ## Usage ### Integration @@ -18,7 +66,7 @@ Since `CometChatCallButton` is a **custom view**, it offers flexibility in integ -```swift +```swift lines let user = User(uid: "your-uid", name: "") let cometChatCallButton = CometChatCallButtons(width: 24, height: 24) @@ -42,7 +90,7 @@ The `setOnVoiceCallClick` action is usually invoked when a voice call is initiat -```swift +```swift lines let cometChatCallButton = CometChatCallButtons(width: 24, height: 24) .set(onVoiceCallClick: { user, group in //Perform Your Action @@ -59,7 +107,7 @@ The `setOnVideoCallClick` action is typically triggered when a video call is ini -```swift +```swift lines let cometChatCallButton = CometChatCallButtons(width: 24, height: 24) .set(onVideoCallClick: { user, group in //Perform Your Action @@ -77,7 +125,7 @@ You can customize this behavior by using the provided code snippet to override t -```swift +```swift lines let cometChatCallButton = CometChatCallButtons(width: 24, height: 24) .set(onError: { error in //Perform Your Action @@ -112,7 +160,7 @@ Events emitted by the Call buttons component is as follows. -```swift +```swift lines // View controller from your project where you want to listen events. public class ViewController: UIViewController { @@ -189,7 +237,7 @@ You can customize the appearance of the `CallButtons` Component by applying the -```swift +```swift lines CometChatCallButtons.style.audioCallButtonBackground = UIColor(hex: "#EDEAFA") CometChatCallButtons.style.audioCallIconTint = UIColor(hex: "#6852D6") CometChatCallButtons.style.videoCallButtonBackground = UIColor(hex: "#EDEAFA") @@ -204,7 +252,7 @@ CometChatCallButtons.style.videoCallIconTint = UIColor(hex: "#6852D6") -```swift +```swift lines let callButtonStyle = CallButtonStyle() callButtonStyle.audioCallButtonBackground = UIColor(hex: "#EDEAFA") callButtonStyle.audioCallIconTint = UIColor(hex: "#6852D6") @@ -220,7 +268,7 @@ callButton.style = callButtonStyle - + CometChatCallButtons with custom styling showing purple tinted call icons on light purple background List of properties exposed by ButtonStyle @@ -284,7 +332,7 @@ You can customize the properties of the Outgoing Call component by making use of -```swift +```swift lines // Create an object of OutgoingCallConfiguration let outgoingCallConfiguration = OutgoingCallConfiguration() ``` @@ -303,7 +351,7 @@ You can modify the style using the `OutgoingCallStyle` property, disable sound f -```swift +```swift lines let outgoingCallConfiguration = OutgoingCallConfiguration() .disable(soundForCalls: true) @@ -324,7 +372,7 @@ To ensure that the `CallButtons` is properly configured, passing the controller * Swift -```swift +```swift lines let callButtons = CometChatCallButtons(width: 24, height: 24) callButtons.set(controller: UIViewController) // Passing the controller is required ``` @@ -332,3 +380,195 @@ callButtons.set(controller: UIViewController) // Passing the controller is requi *** + +## Props + +All props are optional. + +--- + +### user + +The user for 1-on-1 call buttons. Pass either `user` or `group`, not both. + +| | | +|---|---| +| Type | `User?` | +| Default | `nil` | + +--- + +### group + +The group for group call buttons. Pass either `user` or `group`, not both. + +| | | +|---|---| +| Type | `Group?` | +| Default | `nil` | + +--- + +### hideVoiceCallButton + +Hides the voice call button. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### hideVideoCallButton + +Hides the video call button. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### outgoingCallConfiguration + +Configuration object for the internal `CometChatOutgoingCall` sub-component. + +| | | +|---|---| +| Type | `OutgoingCallConfiguration` | +| Default | `OutgoingCallConfiguration()` | + +--- + +### customSoundForCalls + +Custom sound file URL for calls. + +| | | +|---|---| +| Type | `URL?` | +| Default | `nil` | + +--- + +## Events + +Events emitted by the Call Buttons component: + +| Event | Description | +|-------|-------------| +| `onOutgoingCallAccepted` | Triggers when the outgoing call is accepted | +| `onOutgoingCallRejected` | Triggers when the outgoing call is rejected | +| `onCallEnded` | Triggers when the call ends | + +--- + +## Common Patterns + +### Add Call Buttons to Message Header + +Integrate call buttons into a custom message header: + + + +```swift lines +class CustomMessageHeader: UIView { + + private var callButtons: CometChatCallButtons! + + func configure(with user: User) { + callButtons = CometChatCallButtons(width: 24, height: 24) + callButtons.set(user: user) + callButtons.set(controller: parentViewController) + + // Add to header view + addSubview(callButtons) + // Set up constraints... + } +} +``` + + + +### Voice-Only Call Button + +Show only the voice call button for audio-focused apps: + + + +```swift lines +let callButtons = CometChatCallButtons(width: 24, height: 24) +callButtons.set(user: user) +callButtons.hideVideoCallButton = true +callButtons.set(controller: self) +``` + + + +### Custom Call Initiation with Confirmation + +Show confirmation before starting a call: + + + +```swift lines +let callButtons = CometChatCallButtons(width: 24, height: 24) +callButtons.set(user: user) +callButtons.set(onVoiceCallClick: { [weak self] user, group in + let alert = UIAlertController( + title: "Start Voice Call", + message: "Call \(user?.name ?? group?.name ?? "")?", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + alert.addAction(UIAlertAction(title: "Call", style: .default) { _ in + // Initiate the call + self?.initiateVoiceCall(to: user, group: group) + }) + self?.present(alert, animated: true) +}) +``` + + + +### Group Video Call Button + +Configure call buttons for group video calls: + + + +```swift lines +let callButtons = CometChatCallButtons(width: 24, height: 24) +callButtons.set(group: group) +callButtons.hideVoiceCallButton = true // Groups often use video calls +callButtons.set(controller: self) + +// Custom call settings for group calls +callButtons.set(callSettingBuilder: { callType, participants in + return CallSettingsBuilder() + .setDefaultLayout(true) + .setShowRecordingButton(true) +}) +``` + + + +--- + +## Related Components + + + + Display incoming call interface + + + Display outgoing call interface + + + Display call history + + + +*** diff --git a/ui-kit/ios/call-features.mdx b/ui-kit/ios/call-features.mdx index c22dfa285..1505803e6 100644 --- a/ui-kit/ios/call-features.mdx +++ b/ui-kit/ios/call-features.mdx @@ -1,39 +1,47 @@ --- -title: "Call" +title: "Calling Features" +sidebarTitle: "Call" +description: "Complete guide to adding voice and video calling to iOS apps with CometChat UI Kit - production-ready code included" --- -## Overview - -CometChat's Calls feature is an advanced functionality that allows you to seamlessly integrate one-on-one as well as group audio and video calling capabilities into your application. This document provides a technical overview of these features, as implemented in the iOS UI Kit. - -## Integration - -First, make sure that you've correctly integrated the UI Kit library into your project. If you haven't done this yet or are facing difficulties, refer to our [Getting Started](/ui-kit/ios/getting-started) guide. This guide will walk you through a step-by-step process of integrating our UI Kit into your iOS project. - -Once you've successfully integrated the UI Kit, the next step is to add the CometChat Calls SDK to your project. This is necessary to enable the calling features in the UI Kit. Here's how you do it: - -**1. CocoaPods** - -We recommend using CocoaPods, as they are the most advanced way of managing iOS project dependencies. Open a terminal window, move to your project directory, and then create a Podfile by running the following command. - - - -1. You can install CometChatCallsSDK for iOS through Swift Package Manager or Cocoapods + +```json +{ + "category": "calling", + "features": [ + {"name": "voiceCalling", "description": "One-on-one and group audio calls", "component": "CometChatCallButtons", "enabledByDefault": true}, + {"name": "videoCalling", "description": "One-on-one and group video calls", "component": "CometChatCallButtons", "enabledByDefault": true}, + {"name": "callLogs", "description": "View call history with metadata", "component": "CometChatCallLogs", "enabledByDefault": true}, + {"name": "incomingCall", "description": "Handle incoming call UI with accept/reject", "component": "CometChatIncomingCall", "enabledByDefault": true}, + {"name": "outgoingCall", "description": "Display outgoing call screen while connecting", "component": "CometChatOutgoingCall", "enabledByDefault": true}, + {"name": "ongoingCall", "description": "Active call interface with controls", "component": "CometChatOngoingCall", "enabledByDefault": true} + ], + "sdkDependencies": { + "required": "CometChatCallsSDK 4.2.2", + "permissions": ["NSCameraUsageDescription", "NSMicrophoneUsageDescription"] + }, + "relatedComponents": ["CometChatCallButtons", "CometChatCallLogs", "CometChatIncomingCall", "CometChatOutgoingCall", "CometChatOngoingCall"] +} +``` + -2. CometChatCallsSDK supports iOS 13 and aboveSwift 5.0+ +## Overview -3. CometChatCallsSDK supports Swift 5.0+ +Add one-on-one and group audio/video calling to your iOS app. Once integrated, call buttons automatically appear in chat headers, and incoming/outgoing call screens are handled for you. - + + + -```ruby Swift -$ pod init -``` +--- -Add the following lines to the Podfile. +## Quick Setup -```ruby Swift -platform :ios, '11.0' + + +Add to your `Podfile`: +```ruby +platform :ios, '13.0' use_frameworks! target 'YourApp' do @@ -42,86 +50,580 @@ target 'YourApp' do end ``` -And then install the CometChatCallsSDK framework through CocoaPods. - -```ruby Swift -$ pod install +Run: +```bash +pod install ``` + -If you're facing any issues while installing pods then use the below command. + +Add to `Info.plist`: +```xml +NSCameraUsageDescription +Camera access required for video calls -```ruby Swift -$ pod install --repo-update +NSMicrophoneUsageDescription +Microphone access required for voice and video calls +``` + + + +In `SceneDelegate.swift`: +```swift lines +import CometChatUIKitSwift + +func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let windowScene = (scene as? UIWindowScene) else { return } + + let uikitSettings = UIKitSettings() + .set(appID: "YOUR_APP_ID") + .set(authKey: "YOUR_AUTH_KEY") + .set(region: "YOUR_REGION") // "us", "eu", or "in" + .build() + + CometChatUIKit.init(uiKitSettings: uikitSettings) { result in + switch result { + case .success: + CometChatUIKit.login(uid: "cometchat-uid-1") { loginResult in + switch loginResult { + case .success: + // Calling is now enabled automatically + print("✅ Ready for calls") + case .onError(let error): + print("❌ Login failed: \(error.description)") + @unknown default: + break + } + } + case .failure(let error): + print("❌ Init failed: \(error.localizedDescription)") + } + } +} ``` + + -Always get the latest version of CometChatCallsSDK by command. +**That's it!** Call buttons now appear in `CometChatMessages` header automatically. -```ruby Swift -$ pod update CometChatCallsSDK +--- + +## Production-Ready Implementation + +Complete app with calling, chat, and call history: + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let windowScene = (scene as? UIWindowScene) else { return } + + // Initialize CometChat + let uikitSettings = UIKitSettings() + .set(appID: "YOUR_APP_ID") + .set(authKey: "YOUR_AUTH_KEY") + .set(region: "YOUR_REGION") + .subscribePresenceForAllUsers() + .build() + + CometChatUIKit.init(uiKitSettings: uikitSettings) { [weak self] result in + switch result { + case .success: + print("✅ CometChat initialized") + self?.loginAndSetupUI(windowScene: windowScene) + + case .failure(let error): + print("❌ Init failed: \(error.localizedDescription)") + } + } + } + + private func loginAndSetupUI(windowScene: UIWindowScene) { + CometChatUIKit.login(uid: "cometchat-uid-1") { [weak self] result in + switch result { + case .success: + print("✅ Logged in") + DispatchQueue.main.async { + self?.setupMainInterface(windowScene: windowScene) + } + + case .onError(let error): + print("❌ Login failed: \(error.description)") + + @unknown default: + break + } + } + } + + private func setupMainInterface(windowScene: UIWindowScene) { + let tabBar = MainTabBarController() + + window = UIWindow(windowScene: windowScene) + window?.rootViewController = tabBar + window?.makeKeyAndVisible() + } +} +``` + + + +```swift lines +import UIKit +import CometChatUIKitSwift + +class MainTabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + setupTabs() + setupAppearance() + } + + private func setupTabs() { + // Chats Tab - with calling enabled + let chatsVC = CometChatConversationsWithMessages() + let chatsNav = UINavigationController(rootViewController: chatsVC) + chatsNav.tabBarItem = UITabBarItem( + title: "Chats", + image: UIImage(systemName: "message"), + selectedImage: UIImage(systemName: "message.fill") + ) + + // Calls Tab - call history + let callsVC = CometChatCallLogs() + callsVC.set(onItemClick: { [weak self] callLog in + self?.handleCallLogTap(callLog) + }) + let callsNav = UINavigationController(rootViewController: callsVC) + callsNav.tabBarItem = UITabBarItem( + title: "Calls", + image: UIImage(systemName: "phone"), + selectedImage: UIImage(systemName: "phone.fill") + ) + + // Users Tab + let usersVC = CometChatUsersWithMessages() + let usersNav = UINavigationController(rootViewController: usersVC) + usersNav.tabBarItem = UITabBarItem( + title: "Users", + image: UIImage(systemName: "person.2"), + selectedImage: UIImage(systemName: "person.2.fill") + ) + + // Groups Tab + let groupsVC = CometChatGroupsWithMessages() + let groupsNav = UINavigationController(rootViewController: groupsVC) + groupsNav.tabBarItem = UITabBarItem( + title: "Groups", + image: UIImage(systemName: "person.3"), + selectedImage: UIImage(systemName: "person.3.fill") + ) + + viewControllers = [chatsNav, callsNav, usersNav, groupsNav] + } + + private func setupAppearance() { + tabBar.tintColor = .systemBlue + tabBar.backgroundColor = .systemBackground + } + + private func handleCallLogTap(_ callLog: CallLog) { + // Get the other user from call log + let loggedInUser = CometChat.getLoggedInUser() + var otherUserUID: String? + + if let initiator = callLog.initiator as? CallUser, + initiator.uid != loggedInUser?.uid { + otherUserUID = initiator.uid + } else if let receiver = callLog.receiver as? CallUser { + otherUserUID = receiver.uid + } + + guard let uid = otherUserUID else { return } + + // Fetch user and open chat + CometChat.getUser(UID: uid) { [weak self] user in + DispatchQueue.main.async { + let messagesVC = CometChatMessages() + messagesVC.user = user + + if let nav = self?.selectedViewController as? UINavigationController { + nav.pushViewController(messagesVC, animated: true) + } + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} ``` + + - +--- -Always ensure to open the XCFramework file after adding the dependencies. +## Initiate Calls Programmatically + +### Voice Call to User + + + +```swift lines +import CometChatSDK + +func startVoiceCall(to userUID: String) { + let call = CometChat.Call( + receiverId: userUID, + callType: .audio, + receiverType: .user + ) + + CometChat.initiateCall(call: call) { call in + print("✅ Voice call started: \(call?.sessionId ?? "")") + } onError: { error in + print("❌ Call failed: \(error?.errorDescription ?? "")") + } +} + +// Usage +startVoiceCall(to: "cometchat-uid-2") +``` + + + +### Video Call to User + + + +```swift lines +import CometChatSDK + +func startVideoCall(to userUID: String) { + let call = CometChat.Call( + receiverId: userUID, + callType: .video, + receiverType: .user + ) + + CometChat.initiateCall(call: call) { call in + print("✅ Video call started: \(call?.sessionId ?? "")") + } onError: { error in + print("❌ Call failed: \(error?.errorDescription ?? "")") + } +} + +// Usage +startVideoCall(to: "cometchat-uid-2") +``` + + + +### Group Call + + + +```swift lines +import CometChatSDK + +func startGroupCall(to groupGUID: String, type: CometChat.CallType) { + let call = CometChat.Call( + receiverId: groupGUID, + callType: type, + receiverType: .group + ) + + CometChat.initiateCall(call: call) { call in + print("✅ Group call started: \(call?.sessionId ?? "")") + } onError: { error in + print("❌ Call failed: \(error?.errorDescription ?? "")") + } +} + +// Usage +startGroupCall(to: "group-guid", type: .video) +``` + + - +--- -*** +## Custom Call Buttons + +Add call buttons anywhere in your app: + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class UserProfileViewController: UIViewController { + + var user: CometChat.User! + + private let voiceCallButton: UIButton = { + let button = UIButton(type: .system) + button.setImage(UIImage(systemName: "phone.fill"), for: .normal) + button.setTitle(" Voice Call", for: .normal) + button.backgroundColor = .systemGreen + button.tintColor = .white + button.layer.cornerRadius = 12 + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private let videoCallButton: UIButton = { + let button = UIButton(type: .system) + button.setImage(UIImage(systemName: "video.fill"), for: .normal) + button.setTitle(" Video Call", for: .normal) + button.backgroundColor = .systemBlue + button.tintColor = .white + button.layer.cornerRadius = 12 + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + private func setupUI() { + view.backgroundColor = .systemBackground + + let stackView = UIStackView(arrangedSubviews: [voiceCallButton, videoCallButton]) + stackView.axis = .horizontal + stackView.spacing = 16 + stackView.distribution = .fillEqually + stackView.translatesAutoresizingMaskIntoConstraints = false + + view.addSubview(stackView) + + NSLayoutConstraint.activate([ + stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor), + stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32), + stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32), + + voiceCallButton.heightAnchor.constraint(equalToConstant: 50), + videoCallButton.heightAnchor.constraint(equalToConstant: 50) + ]) + + voiceCallButton.addTarget(self, action: #selector(voiceCallTapped), for: .touchUpInside) + videoCallButton.addTarget(self, action: #selector(videoCallTapped), for: .touchUpInside) + } + + @objc private func voiceCallTapped() { + initiateCall(type: .audio) + } + + @objc private func videoCallTapped() { + initiateCall(type: .video) + } + + private func initiateCall(type: CometChat.CallType) { + guard let uid = user.uid else { return } + + let call = CometChat.Call( + receiverId: uid, + callType: type, + receiverType: .user + ) + + CometChat.initiateCall(call: call) { [weak self] call in + print("✅ Call initiated") + } onError: { [weak self] error in + self?.showError(error?.errorDescription ?? "Call failed") + } + } + + private func showError(_ message: String) { + let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } +} +``` + + -**2. Swift Package Manager.** +--- -Add the Call SDK dependency : +## Using CometChatCallButtons Component + +The built-in call buttons component: + + + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatHeaderViewController: UIViewController { + + var user: CometChat.User! + + override func viewDidLoad() { + super.viewDidLoad() + setupCallButtons() + } + + private func setupCallButtons() { + let callButtons = CometChatCallButtons() + callButtons.user = user + + // Customize actions + callButtons.set(onVoiceCallClick: { user, group in + print("Voice call to: \(user?.name ?? group?.name ?? "")") + }) + + callButtons.set(onVideoCallClick: { user, group in + print("Video call to: \(user?.name ?? group?.name ?? "")") + }) + + callButtons.set(onError: { error in + print("Error: \(error.errorDescription)") + }) + + // Add to navigation bar + let hostingController = UIHostingController(rootView: callButtons) + addChild(hostingController) + + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: hostingController.view) + } +} +``` + + -You can install **Calling SDK for iOS** through **Swift Package Manager.** +--- -1. Go to your Swift Package Manager's File tab and select Add Packages +## Handle Incoming Calls + +Incoming calls are handled automatically. For custom handling: + + + +```swift lines +import CometChatSDK + +class CallHandler: NSObject, CometChatCallDelegate { + + static let shared = CallHandler() + + func registerForCalls() { + CometChat.calldelegate = self + } + + // Called when receiving an incoming call + func onIncomingCallReceived(incomingCall: CometChat.Call?, error: CometChat.CometChatException?) { + guard let call = incomingCall else { return } + + print("📞 Incoming call from: \(call.sender?.name ?? "")") + print("Call type: \(call.callType == .audio ? "Audio" : "Video")") + + // The UI Kit automatically shows the incoming call screen + // Add custom logic here if needed + } + + // Called when an outgoing call is accepted + func onOutgoingCallAccepted(acceptedCall: CometChat.Call?, error: CometChat.CometChatException?) { + guard let call = acceptedCall else { return } + print("✅ Call accepted: \(call.sessionId ?? "")") + } + + // Called when an outgoing call is rejected + func onOutgoingCallRejected(rejectedCall: CometChat.Call?, error: CometChat.CometChatException?) { + guard let call = rejectedCall else { return } + print("❌ Call rejected: \(call.sessionId ?? "")") + } + + // Called when an incoming call is cancelled + func onIncomingCallCancelled(canceledCall: CometChat.Call?, error: CometChat.CometChatException?) { + guard let call = canceledCall else { return } + print("📵 Call cancelled: \(call.sessionId ?? "")") + } + + // Called when a call ends + func onCallEnded(endedCall: CometChat.Call?, error: CometChat.CometChatException?) { + guard let call = endedCall else { return } + print("📴 Call ended: \(call.sessionId ?? "")") + } +} + +// Register in AppDelegate or SceneDelegate +// CallHandler.shared.registerForCalls() +``` + + -2. Add `CometChatCallsSDK` into your `Package Repository` as below: +--- -```sh Bash -https://github.com/cometchat/calls-sdk-ios.git -``` +## Calling Components Reference -3. To add the package, select Version Rules, enter Up to Exact Version, **4.0.5** and click Next. +### CometChatCallButtons - +Renders voice and video call buttons. -Before Adding the Call SDK dependency to your project's dependencies please make sure that you have completed the Chat UI Kit Integration. +```swift lines +let callButtons = CometChatCallButtons() +callButtons.user = user // or callButtons.group = group - +// Callbacks +callButtons.set(onVoiceCallClick: { user, group in }) +callButtons.set(onVideoCallClick: { user, group in }) +callButtons.set(onError: { error in }) +``` -After adding this dependency, the iOS UI Kit will automatically detect it and activate the calling features. Now, your application supports both audio and video calling. You will see [CallButtons](/ui-kit/ios/call-buttons) component rendered in [MessageHeader](/ui-kit/ios/message-header) Component. +### CometChatIncomingCall - - - +Displays incoming call screen with accept/reject options. -## Features +```swift lines +let incomingCall = CometChatIncomingCall() +incomingCall.set(call: call) -### Incoming Call +incomingCall.set(onAcceptClick: { call in }) +incomingCall.set(onDeclineClick: { call in }) +``` -The [Incoming Call](/ui-kit/ios/incoming-call) component of the CometChat UI Kit provides the functionality that lets users receive real-time audio and video calls in the app. +### CometChatOutgoingCall -When a call is made to a user, the Incoming Call component triggers and displays a call screen. This call screen typically displays the caller information and provides the user with options to either accept or reject the incoming call. +Displays outgoing call screen while waiting for answer. - - - +```swift lines +let outgoingCall = CometChatOutgoingCall() +outgoingCall.set(call: call) -### Outgoing Call +outgoingCall.set(onCancelClick: { call in }) +``` -The [Outgoing Call](/ui-kit/ios/incoming-call) component of the CometChat UI Kit is designed to manage the outgoing call process within your application. When a user initiates an audio or video call to another user or group, this component displays an outgoing call screen, showcasing information about the recipient and the call status. +### CometChatCallLogs -Importantly, the Outgoing Call component is smartly designed to transition automatically into the ongoing call screen once the receiver accepts the call. This ensures a smooth flow from initiating the call to engaging in a conversation, without any additional steps required from the user. +Displays call history. See [Call Logs](/ui-kit/ios/call-logs) for full documentation. - - - +```swift lines +let callLogs = CometChatCallLogs() +callLogs.set(onItemClick: { callLog in }) +``` -### Call Logs +--- -[Call Logs](/ui-kit/ios/call-logs) component provides you with the records call events such as who called who, the time of the call, and the duration of the call. This information can be fetched from the CometChat server and displayed in a structured format for users to view their past call activities. +## Related - - - +- [Call Logs](/ui-kit/ios/call-logs) - Display call history +- [Call Buttons](/ui-kit/ios/call-buttons) - Call button component +- [Incoming Call](/ui-kit/ios/incoming-call) - Incoming call screen +- [Outgoing Call](/ui-kit/ios/outgoing-call) - Outgoing call screen +- [Ongoing Call](/ui-kit/ios/ongoing-call) - Active call screen diff --git a/ui-kit/ios/call-logs.mdx b/ui-kit/ios/call-logs.mdx index f59346b3a..ab0808108 100644 --- a/ui-kit/ios/call-logs.mdx +++ b/ui-kit/ios/call-logs.mdx @@ -1,15 +1,71 @@ --- title: "Call Logs" +description: "Displays a list of call logs with call type, duration, and participant information" --- -## Overview - -`CometChatCallLogs` is a [Component](/ui-kit/ios/components-overview#components) that shows the list of Call Log available . By default, names are shown for all listed users, along with their avatar if available. +The `CometChatCallLogs` component shows the list of call logs available. By default, names are shown for all listed users, along with their avatar if available. - + CometChatCallLogs showing a list of call history with caller names, call types, and timestamps + +```json +{ + "component": "CometChatCallLogs", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatCallsSDK", + "description": "Displays a list of call logs with call type, duration, and participant information", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onItemClick", + "type": "(Any) -> Void", + "note": "CallLog is passed as Any type, cast to CometChatCallsSDK.CallLog" + }, + "props": { + "data": { + "callRequestBuilder": { "type": "CallLogsRequest.CallLogsBuilder?", "default": "nil" } + }, + "callbacks": { + "onItemClick": "(Any) -> Void", + "onItemLongClick": "(Any, IndexPath) -> Void", + "onBack": "() -> Void", + "onError": "(Any) -> Void", + "onEmpty": "() -> Void", + "onLoad": "([Any]) -> Void" + }, + "visibility": { + "hideError": { "type": "Bool", "default": false }, + "hideNavigationBar": { "type": "Bool", "default": false }, + "hideLoadingState": { "type": "Bool", "default": false }, + "hideBackIcon": { "type": "Bool", "default": false } + }, + "viewSlots": { + "listItemView": "(Any) -> UIView", + "titleView": "(Any) -> UIView", + "leadingView": "(Any) -> UIView", + "trailView": "(Any) -> UIView" + } + }, + "events": [], + "sdkListeners": [], + "compositionExample": { + "description": "CallLogs is typically used as a standalone screen or tab in the main navigation", + "components": ["CometChatCallLogs", "CometChatCallLogDetails"], + "flow": "User views call history → taps call log → sees call details or initiates callback" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatCallLogs` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | + +--- + The `Call Logs` component is composed of the following BaseComponents: | Components | Description | @@ -27,7 +83,7 @@ The `Call Logs` component is composed of the following BaseComponents: -```swift +```swift lines // To navigate to the CometChatCallLogs let callLogs = CometChatCallLogs() self.navigationController?.pushViewController(callLogs, animated: true) @@ -47,10 +103,13 @@ self.navigationController?.pushViewController(callLogs, animated: true) -```swift -// syntax for set(onItemClick: @escaping ((_ callLog: CometChatCallsSDK.CallLog, _ indexPath: IndexPath) -> Void)) -cometChatCallLogs.set(onItemClick: { callLogs, indexPath in +```swift lines +// syntax for set(onItemClick: ((_ callLog: Any) -> ())?) +// Note: callLog is of type CometChatCallsSDK.CallLog, cast it to access properties +cometChatCallLogs.set(onItemClick: { callLog in // Override on item click + guard let callLog = callLog as? CallLog else { return } + // Access callLog properties }) ``` @@ -66,10 +125,13 @@ cometChatCallLogs.set(onItemClick: { callLogs, indexPath in -```swift -// syntax for set(onItemLongClick: @escaping ((_ callLog: CometChatCallsSDK.CallLog, _ indexPath: IndexPath) -> Void)) +```swift lines +// syntax for set(onItemLongClick: ((_ callLog: Any, _ indexPath: IndexPath) -> ())?) +// Note: callLog is of type CometChatCallsSDK.CallLog, cast it to access properties cometChatCallLogs.set(onItemLongClick: { callLog, indexPath in - // Override on item click + // Override on item long click + guard let callLog = callLog as? CallLog else { return } + // Access callLog properties }) ``` @@ -85,7 +147,7 @@ This `set(onBack:)` method becomes valuable when a user needs to override the ac -```swift +```swift lines cometChatCallLogs.set(onBack: { // Override on back }) @@ -103,7 +165,7 @@ This method proves helpful when a user needs to customize the action taken upon -```swift +```swift lines cometChatCallLogs.set(onError: { error in // Override on error }) @@ -121,7 +183,7 @@ This `set(onEmpty:)` method is triggered when the call logs list is empty in Com -```swift +```swift lines cometChatCallLogs.set(onEmpty: { }) @@ -139,7 +201,7 @@ This set(onLoad:) method is triggered when call logs are successfully loaded in -```swift +```swift lines cometChatCallLogs.set(onLoad: { callLogs in }) ``` @@ -178,7 +240,7 @@ In the example below, we are applying a filter based on limit , calltype and cal -```swift +```swift lines let callRequestBuilder = CallLogsRequest.CallLogsBuilder() .set(limit: 2) @@ -222,7 +284,7 @@ You can customize the appearance of the `CallLog` Component by applying the `Cal -```swift +```swift lines let customAvatarStyle = AvatarStyle() customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) @@ -240,7 +302,7 @@ CometChatCallLogs.avatarStyle = customAvatarStyle -```swift +```swift lines let customAvatarStyle = AvatarStyle() customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) @@ -259,7 +321,7 @@ callLog.avatarStyle = customAvatarStyle - + CometChatCallLogs with custom styling showing orange title text and rounded avatar with custom background color List of properties exposed by CallLogStyle @@ -360,7 +422,7 @@ This enables developers to localize, format, or personalize the date and time st -```swift +```swift lines CometChatCallLogs.dateTimeFormatter.time = { timestamp in return "at " + DateFormatter.localizedString(from: Date(timeIntervalSince1970: TimeInterval(timestamp)), dateStyle: .none, timeStyle: .short) } @@ -384,7 +446,7 @@ CometChatCallLogs.dateTimeFormatter.otherDay = { timestamp in // This will displ -```swift +```swift lines let callLogs = CometChatCallLogs() callLogs.dateTimeFormatter.yesterday = { timestamp in return "Yesterday at " + formattedTime(from: timestamp) @@ -419,7 +481,7 @@ With this function, you can assign a custom ListItem to the CallLogs Component. -```swift +```swift lines let callLogs = CometChatCallLogs() callLogs.set(listItemView: { callLog in let view = CustomListItem() @@ -432,12 +494,12 @@ callLogs.set(listItemView: { callLog in - + CometChatCallLogs with custom list item view showing call icon, caller name, subtitle, and date -```swift +```swift lines import UIKit import CometChatUIKitSwift import CometChatCallsSDK @@ -530,7 +592,7 @@ You can create a custom Title view for more complex or unique list items and int -```swift +```swift lines let callLogs = CometChatCallLogs() callLogs.set(titleView: { callLog in let view = CustomTitleView() @@ -546,12 +608,12 @@ callLogs.set(titleView: { callLog in **Example** - + CometChatCallLogs with custom title view showing caller name with clock icon and duration -```swift +```swift lines import UIKit import CometChatUIKitSwift import CometChatSDK @@ -653,7 +715,7 @@ You can create a custom Title view for more complex or unique list items and int -```swift +```swift lines let callLogs = CometChatCallLogs() callLogs.set(leadingView: { callLog in let view = CustomLeadingView() @@ -669,12 +731,12 @@ callLogs.set(leadingView: { callLog in **Example** - + CometChatCallLogs with custom leading view showing purple circular call icon button -```swift +```swift lines import UIKit import CometChatUIKitSwift import CometChatSDK @@ -744,7 +806,7 @@ Afterwards, seamlessly integrate this `SubtitleView` UIView file into the `.setS -```swift +```swift lines let callLogs = CometChatCallLogs() callLogs.set(subtitleView: { callLog in let view = CustomSubtitleView() @@ -759,12 +821,12 @@ callLogs.set(subtitleView: { callLog in **Example** - + CometChatCallLogs with custom subtitle view showing call initiation timestamp -```swift +```swift lines import UIKit import CometChatUIKitSwift import CometChatSDK @@ -830,7 +892,7 @@ Afterwards, seamlessly integrate this `CustomTrailView` UIView file into the `.s -```swift +```swift lines let callLogs = CometChatCallLogs() callLogs.set(trailView: { callLog in let view = CustomTrailView() @@ -845,12 +907,12 @@ callLogs.set(trailView: { callLog in **Example** - + CometChatCallLogs with custom trail view showing call timestamp on the right side -```swift +```swift lines import UIKit import CometChatUIKitSwift import CometChatSDK @@ -906,10 +968,255 @@ class CustomTrailView: UIView { *** +--- + +## Props + +All props are optional. + +--- + +### callRequestBuilder + +Controls which call logs load and in what order. + +| | | +|---|---| +| Type | `CallLogsRequest.CallLogsBuilder?` | +| Default | `nil` | + +--- + +### hideError + +Hides the error state view. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### hideNavigationBar + +Hides the navigation bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### hideLoadingState + +Hides the loading state view. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### hideBackIcon + +Hides the back icon in the navigation bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### avatarStyle + +Customizes the appearance of avatars in the call logs list. + +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | + +```swift lines +import CometChatUIKitSwift + +let customAvatarStyle = AvatarStyle() +customAvatarStyle.backgroundColor = UIColor.systemBlue +customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) + +let callLogs = CometChatCallLogs() +callLogs.avatarStyle = customAvatarStyle +``` + +--- + +## Events + +Events emitted by the Call Logs component: + +| Event | Description | +|-------|-------------| +| `onItemClick` | Triggers when a call log item is clicked | +| `onItemLongClick` | Triggers when a call log item is long pressed | +| `onBack` | Triggers when the back button is pressed | +| `onError` | Triggers when an error occurs | +| `onEmpty` | Triggers when the call logs list is empty | +| `onLoad` | Triggers when call logs are successfully loaded | + +--- + +## View Slots + +| Slot | Signature | Replaces | +|------|-----------|----------| +| `listItemView` | `(CallLog) -> UIView` | Entire list item row | +| `titleView` | `(CallLog) -> UIView` | Name / title text | +| `leadingView` | `(CallLog) -> UIView` | Avatar / left section | +| `trailView` | `(CallLog) -> UIView` | Right section with call button | +| `subtitleView` | `(CallLog) -> UIView` | Call type, direction, timestamp | + +--- + Ensure to pass and present `CometChatCallLogs`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. +--- + +## Common Patterns + +### Present Call Logs as a Tab + +Add call logs as a tab in your main navigation: + + + +```swift lines +class MainTabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + + let callLogs = CometChatCallLogs() + let callLogsNav = UINavigationController(rootViewController: callLogs) + callLogsNav.tabBarItem = UITabBarItem( + title: "Calls", + image: UIImage(systemName: "phone"), + selectedImage: UIImage(systemName: "phone.fill") + ) + + viewControllers = [/* other tabs */, callLogsNav] + } +} +``` + + + +### Callback on Call Log Selection + +Handle call log selection to initiate a callback: + + + +```swift lines +let callLogs = CometChatCallLogs() +callLogs.set(onItemClick: { [weak self] callLog, indexPath in + // Get the other participant + var callUser: CallUser? + if let initiator = callLog.initiator as? CallUser, + initiator.uid != CometChatUIKit.getLoggedInUser()?.uid { + callUser = initiator + } else if let receiver = callLog.receiver as? CallUser { + callUser = receiver + } + + guard let user = callUser else { return } + + // Show callback options + let alert = UIAlertController(title: "Call \(user.name ?? "")?", message: nil, preferredStyle: .actionSheet) + alert.addAction(UIAlertAction(title: "Voice Call", style: .default) { _ in + self?.initiateCall(uid: user.uid ?? "", type: .audio) + }) + alert.addAction(UIAlertAction(title: "Video Call", style: .default) { _ in + self?.initiateCall(uid: user.uid ?? "", type: .video) + }) + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + self?.present(alert, animated: true) +}) +``` + + + +### Filter Call Logs by Type + +Show only missed calls or specific call types: + + + +```swift lines +// Show only missed calls +let missedCallsBuilder = CallLogsRequest.CallLogsBuilder() + .set(callStatus: .unanswered) + .set(limit: 30) + +let callLogs = CometChatCallLogs() +callLogs.set(callRequestBuilder: missedCallsBuilder) + +// Show only video calls +let videoCallsBuilder = CallLogsRequest.CallLogsBuilder() + .set(callType: .video) + .set(limit: 30) +``` + + + +### Call Logs with Custom Empty State + +Show a custom view when there are no call logs: + + + +```swift lines +let callLogs = CometChatCallLogs() + +callLogs.set(onEmpty: { [weak self] in + // Show custom empty state or prompt user to make their first call + print("No call history yet") +}) + +// Or set a custom empty view +let emptyView = UIView() +let label = UILabel() +label.text = "No calls yet\nStart a conversation!" +label.textAlignment = .center +label.numberOfLines = 0 +emptyView.addSubview(label) +// Add constraints... + +callLogs.set(emptyView: emptyView) +``` + + + +--- + +## Related Components + + + + Display incoming call interface + + + Display outgoing call interface + + + Voice and video call buttons + + + *** diff --git a/ui-kit/ios/color-resources.mdx b/ui-kit/ios/color-resources.mdx index 097b70398..9e4bd68de 100644 --- a/ui-kit/ios/color-resources.mdx +++ b/ui-kit/ios/color-resources.mdx @@ -1,60 +1,333 @@ --- title: "Color Resources" +sidebarTitle: "Color Resources" +description: "Complete guide to customizing colors in CometChat iOS UI Kit - themes, dark mode, and branding" --- -## Overview + -Color resources in CometChatTheme for iOS enable you to maintain a consistent visual identity across your application. These predefined colors are used for various UI elements, including text, buttons, backgrounds, alerts, and more. +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Theme Class | `CometChatTheme` | +| Primary Color | `CometChatTheme.primaryColor` — Main brand color (#6852D6 default) | +| Background Colors | `backgroundColor01`, `backgroundColor02`, `backgroundColor03` | +| Text Colors | `textColorPrimary`, `textColorSecondary`, `textColorTertiary` | +| Alert Colors | `successColor`, `errorColor`, `warningColor`, `infoColor` | +| Dark Mode | Use `UIColor { traitCollection in }` for dynamic colors | +| Apply Timing | Set theme before `CometChatUIKit.init()` | -CometChatTheme adapts seamlessly to **Light mode** and **Dark mode**, ensuring an optimal user experience across different system appearances. + -The color resources are divided into the following categories: +## Overview -* **Primary Colors**: Define the main theme of the application. -* **Neutral Colors**: Used for backgrounds, strokes, and secondary UI elements. -* **Alert Colors**: Highlight states like success, warning, error, or information. -* **Text Colors**: Used for typography. -* **Icon Colors**: Define icon appearances. -* **Button Colors**: Customize button backgrounds, icons, and text. +CometChat UI Kit uses `CometChatTheme` to manage colors across all components. Colors automatically adapt to Light and Dark mode, ensuring a consistent experience. -CometChatTheme provides separate color definitions for light and dark modes, allowing seamless adaptation to the system's theme. + + + + + + + + + + + + -## Usage +--- -Default Colors CometChatTheme includes predefined color sets for Light and Dark modes. These color sets ensure proper visual contrast, accessibility, and consistent branding. With CometChatTheme, the predefined colors are automatically applied based on the system’s appearance. +## Color Categories -You can access and use these default colors directly through the CometChatTheme class. +| Category | Purpose | Examples | +|----------|---------|----------| +| **Primary** | Main brand color, buttons, links | `primaryColor` | +| **Background** | Screen and component backgrounds | `backgroundColor01`, `backgroundColor02` | +| **Text** | Typography colors | `textColorPrimary`, `textColorSecondary` | +| **Border** | Dividers and outlines | `borderColorLight`, `borderColorDark` | +| **Alert** | Status indicators | `successColor`, `errorColor`, `warningColor` | +| **Icon** | Icon tints | `iconColorPrimary`, `iconColorSecondary` | + +--- -Example: Light Mode Color Usage +## Quick Start + +### Access Default Colors -```swift -CometChatTheme.primaryColor // Example: UIColor(hex: "#6852D6") -CometChatTheme.backgroundColor01 // Light: UIColor(hex: "#FFFFFF") +```swift lines +import CometChatUIKitSwift + +// Primary brand color +let primary = CometChatTheme.primaryColor // #6852D6 + +// Background colors +let background = CometChatTheme.backgroundColor01 // White (light) / #141414 (dark) +let secondaryBg = CometChatTheme.backgroundColor02 + +// Text colors +let primaryText = CometChatTheme.textColorPrimary +let secondaryText = CometChatTheme.textColorSecondary + +// Alert colors +let success = CometChatTheme.successColor // Green +let error = CometChatTheme.errorColor // Red +let warning = CometChatTheme.warningColor // Orange + +// Icon colors +let iconPrimary = CometChatTheme.iconColorPrimary +let iconSecondary = CometChatTheme.iconColorSecondary ``` + + + +--- + +## Customize Theme Colors + +### Change Primary Color (Brand Color) + + +```swift lines +import CometChatUIKitSwift + +// Set your brand color globally +CometChatTheme.primaryColor = UIColor(hex: "#FF5722") // Orange brand + +// All components will now use this color for: +// - Buttons +// - Links +// - Selected states +// - Accent elements +``` + + +### Complete Theme Customization + + + +```swift lines +import CometChatUIKitSwift + +class ThemeManager { + + static func applyCustomTheme() { + // Brand colors + CometChatTheme.primaryColor = UIColor(hex: "#6200EE") // Purple + + // Background colors + CometChatTheme.backgroundColor01 = UIColor(hex: "#FFFFFF") + CometChatTheme.backgroundColor02 = UIColor(hex: "#F5F5F5") + CometChatTheme.backgroundColor03 = UIColor(hex: "#EEEEEE") + + // Text colors + CometChatTheme.textColorPrimary = UIColor(hex: "#212121") + CometChatTheme.textColorSecondary = UIColor(hex: "#757575") + CometChatTheme.textColorTertiary = UIColor(hex: "#9E9E9E") + + // Border colors + CometChatTheme.borderColorLight = UIColor(hex: "#E0E0E0") + CometChatTheme.borderColorDark = UIColor(hex: "#BDBDBD") + + // Alert colors + CometChatTheme.successColor = UIColor(hex: "#4CAF50") + CometChatTheme.errorColor = UIColor(hex: "#F44336") + CometChatTheme.warningColor = UIColor(hex: "#FF9800") + CometChatTheme.infoColor = UIColor(hex: "#2196F3") + + // Icon colors + CometChatTheme.iconColorPrimary = UIColor(hex: "#212121") + CometChatTheme.iconColorSecondary = UIColor(hex: "#757575") + } +} +// Apply in AppDelegate or SceneDelegate +ThemeManager.applyCustomTheme() +``` + - - - +--- + +## Dark Mode Support -Example: Dark Mode Color Usage +CometChat automatically adapts to system appearance. You can also customize dark mode colors: -```swift -CometChatTheme.primaryColor // Example: UIColor(hex: "#6852D6") -CometChatTheme.backgroundColor01 // Light: UIColor(hex: "#141414") -``` +```swift lines +import CometChatUIKitSwift +import UIKit +class ThemeManager { + + static func applyTheme() { + // Create dynamic colors that adapt to light/dark mode + CometChatTheme.primaryColor = UIColor { traitCollection in + return traitCollection.userInterfaceStyle == .dark + ? UIColor(hex: "#BB86FC") // Light purple for dark mode + : UIColor(hex: "#6200EE") // Purple for light mode + } + + CometChatTheme.backgroundColor01 = UIColor { traitCollection in + return traitCollection.userInterfaceStyle == .dark + ? UIColor(hex: "#121212") // Dark background + : UIColor(hex: "#FFFFFF") // White background + } + + CometChatTheme.textColorPrimary = UIColor { traitCollection in + return traitCollection.userInterfaceStyle == .dark + ? UIColor(hex: "#FFFFFF") // White text + : UIColor(hex: "#212121") // Dark text + } + } +} +``` + + +--- + +## Color Reference + +### Primary Colors + +| Property | Light Mode | Dark Mode | Usage | +|----------|------------|-----------|-------| +| `primaryColor` | `#6852D6` | `#6852D6` | Buttons, links, accents | + +### Background Colors + +| Property | Light Mode | Dark Mode | Usage | +|----------|------------|-----------|-------| +| `backgroundColor01` | `#FFFFFF` | `#141414` | Main background | +| `backgroundColor02` | `#F5F5F5` | `#1E1E1E` | Secondary background | +| `backgroundColor03` | `#EEEEEE` | `#2C2C2C` | Tertiary background | + +### Text Colors + +| Property | Light Mode | Dark Mode | Usage | +|----------|------------|-----------|-------| +| `textColorPrimary` | `#141414` | `#FFFFFF` | Main text | +| `textColorSecondary` | `#727272` | `#A0A0A0` | Secondary text | +| `textColorTertiary` | `#A0A0A0` | `#727272` | Hints, placeholders | +### Alert Colors + +| Property | Color | Usage | +|----------|-------|-------| +| `successColor` | `#09C26F` | Success states | +| `errorColor` | `#F44649` | Errors, missed calls | +| `warningColor` | `#FFAB00` | Warnings | +| `infoColor` | `#2196F3` | Information | + +### Border Colors + +| Property | Light Mode | Dark Mode | Usage | +|----------|------------|-----------|-------| +| `borderColorLight` | `#E8E8E8` | `#2C2C2C` | Subtle borders | +| `borderColorDark` | `#CCCCCC` | `#404040` | Prominent borders | + +--- + +## Production Example + +Complete app with custom branding: + + + +```swift lines +import UIKit +import CometChatUIKitSwift + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + // Apply custom theme before initializing CometChat + applyBrandTheme() + + return true + } + + private func applyBrandTheme() { + // Your brand colors + let brandPrimary = UIColor(hex: "#1E88E5") // Blue + let brandSecondary = UIColor(hex: "#FFC107") // Amber + + // Apply to CometChat theme + CometChatTheme.primaryColor = brandPrimary + + // Customize backgrounds + CometChatTheme.backgroundColor01 = UIColor { trait in + trait.userInterfaceStyle == .dark + ? UIColor(hex: "#0D1117") + : UIColor(hex: "#FFFFFF") + } + + CometChatTheme.backgroundColor02 = UIColor { trait in + trait.userInterfaceStyle == .dark + ? UIColor(hex: "#161B22") + : UIColor(hex: "#F6F8FA") + } + + // Customize text + CometChatTheme.textColorPrimary = UIColor { trait in + trait.userInterfaceStyle == .dark + ? UIColor(hex: "#C9D1D9") + : UIColor(hex: "#24292F") + } + + CometChatTheme.textColorSecondary = UIColor { trait in + trait.userInterfaceStyle == .dark + ? UIColor(hex: "#8B949E") + : UIColor(hex: "#57606A") + } + + // Alert colors + CometChatTheme.successColor = UIColor(hex: "#238636") + CometChatTheme.errorColor = UIColor(hex: "#DA3633") + CometChatTheme.warningColor = brandSecondary + } +} + +// UIColor extension for hex support +extension UIColor { + convenience init(hex: String) { + var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines) + hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "") + + var rgb: UInt64 = 0 + Scanner(string: hexSanitized).scanHexInt64(&rgb) + + let r = CGFloat((rgb & 0xFF0000) >> 16) / 255.0 + let g = CGFloat((rgb & 0x00FF00) >> 8) / 255.0 + let b = CGFloat(rgb & 0x0000FF) / 255.0 + + self.init(red: r, green: g, blue: b, alpha: 1.0) + } +} +``` + - - - +--- + +## Related + + + + Style individual components + + + Complete theming guide + + + Initial setup + + diff --git a/ui-kit/ios/component-styling.mdx b/ui-kit/ios/component-styling.mdx index 369923b4e..8e6fc6d0a 100644 --- a/ui-kit/ios/component-styling.mdx +++ b/ui-kit/ios/component-styling.mdx @@ -1,240 +1,334 @@ --- title: "Component Styling" +sidebarTitle: "Component Styling" +description: "Complete guide to styling CometChat iOS UI Kit components - colors, fonts, and custom appearances" --- -## Overview + -CometChat UIKit for iOS enables developers to integrate customizable components into their applications effortlessly. Each component is designed to ensure a consistent user experience, offering flexibility to align with your app’s design system. You can modify attributes such as colors, fonts, sizes, and more using CometChatTheme or directly applying styles to components. +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Global Styling | `CometChatConversations.style.titleColor = UIColor` | +| Instance Styling | `let style = ConversationsStyle(); conversations.style = style` | +| Style Classes | `ConversationsStyle`, `UsersStyle`, `GroupsStyle`, `MessageListStyle`, etc. | +| Base Styles | `AvatarStyle`, `BadgeStyle`, `StatusIndicatorStyle`, `ReceiptStyle` | +| Apply Timing | Global styles before `CometChatUIKit.init()` | +| Precedence | Instance styles override global styles | -Below is a detailed guide for styling individual components within the UIKit. + -## Components +## Overview -### Conversations +Every CometChat component can be styled to match your app's design. You can apply styles globally (affects all instances) or per-instance (affects one component). + +--- + +## Styling Methods -The `CometChatConversations` component provides a list of recent chats, displaying participants, message previews, and timestamps. It supports default themes while offering extensive customization for text appearance, icons, and layout. This component allows you to create an intuitive and visually appealing chat list that matches your app's branding. +### Global Styling -You can check out the list of styling properties offered by [CometChatConversations](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Conversations/ConversationsStyle.swift) +Apply once, affects all instances of a component: -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = 8 +```swift lines +import CometChatUIKitSwift -let customReceiptStyle = ReceiptStyle() -customReceiptStyle.backgroundColor = UIColor(hex: "#F76808") +// Set before using any components (e.g., in AppDelegate) +CometChatConversations.style.titleColor = UIColor(hex: "#6200EE") +CometChatConversations.style.titleFont = UIFont.systemFont(ofSize: 28, weight: .bold) +CometChatConversations.style.backgroundColor = .systemBackground +``` + + -let customBadgeStyle = BadgeStyle() -customBadgeStyle.backgroundColor = UIColor(hex: "#F76808") +### Instance Styling -let customConversation = CometChatConversation() -customConversation.avatarStyle = customAvatarStyle -customConversation.receiptStyle = customReceiptStyle -customConversation.badgeStyle = customBadgeStyle -``` +Apply to a specific component instance: - + + +```swift lines +import CometChatUIKitSwift + +let style = ConversationsStyle() +style.titleColor = UIColor(hex: "#6200EE") +style.titleFont = UIFont.systemFont(ofSize: 28, weight: .bold) +style.backgroundColor = .systemBackground +let conversations = CometChatConversations() +conversations.style = style +``` + - - - +--- -### Users +## Component Styles -The CometChatUsers component displays a scrollable list of users, ideal for showcasing available contacts for messaging, calls, or group creation. Customization includes user avatars, status indicators, and list backgrounds, enabling alignment with your app's design system. +### Conversations -You can check out the list of styling properties offered by [CometChatUsers](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Users/UsersStyle.swift) + + + -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = 8 - -let customReceiptStyle = ReceiptStyle() -customReceiptStyle.backgroundColor = UIColor(hex: "#F76808") - -let customBadgeStyle = BadgeStyle() -customBadgeStyle.backgroundColor = UIColor(hex: "#F76808") - -CometChatUsers.style.titleColor = UIColor(hexString: "#F76808") -CometChatUsers.style.titleFont = UIFont(name: "Times-New-Roman", size: 34) -CometChatUsers.avatarStyle = customAvatarStyle -CometChatUsers.receiptStyle = customReceiptStyle -CometChatUsers.badgeStyle = customBadgeStyle +```swift lines +import CometChatUIKitSwift + +// Create custom styles +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(hex: "#FBAA75") +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) + +let badgeStyle = BadgeStyle() +badgeStyle.backgroundColor = UIColor(hex: "#F76808") +badgeStyle.textColor = .white +badgeStyle.textFont = UIFont.systemFont(ofSize: 12, weight: .bold) + +let receiptStyle = ReceiptStyle() +receiptStyle.readIconTint = UIColor(hex: "#6200EE") +receiptStyle.deliveredIconTint = UIColor(hex: "#9E9E9E") + +// Apply to conversations +let conversations = CometChatConversations() +conversations.avatarStyle = avatarStyle +conversations.badgeStyle = badgeStyle +conversations.receiptStyle = receiptStyle + +// Style the list +conversations.style.titleColor = UIColor(hex: "#212121") +conversations.style.titleFont = UIFont.systemFont(ofSize: 17, weight: .semibold) +conversations.style.subtitleColor = UIColor(hex: "#757575") +conversations.style.subtitleFont = UIFont.systemFont(ofSize: 14) +conversations.style.backgroundColor = .systemBackground +conversations.style.listItemBackground = .systemBackground ``` - - - - - +[View all ConversationsStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Conversations/ConversationsStyle.swift) -### Groups +--- -The CometChatGroups component enables displaying and interacting with chat groups. Each group item highlights key details like group name, participant count, and last active time. Developers can customize avatar styles, fonts, borders, and background colors. +### Users -You can check out the list of styling properties offered by [CometChatGroups](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Groups/GroupsStyle.swift) + + + -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = 8 - -let customReceiptStyle = ReceiptStyle() -customReceiptStyle.backgroundColor = UIColor(hex: "#F76808") - -let customBadgeStyle = BadgeStyle() -customBadgeStyle.backgroundColor = UIColor(hex: "#F76808") - -CometChatGroups.style.titleColor = UIColor(hexString: "#F76808") -CometChatGroups.style.titleFont = UIFont(name: "Times-New-Roman", size: 34) -CometChatGroups.avatarStyle = customAvatarStyle -CometChatGroups.receiptStyle = customReceiptStyle -CometChatGroups.badgeStyle = customBadgeStyle +```swift lines +import CometChatUIKitSwift + +// Avatar style +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(hex: "#FBAA75") +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) + +// Status indicator style +let statusStyle = StatusIndicatorStyle() +statusStyle.backgroundColor = .systemGreen +statusStyle.borderColor = .white +statusStyle.borderWidth = 2 + +// Apply styles +let users = CometChatUsers() +users.avatarStyle = avatarStyle +users.statusIndicatorStyle = statusStyle + +// List styling +users.style.titleColor = UIColor(hex: "#F76808") +users.style.titleFont = UIFont(name: "Helvetica-Bold", size: 28) +users.style.listItemTitleColor = UIColor(hex: "#212121") +users.style.listItemTitleFont = UIFont.systemFont(ofSize: 16, weight: .medium) +users.style.backgroundColor = .systemBackground ``` - - - - - +[View all UsersStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Users/UsersStyle.swift) -### Message Header +--- -The CometChatMessageHeader component displays essential information about the active chat, such as the recipient's name, avatar, and status (online/offline). It also includes navigation, search, or menu buttons. Customization options include header background, text appearance, and icon styles. +### Groups -You can check out the list of styling properties offered by [CometChatMessageHeader](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20Header/MessageHeaderStyle.swift) + + + -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") - -CometChatMessageHeader.style.titleTextColor = UIColor(hexString: "#F76808") -CometChatMessageHeader.style.titleTextFont = UIFont(name: "Times-New-Roman", size: 16) -CometChatMessageHeader.style.avatarStyle = customAvatarStyle +```swift lines +import CometChatUIKitSwift + +// Avatar style for group icons +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(hex: "#FBAA75") +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) + +// Apply styles +let groups = CometChatGroups() +groups.avatarStyle = avatarStyle + +// List styling +groups.style.titleColor = UIColor(hex: "#F76808") +groups.style.titleFont = UIFont(name: "Helvetica-Bold", size: 28) +groups.style.listItemTitleColor = UIColor(hex: "#212121") +groups.style.listItemSubtitleColor = UIColor(hex: "#757575") +groups.style.backgroundColor = .systemBackground ``` - - - - - +[View all GroupsStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Groups/GroupsStyle.swift) -### Message List +--- -The CometChatMessageList component displays a conversation's sequence of messages, supporting text, media, reactions, and more. Developers can customize bubble colors, text appearance, timestamps, and alignment to enhance the chat experience. +### Message Header -You can check out the list of styling properties offered by [CometChatMessageList](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/MessageListStyle.swift) + + + -```swift -CometChatMessageList.style.backgroundColor = UIColor(hexString: "#FBAA75") -CometChatMessageList.messageBubbleStyle.outgoing.backgroundColor = UIColor(hexString: "#F76808") +```swift lines +import CometChatUIKitSwift + +// Avatar style +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(hex: "#FBAA75") +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) + +// Apply to message header +CometChatMessageHeader.style.titleTextColor = UIColor(hex: "#F76808") +CometChatMessageHeader.style.titleTextFont = UIFont(name: "Helvetica-Bold", size: 18) +CometChatMessageHeader.style.subtitleTextColor = UIColor(hex: "#757575") +CometChatMessageHeader.style.backgroundColor = .systemBackground +CometChatMessageHeader.avatarStyle = avatarStyle ``` - - +[View all MessageHeaderStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20Header/MessageHeaderStyle.swift) + +--- + +### Message List + -### Message Composer + + +```swift lines +import CometChatUIKitSwift -The CometChatMessageComposer component provides users with an interface to compose and send messages, including text, attachments, and stickers. Developers can style input boxes, buttons, and icons to match their app’s design. +// Background color +CometChatMessageList.style.backgroundColor = UIColor(hex: "#FBAA75") -You can check out the list of styling properties offered by [CometChatMessageList](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20Composer/MessageComposerStyle.swift) +// Outgoing message bubbles (your messages) +CometChatMessageBubble.style.outgoing.backgroundColor = UIColor(hex: "#F76808") +CometChatMessageBubble.style.outgoing.textBubbleStyle.textColor = .white +CometChatMessageBubble.style.outgoing.textBubbleStyle.textFont = UIFont.systemFont(ofSize: 15) - - -```swift -CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = UIColor(hexString: "#F76808") -CometChatMessageComposer.style.attachmentImageTint = UIColor(hexString: "#F76808") -CometChatMessageComposer.style.voiceRecordingImageTint = UIColor(hexString: "#F76808") -CometChatMessageComposer.style.stickerTint = UIColor(hexString: "#F76808") -CometChatMessageComposer.style.aiImageTint = UIColor(hexString: "#F76808") -``` +// Incoming message bubbles (other's messages) +CometChatMessageBubble.style.incoming.backgroundColor = UIColor(hex: "#E8E8E8") +CometChatMessageBubble.style.incoming.textBubbleStyle.textColor = UIColor(hex: "#212121") +CometChatMessageBubble.style.incoming.textBubbleStyle.textFont = UIFont.systemFont(ofSize: 15) +// Timestamp style +CometChatMessageList.style.timestampTextColor = UIColor(hex: "#9E9E9E") +CometChatMessageList.style.timestampTextFont = UIFont.systemFont(ofSize: 11) +``` - - - - +[View all MessageListStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/MessageListStyle.swift) -### Call Logs +--- -The CometChatCallLogs Component provides a comprehensive list of recent voice and video calls. Each call log displays details such as the caller’s name, avatar, call type (audio/video), call status (missed, incoming, outgoing), and timestamps. This component ensures smooth integration and allows developers to customize styles, icons, and colors to align with the app’s branding. +### Message Composer -You can check out the list of styling properties offered by [CometChatCallLogs](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Calls/Call%20Log/Call%20Logs/CallLogStyle.swift) + + + -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = 8 - -CometChatCallLogs.style.titleColor = UIColor(hexString: "#F76808") -CometChatCallLogs.style.titleFont = UIFont(name: "Roboto", size: 24) -CometChatCallLogs.avatarStyle = customAvatarStyle +```swift lines +import CometChatUIKitSwift + +// Send button +CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = UIColor(hex: "#F76808") +CometChatMessageComposer.style.sendButtonImageTint = .white + +// Action icons +CometChatMessageComposer.style.attachmentImageTint = UIColor(hex: "#F76808") +CometChatMessageComposer.style.voiceRecordingImageTint = UIColor(hex: "#F76808") +CometChatMessageComposer.style.stickerTint = UIColor(hex: "#F76808") +CometChatMessageComposer.style.aiImageTint = UIColor(hex: "#F76808") + +// Input field +CometChatMessageComposer.style.inputBackgroundColor = UIColor(hex: "#F5F5F5") +CometChatMessageComposer.style.inputTextColor = UIColor(hex: "#212121") +CometChatMessageComposer.style.inputTextFont = UIFont.systemFont(ofSize: 16) +CometChatMessageComposer.style.placeholderTextColor = UIColor(hex: "#9E9E9E") + +// Background +CometChatMessageComposer.style.backgroundColor = .systemBackground +CometChatMessageComposer.style.borderColor = UIColor(hex: "#E8E8E8") ``` - - +[View all MessageComposerStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20Composer/MessageComposerStyle.swift) + +--- + +### Call Logs + -### AI Assistant Chat History - -The CometChatAIAssistantChatHistory component provides a pre-built interface to display the conversation history between a user and an AI assistant. Each message shows the sender, timestamp, and message content. This component ensures smooth integration and allows developers to customize styles, icons, and colors to align with the app’s branding. - -```swift -let customDateStyle = CometChatDateStyle( -textColor: UIColor(hexString: "#8E8E93"), -textStyle: UIFont.systemFont(ofSize: 12) -) -CometChatAIAssistantChatHistory.style.backgroundColor = UIColor(hexString: "#FFF9F2") -CometChatAIAssistantChatHistory.style.headerBackgroundColor = UIColor(hexString: "#FFF9F2") -CometChatAIAssistantChatHistory.style.headerTitleTextColor = UIColor(hexString: "#141414") -CometChatAIAssistantChatHistory.style.headerTitleTextFont = UIFont.boldSystemFont(ofSize: 18) -CometChatAIAssistantChatHistory.style.newChatIconColor = UIColor(hexString: "#F76808") -CometChatAIAssistantChatHistory.style.itemTextColor = UIColor(hexString: "#141414") -CometChatAIAssistantChatHistory.style.itemTextFont = UIFont.systemFont(ofSize: 14) -CometChatAIAssistantChatHistory.style.dateSeparatorStyle = customDateStyle +```swift lines +import CometChatUIKitSwift + +// Avatar style +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(hex: "#FBAA75") +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) + +// Apply styles +CometChatCallLogs.style.titleColor = UIColor(hex: "#F76808") +CometChatCallLogs.style.titleFont = UIFont(name: "Helvetica-Bold", size: 24) +CometChatCallLogs.style.listItemTitleTextColor = UIColor(hex: "#212121") +CometChatCallLogs.style.listItemSubTitleTextColor = UIColor(hex: "#757575") +CometChatCallLogs.style.backgroundColor = .systemBackground + +// Call type icons +CometChatCallLogs.style.incomingCallIconTint = .systemRed +CometChatCallLogs.style.outgoingCallIconTint = .systemGreen +CometChatCallLogs.style.missedCallTitleColor = .systemRed + +CometChatCallLogs.avatarStyle = avatarStyle ``` - - -### Search +[View all CallLogStyle properties →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Calls/Call%20Log/Call%20Logs/CallLogStyle.swift) + +--- -The `CometChatSearch` component allows users to search through conversations and messages. It provides a user-friendly interface for finding specific content quickly, with customizable styles for various elements such as background colors, text appearances, and section headers. +### Search @@ -242,129 +336,228 @@ The `CometChatSearch` component allows users to search through conversations and +```swift lines +import CometChatUIKitSwift -```swift - -// component level styling +// Instance styling let style = SearchStyle() style.backgroundColor = UIColor(hex: "#EDEAFA") style.listItemBackground = UIColor(hex: "#EDEAFA") -style.listItemTitleFont = UIFont(name: "TimesNewRomanPS-Regular", size: 16) -style.titleFont = UIFont(name: "TimesNewRomanPS-Bold", size: 12) -style.searchBarPlaceholderTextFont = UIFont(name: "TimesNewRomanPS-Regular", size: 12) - +style.listItemTitleFont = UIFont(name: "Helvetica", size: 16) +style.titleFont = UIFont(name: "Helvetica-Bold", size: 12) +style.searchBarPlaceholderTextFont = UIFont(name: "Helvetica", size: 12) +style.searchBarBackgroundColor = .white +style.searchBarTextColor = UIColor(hex: "#212121") + let searchVC = CometChatSearch() searchVC.style = style -self?.navigationController?.pushViewController(searchVC, animated: true) - - -// global level styling + +// Or global styling CometChatSearch.style.backgroundColor = UIColor(hex: "#EDEAFA") CometChatSearch.style.listItemBackground = UIColor(hex: "#EDEAFA") -CometChatSearch.style.listItemTitleFont = UIFont(name: "TimesNewRomanPS-Regular", size: 16) -CometChatSearch.style.titleFont = UIFont(name: "TimesNewRomanPS-Bold", size: 12) -CometChatSearch.style.searchBarPlaceholderTextFont = UIFont(name: "TimesNewRomanPS-Regular", size: 12) ``` - -*** +--- -## Base Component +### AI Assistant Chat History -### Avatar + + +```swift lines +import CometChatUIKitSwift + +// Date separator style +let dateStyle = CometChatDateStyle() +dateStyle.textColor = UIColor(hex: "#8E8E93") +dateStyle.textFont = UIFont.systemFont(ofSize: 12) + +// Apply styles +CometChatAIAssistantChatHistory.style.backgroundColor = UIColor(hex: "#FFF9F2") +CometChatAIAssistantChatHistory.style.headerBackgroundColor = UIColor(hex: "#FFF9F2") +CometChatAIAssistantChatHistory.style.headerTitleTextColor = UIColor(hex: "#141414") +CometChatAIAssistantChatHistory.style.headerTitleTextFont = UIFont.boldSystemFont(ofSize: 18) +CometChatAIAssistantChatHistory.style.newChatIconColor = UIColor(hex: "#F76808") +CometChatAIAssistantChatHistory.style.itemTextColor = UIColor(hex: "#141414") +CometChatAIAssistantChatHistory.style.itemTextFont = UIFont.systemFont(ofSize: 14) +CometChatAIAssistantChatHistory.style.dateSeparatorStyle = dateStyle +``` + + -The `CometChatAvatar` Component is used across the UIKit to represent users, groups, or placeholders visually. This highly reusable component supports various shapes (circle or square), sizes, borders, and fallback icons, allowing complete design consistency for profile or group images. +--- -You can check out the list of styling properties offered by [CometChatAvatar](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Avatar/AvatarStyle.swift) +## Base Component Styles -### Status indicator +### Avatar -The `CometChatStatusIndicator` visually represents user presence (online, offline, or custom states). It can be styled for different shapes, sizes, and colors to reflect your app’s visual preferences while maintaining clarity in conveying status information. + + +```swift lines +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(hex: "#6200EE") +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 24) // Circle +avatarStyle.borderWidth = 2 +avatarStyle.borderColor = .white +avatarStyle.textFont = UIFont.systemFont(ofSize: 16, weight: .bold) +avatarStyle.textColor = .white +``` + + -You can check out the list of styling properties offered by [CometChatStatusIndicator](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Status%20Indicator/StatusIndicatorStyle.swift) +[View AvatarStyle →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Avatar/AvatarStyle.swift) ### Badge -The `CometChatBadge` Component displays notifications or counts, such as unread messages. It can be styled for background colors, border radius, text size, and colors, allowing you to create visually distinct indicators for different notifications. - -You can check out the list of styling properties offered by [CometChatBadge](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Badge/BadgeCountStyle.swift) - -### Date - -The `CometChatDate` Component formats and displays timestamps in conversation lists and message threads. It ensures time-related information is clear and consistent. Developers can customize its text appearance, alignment, and colors to fit various contexts. - -You can check out the list of styling properties offered by [CometChatDate](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Date/DateStyle.swift) - -### Receipts - -The `CometChatReceipts` Component indicates message delivery and read statuses using intuitive icons. These can be styled for icon size, tint, and alignment, ensuring they remain clear and consistent with your app’s UI. - -You can check out the list of styling properties offered by [CometChatReceipts](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Receipt/ReceiptStyle.swift) - -### Media Recorder - -The `CometChatMediaRecorder` Component facilitates the recording of audio and video messages. It supports full customization of its recording controls, including button sizes, shapes, and colors, making it an integral part of your media-rich chat experience. - -You can check out the list of styling properties offered by [CometChatMediaRecorder](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/MediaRecorder/MediaRecorderStyle.swift) - -### Sticker Keyboard - -The `CometChatStickerKeyboard` simplifies the integration of sticker-based messaging. Customize the background, grid layout, and sticker display styles to align with your chat experience. This component provides a visually rich and interactive way to enhance conversations. - -You can check out the list of styling properties offered by [CometChatStickerKeyboard](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Extensions/Sticker/StickerKeyboardStyle.swift) - -### Reaction list - -The `CometChatReactionList` Component provides a visual representation of emoji reactions on messages. It supports customization for reaction sizes, spacing, and colors, enabling you to build an engaging and personalized messaging environment. - -You can check out the list of styling properties offered by [CometChatReactionList](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/ReactionsHelper/ReactionList/ReactionListStyle.swift) - -### Conversation Starter - -The `CometChatConversationStarter` Component offers AI-based suggestions or reply options to initiate a chat. Developers can customize the background, text styles, and button appearances to ensure seamless integration with the app’s visual language. - -You can check out the list of styling properties offered by [CometChatConversationStarter](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/AI/AI%20Conversation%20Starter/AIConversationStarterStyle.swift) - -### Conversation Summary - -The `CometChatConversationSummary` Component highlights the essence of a conversation, including participant details, last message, and timestamp. Customize text sizes, colors, and spacing to create visually distinct summaries that improve readability and engagement. - -You can check out the list of styling properties offered by [CometChatConversationSummary](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/AI/AI%20Summarizer/AIConversationSummaryStyle.swift) - -### Smart Replies - -The `CometChatSmartReplies` Component provides AI-driven suggestions for quick message replies. Fully customizable for button styles, padding, and colors, this component enables a streamlined and modern chat experience for users. - -You can check out the list of styling properties offered by [CometChatSmartReplies](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/AI/AI%20Smart%20Replies/AISmartRepliesStyle.swift) - -### Message Information - -The `CometChatMessageInformation` Component displays metadata for messages, such as delivery timestamps, sender details, and read receipts. Customization options include text styles, colors, and alignment, making it adaptable to various app layouts. - -You can check out the list of styling properties offered by [CometChatMessageInformation](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20Information/MessageInformationStyle.swift) + + +```swift lines +let badgeStyle = BadgeStyle() +badgeStyle.backgroundColor = UIColor(hex: "#F44336") +badgeStyle.textColor = .white +badgeStyle.textFont = UIFont.systemFont(ofSize: 12, weight: .bold) +badgeStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 10) +badgeStyle.borderWidth = 0 +``` + + -### Message option sheet +[View BadgeStyle →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Badge/BadgeCountStyle.swift) -The `CometChatMessageOptionSheet` Component is a context menu for performing actions on messages, such as replying, forwarding, or deleting. Developers can style its background, icons, and text to match the app’s menu system. +### Status Indicator -You can check out the list of styling properties offered by [CometChatMessageOptionSheet](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Models/CometChatMessageOption.swift) + + +```swift lines +let statusStyle = StatusIndicatorStyle() +statusStyle.backgroundColor = .systemGreen // Online color +statusStyle.borderColor = .white +statusStyle.borderWidth = 2 +statusStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 6) // Circle +``` + + -### Attachment option sheet +[View StatusIndicatorStyle →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Status%20Indicator/StatusIndicatorStyle.swift) -The `CometChatAttachmentOptionSheet` Component provides a sleek interface for users to attach media, documents, or other files. It supports icon and text customizations to create a cohesive attachment experience. +### Receipt -You can check out the list of styling properties offered by [CometChatAttachmentOptionSheet](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Message%20Action%20Sheet/ActionSheetStyle.swift) + + +```swift lines +let receiptStyle = ReceiptStyle() +receiptStyle.sentIconTint = UIColor(hex: "#9E9E9E") +receiptStyle.deliveredIconTint = UIColor(hex: "#9E9E9E") +receiptStyle.readIconTint = UIColor(hex: "#6200EE") +receiptStyle.errorIconTint = UIColor(hex: "#F44336") +``` + + -### AIOption Sheet +[View ReceiptStyle →](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Views/Receipt/ReceiptStyle.swift) -The `CometChatAIOptionSheet` Component offers AI-powered action options, like generating replies or initiating voice-to-text commands. It allows developers to style icons, colors, and interaction elements for a polished and user-friendly interface. +--- -You can check out the list of styling properties offered by [CometChatAIOptionSheet](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/AI/AI%20Shared%20Views/AIOptionsStyle.swift) +## Complete Styling Example -### Mentions +Apply consistent branding across all components: -The `CometChatMentions` Component highlights referenced users or groups within messages. With customizable styles for text color and background, you can ensure mentions stand out clearly in chats while maintaining a cohesive visual theme. + + +```swift lines +import CometChatUIKitSwift +import UIKit + +class StyleManager { + + // Brand colors + static let primaryColor = UIColor(hex: "#6200EE") + static let secondaryColor = UIColor(hex: "#03DAC6") + static let backgroundColor = UIColor.systemBackground + static let surfaceColor = UIColor(hex: "#F5F5F5") + static let textPrimary = UIColor(hex: "#212121") + static let textSecondary = UIColor(hex: "#757575") + + static func applyGlobalStyles() { + // Theme colors + CometChatTheme.primaryColor = primaryColor + + // Avatar style (used everywhere) + let avatarStyle = AvatarStyle() + avatarStyle.backgroundColor = secondaryColor + avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) + + // Badge style + let badgeStyle = BadgeStyle() + badgeStyle.backgroundColor = primaryColor + badgeStyle.textColor = .white + + // Apply to Conversations + CometChatConversations.avatarStyle = avatarStyle + CometChatConversations.badgeStyle = badgeStyle + CometChatConversations.style.titleColor = textPrimary + CometChatConversations.style.titleFont = UIFont.systemFont(ofSize: 28, weight: .bold) + CometChatConversations.style.backgroundColor = backgroundColor + + // Apply to Users + CometChatUsers.avatarStyle = avatarStyle + CometChatUsers.style.titleColor = textPrimary + CometChatUsers.style.backgroundColor = backgroundColor + + // Apply to Groups + CometChatGroups.avatarStyle = avatarStyle + CometChatGroups.style.titleColor = textPrimary + CometChatGroups.style.backgroundColor = backgroundColor + + // Apply to Message Header + CometChatMessageHeader.avatarStyle = avatarStyle + CometChatMessageHeader.style.titleTextColor = textPrimary + CometChatMessageHeader.style.backgroundColor = backgroundColor + + // Apply to Message List + CometChatMessageList.style.backgroundColor = surfaceColor + CometChatMessageBubble.style.outgoing.backgroundColor = primaryColor + CometChatMessageBubble.style.outgoing.textBubbleStyle.textColor = .white + CometChatMessageBubble.style.incoming.backgroundColor = .white + CometChatMessageBubble.style.incoming.textBubbleStyle.textColor = textPrimary + + // Apply to Message Composer + CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = primaryColor + CometChatMessageComposer.style.attachmentImageTint = primaryColor + CometChatMessageComposer.style.backgroundColor = backgroundColor + + // Apply to Call Logs + CometChatCallLogs.avatarStyle = avatarStyle + CometChatCallLogs.style.titleColor = textPrimary + CometChatCallLogs.style.backgroundColor = backgroundColor + } +} + +// Apply in AppDelegate +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + StyleManager.applyGlobalStyles() + return true + } +} +``` + + -You can check out the list of styling properties offered by [CometChatMentions](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20Composer/TextFormatter/MentionTextStyle.swift) +--- + +## Related + + + + Theme colors + + + Complete theming + + + All components + + diff --git a/ui-kit/ios/components-overview.mdx b/ui-kit/ios/components-overview.mdx index 3888e4b00..7c7e5d6c7 100644 --- a/ui-kit/ios/components-overview.mdx +++ b/ui-kit/ios/components-overview.mdx @@ -1,47 +1,407 @@ --- -title: "Overview" +title: "Components Overview" +sidebarTitle: "Overview" +description: "Understanding CometChat iOS UI Kit components - types, actions, events, and customization" --- -CometChat's **UI Kit** is a set of pre-built UI components that allows you to easily craft an in-app chat with all the essential messaging features. + +```json +{ + "platform": "iOS UI Kit", + "package": "CometChatUIKitSwift", + "version": "5.0.0", + "componentTypes": { + "base": "Simple UI elements with no business logic", + "components": "UI elements with built-in business logic", + "composite": "Multiple components combined into complete features" + }, + "baseComponents": [ + {"name": "CometChatAvatar", "purpose": "User/group profile images"}, + {"name": "CometChatBadge", "purpose": "Notification counts"}, + {"name": "CometChatStatusIndicator", "purpose": "Online/offline status"}, + {"name": "CometChatDate", "purpose": "Formatted timestamps"}, + {"name": "CometChatReceipt", "purpose": "Message delivery status"} + ], + "components": [ + {"name": "CometChatUsers", "purpose": "List of users"}, + {"name": "CometChatGroups", "purpose": "List of groups"}, + {"name": "CometChatConversations", "purpose": "Recent chats list"}, + {"name": "CometChatMessageList", "purpose": "Chat messages"}, + {"name": "CometChatMessageComposer", "purpose": "Message input"}, + {"name": "CometChatMessageHeader", "purpose": "Chat header"}, + {"name": "CometChatCallLogs", "purpose": "Call history"} + ], + "compositeComponents": [ + {"name": "CometChatMessages", "contains": ["MessageHeader", "MessageList", "MessageComposer"]}, + {"name": "CometChatUsersWithMessages", "contains": ["Users", "Messages"]}, + {"name": "CometChatGroupsWithMessages", "contains": ["Groups", "Messages"]}, + {"name": "CometChatConversationsWithMessages", "contains": ["Conversations", "Messages"]} + ] +} +``` + -## Type of Components +## Overview -UI components based on the behaviour and functionality can be categorized into three types: Base Components, Components, and Composite Components. +CometChat UI Kit provides pre-built components that you can use to quickly build a chat experience. Components are organized into three types based on complexity. + +--- + +## Component Types ### Base Components -Base Components form the building blocks of your app's user interface (UI). They focus solely on presenting visual elements based on input data, without handling any business logic. These components provide the foundational appearance and behavior for your UI. +Simple UI elements with no business logic. They display data you pass to them. + +| Component | Purpose | +|-----------|---------| +| `CometChatAvatar` | User/group profile images | +| `CometChatBadge` | Notification counts | +| `CometChatStatusIndicator` | Online/offline status | +| `CometChatDate` | Formatted timestamps | +| `CometChatReceipt` | Message delivery status | + + + +```swift lines +import CometChatUIKitSwift + +// Avatar - displays user image +let avatar = CometChatAvatar() +avatar.setAvatar(avatarUrl: user.avatar, with: user.name) + +// Badge - shows unread count +let badge = CometChatBadge() +badge.set(count: 5) + +// Status indicator - shows online status +let status = CometChatStatusIndicator() +status.set(status: .online) +``` + + + +--- ### Components -Components build upon Base Components by incorporating business logic. They not only render UI elements but also manage data loading, execute specific actions, and respond to events. This combination of visual presentation and functional capabilities makes Components essential for creating dynamic and interactive UIs. +UI elements with built-in business logic. They fetch data, handle actions, and emit events. + +| Component | Purpose | +|-----------|---------| +| `CometChatUsers` | List of users | +| `CometChatGroups` | List of groups | +| `CometChatConversations` | Recent chats list | +| `CometChatMessageList` | Chat messages | +| `CometChatMessageComposer` | Message input | +| `CometChatMessageHeader` | Chat header | +| `CometChatCallLogs` | Call history | + + + +```swift lines +import CometChatUIKitSwift + +// Users list - fetches and displays users automatically +let users = CometChatUsers() +users.set(onItemClick: { user, indexPath in + print("Selected: \(user.name ?? "")") +}) + +// Conversations - shows recent chats +let conversations = CometChatConversations() +conversations.set(onItemClick: { conversation, indexPath in + // Open chat +}) + +// Message list - displays messages for a user/group +let messageList = CometChatMessageList() +messageList.set(user: user) +``` + + + +--- ### Composite Components -Composite Components are advanced UI elements that combine multiple Components or other Composite Components to achieve complex functionality. By layering components together, Composite Components offer a sophisticated and flexible approach to designing UIs. They enable diverse functionalities and interactions, making them versatile tools for creating rich user experiences. +Combine multiple components into complete features. + +| Component | Contains | +|-----------|----------| +| `CometChatMessages` | MessageHeader + MessageList + MessageComposer | +| `CometChatUsersWithMessages` | Users + Messages | +| `CometChatGroupsWithMessages` | Groups + Messages | +| `CometChatConversationsWithMessages` | Conversations + Messages | + + + +```swift lines +import CometChatUIKitSwift + +// Complete chat experience in one component +let conversationsWithMessages = CometChatConversationsWithMessages() +navigationController?.pushViewController(conversationsWithMessages, animated: true) + +// Or just the messages view +let messages = CometChatMessages() +messages.user = user // or messages.group = group +navigationController?.pushViewController(messages, animated: true) +``` + + + +--- ## Actions -Actions direct the operational behavior of a component. They are split into two categories: Predefined Actions and User-Defined Actions. +Actions define how components respond to user interactions. ### Predefined Actions -These are actions that are inherently programmed into a UI component. They are ingrained in the component itself by default, and they execute automatically in response to user interaction,without needing any additional user input. +Built-in behaviors that work automatically: + + + +```swift lines +// CometChatConversations has predefined actions: +// - Tap conversation → Opens messages +// - Long press → Shows options +// - Swipe → Delete conversation + +let conversations = CometChatConversations() +// These work automatically! +``` + + + +### Custom Actions + +Override default behavior with your own logic: + + + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let conversations = CometChatConversations() + +// Override tap action +conversations.set(onItemClick: { conversation, indexPath in + // Your custom logic + print("Tapped: \(conversation.conversationWith?.name ?? "")") + + // Navigate to custom screen instead of default + let customChatVC = MyChatViewController() + customChatVC.conversation = conversation + self.navigationController?.pushViewController(customChatVC, animated: true) +}) -### User-Defined Actions +// Override long press +conversations.set(onItemLongClick: { conversation, indexPath in + // Show custom options + self.showCustomOptions(for: conversation) +}) -These are actions that must be explicitly specified by the user. They are not innately part of the component like predefined actions. Instead, they must be developed based on the unique needs of the user or the application. User-defined actions provide adaptability and allow for the creation of custom behaviors that align with the individual needs of the application. +// Handle errors +conversations.set(onError: { error in + print("Error: \(error.localizedDescription)") +}) -To customize the behavior of a component, actions must be overridden by the user. This provides the user with control over how the component responds to specific events or interactions. +// Handle empty state +conversations.set(onEmpty: { + print("No conversations") +}) +``` + + -Both Components and Composite Components expose actions to the user, which means that users can interact with these types of components through predefined or user-defined actions. On the other hand, Base Components do not expose actions to the user as they are the foundational building blocks mainly responsible for rendering the user interface and do not carry any business logic or actions. +--- ## Events -Events allow for a decoupled, flexible architecture where different parts of the application can interact without having to directly reference each other. This makes it easier to create complex, interactive experiences, as well as to extend and customize the functionality provided by the CometChat UI Kit. +Events allow components to communicate without direct references. Subscribe to events from anywhere in your app. + +### Available Events + +| Event | Triggered When | +|-------|----------------| +| `ccMessageSent` | Message is sent | +| `ccMessageEdited` | Message is edited | +| `ccMessageDeleted` | Message is deleted | +| `ccMessageRead` | Message is read | +| `ccUserBlocked` | User is blocked | +| `ccUserUnblocked` | User is unblocked | +| `ccGroupCreated` | Group is created | +| `ccGroupDeleted` | Group is deleted | +| `ccGroupMemberAdded` | Member added to group | +| `ccGroupMemberRemoved` | Member removed from group | + +### Subscribe to Events -Both Components and Composite Components have the ability to emit events. These events are dispatched in response to certain changes or user interactions within the component. By emitting events, these components allow other parts of the application to react to changes or interactions, thus enabling dynamic and interactive behavior within the application. + + +```swift lines +import CometChatUIKitSwift +import Combine + +class ChatManager { + + private var cancellables = Set() + + func subscribeToEvents() { + // Message sent event + CometChatMessageEvents.ccMessageSent + .sink { message in + print("Message sent: \(message.text ?? "")") + // Update UI, analytics, etc. + } + .store(in: &cancellables) + + // Message deleted event + CometChatMessageEvents.ccMessageDeleted + .sink { message in + print("Message deleted: \(message.id)") + } + .store(in: &cancellables) + + // User blocked event + CometChatUserEvents.ccUserBlocked + .sink { user in + print("Blocked: \(user.name ?? "")") + } + .store(in: &cancellables) + + // Group member added + CometChatGroupEvents.ccGroupMemberAdded + .sink { (action, addedBy, addedUser, group) in + print("\(addedUser.name ?? "") added to \(group.name ?? "")") + } + .store(in: &cancellables) + } + + func unsubscribe() { + cancellables.removeAll() + } +} +``` + + + +--- ## Configurations -Configurations offer the ability to customize the properties of each individual component within a Composite Component. If a Composite Component includes multiple components, each of these components will have its own set of properties that can be configured. This means multiple sets of configurations are available, one for each constituent component. This allows for fine-tuned customization of the Composite Component, enabling you to tailor its behavior and appearance to match specific requirements in a granular manner. +Customize nested components within composite components: + + + +```swift lines +import CometChatUIKitSwift + +// CometChatMessages contains: MessageHeader, MessageList, MessageComposer +// You can configure each one: + +let messages = CometChatMessages() +messages.user = user + +// Configure MessageHeader +let headerConfig = MessageHeaderConfiguration() +headerConfig.hideBackButton = false +headerConfig.set(subtitleView: { user, group in + let label = UILabel() + label.text = user?.status == .online ? "Online" : "Offline" + label.textColor = user?.status == .online ? .systemGreen : .gray + return label +}) +messages.set(messageHeaderConfiguration: headerConfig) + +// Configure MessageList +let listConfig = MessageListConfiguration() +listConfig.set(emptyStateText: "No messages yet") +listConfig.set(errorStateText: "Failed to load messages") +messages.set(messageListConfiguration: listConfig) + +// Configure MessageComposer +let composerConfig = MessageComposerConfiguration() +composerConfig.set(placeholderText: "Type a message...") +composerConfig.hideLiveReaction = true +messages.set(messageComposerConfiguration: composerConfig) +``` + + + +--- + +## Component Hierarchy + +``` +CometChatConversationsWithMessages +├── CometChatConversations +│ ├── CometChatListItem +│ │ ├── CometChatAvatar +│ │ ├── CometChatBadge +│ │ ├── CometChatStatusIndicator +│ │ └── CometChatDate +│ └── CometChatListBase +└── CometChatMessages + ├── CometChatMessageHeader + │ ├── CometChatAvatar + │ └── CometChatStatusIndicator + ├── CometChatMessageList + │ ├── CometChatMessageBubble + │ ├── CometChatReceipt + │ └── CometChatDate + └── CometChatMessageComposer + ├── CometChatMediaRecorder + └── CometChatStickerKeyboard +``` + +--- + +## Quick Reference + +### When to Use Each Type + +| Need | Use | +|------|-----| +| Display user avatar | `CometChatAvatar` (Base) | +| Show list of users | `CometChatUsers` (Component) | +| Complete chat with user selection | `CometChatUsersWithMessages` (Composite) | +| Custom chat UI | Individual Components | +| Quick integration | Composite Components | + +### Common Patterns + + + +```swift lines +// Pattern 1: Quick integration with composite +let chat = CometChatConversationsWithMessages() +navigationController?.pushViewController(chat, animated: true) + +// Pattern 2: Custom flow with components +let users = CometChatUsers() +users.set(onItemClick: { user, _ in + let messages = CometChatMessages() + messages.user = user + self.navigationController?.pushViewController(messages, animated: true) +}) + +// Pattern 3: Fully custom with base components +let customCell = UITableViewCell() +let avatar = CometChatAvatar() +avatar.setAvatar(avatarUrl: user.avatar, with: user.name) +customCell.contentView.addSubview(avatar) +``` + + + +--- + +## Related + +- [Component Styling](/ui-kit/ios/component-styling) - Customize appearance +- [Color Resources](/ui-kit/ios/color-resources) - Theme colors +- [Getting Started](/ui-kit/ios/getting-started) - Initial setup diff --git a/ui-kit/ios/conversations.mdx b/ui-kit/ios/conversations.mdx index b8b804408..dc9878723 100644 --- a/ui-kit/ios/conversations.mdx +++ b/ui-kit/ios/conversations.mdx @@ -1,1186 +1,1594 @@ --- title: "Conversations" +description: "Display and manage all chat conversations for the logged-in user" --- -## Overview - -The Conversations is a [Component](/ui-kit/ios/components-overview#components), That shows all conversations related to the currently logged-in user, +The `CometChatConversations` component displays a list of all conversations (one-on-one and group chats) for the currently logged-in user. It shows the last message, unread count, typing indicators, and user presence in real-time. - + CometChatConversations showing a list of recent conversations with user avatars, last message previews, timestamps, and unread message badges -## Usage + +```json +{ + "component": "CometChatConversations", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays a list of all conversations for the logged-in user with real-time updates for messages, typing indicators, and presence.", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onItemClick", + "type": "(Conversation, IndexPath) -> Void" + }, + "props": { + "data": { + "conversationRequestBuilder": { + "type": "ConversationRequest.ConversationRequestBuilder?", + "default": "nil", + "note": "Custom request builder for filtering conversations" + } + }, + "callbacks": { + "onItemClick": "(Conversation, IndexPath) -> Void", + "onItemLongClick": "(Conversation, IndexPath) -> Void", + "onBack": "() -> Void", + "onSelection": "([Conversation]) -> Void", + "onError": "(CometChatException) -> Void", + "onEmpty": "() -> Void", + "onLoad": "([Conversation]) -> Void" + }, + "visibility": { + "hideSearch": { "type": "Bool", "default": false }, + "hideReceipts": { "type": "Bool", "default": false }, + "hideUserStatus": { "type": "Bool", "default": false }, + "hideGroupType": { "type": "Bool", "default": false }, + "hideDeleteConversationOption": { "type": "Bool", "default": false }, + "hideNavigationBar": { "type": "Bool", "default": false }, + "hideBackButton": { "type": "Bool", "default": false } + }, + "sound": { + "disableSoundForMessages": { "type": "Bool", "default": false }, + "customSoundForMessages": { "type": "URL?", "default": "nil" } + }, + "selection": { + "selectionMode": { "type": "SelectionMode", "default": ".none" } + }, + "viewSlots": { + "listItemView": "(Conversation) -> UIView", + "leadingView": "(Conversation) -> UIView", + "titleView": "(Conversation) -> UIView", + "subtitleView": "(Conversation) -> UIView", + "tailView": "(Conversation) -> UIView", + "emptyStateView": "() -> UIView", + "errorStateView": "() -> UIView", + "loadingStateView": "() -> UIView" + }, + "formatting": { + "datePattern": "(Conversation) -> String", + "textFormatters": "[CometChatTextFormatter]" + } + }, + "events": [ + { + "name": "ccConversationDelete", + "payload": "Conversation", + "description": "Fires when a conversation is deleted" + } + ], + "sdkListeners": [ + "onMessageReceived", + "onMessageEdited", + "onMessageDeleted", + "onTypingStarted", + "onTypingEnded", + "onUserOnline", + "onUserOffline", + "onGroupMemberJoined", + "onGroupMemberLeft" + ], + "compositionExample": { + "description": "Conversations list navigating to Messages", + "components": ["CometChatConversations", "CometChatMessages"], + "flow": "User taps conversation → onItemClick fires → Navigate to CometChatMessages with user/group" + }, + "types": { + "Conversation": { + "conversationId": "String?", + "conversationType": "ConversationType", + "conversationWith": "AppEntity?", + "lastMessage": "BaseMessage?", + "unreadMessageCount": "Int" + }, + "ConversationType": { + "user": "One-on-one conversation", + "group": "Group conversation", + "both": "All conversation types" + } + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatConversations` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | -### Integration +--- -As CometChatConversations is a custom view controller, it can be initiated either by tapping a button or through the trigger of any event. It offers multiple parameters and methods for tailoring its user interface. +## Where It Fits -```ruby swift -let cometChatConversations = CometChatConversations() -self.navigationController.pushViewController(cometChatConversations, animated: true) +`CometChatConversations` serves as the main entry point for chat functionality. It displays all conversations and navigates to `CometChatMessages` when a conversation is selected. + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatListViewController: UIViewController { + + private var conversationsController: CometChatConversations! + + override func viewDidLoad() { + super.viewDidLoad() + setupConversations() + } + + private func setupConversations() { + conversationsController = CometChatConversations() + + // Handle conversation selection - navigate to messages + conversationsController.set(onItemClick: { [weak self] conversation, indexPath in + self?.openMessages(for: conversation) + }) + + navigationController?.pushViewController(conversationsController, animated: true) + } + + private func openMessages(for conversation: Conversation) { + let messagesVC = CometChatMessages() + + if let user = conversation.conversationWith as? User { + messagesVC.set(user: user) + } else if let group = conversation.conversationWith as? Group { + messagesVC.set(group: group) + } + + navigationController?.pushViewController(messagesVC, animated: true) + } +} ``` -* Integration (With Custom Request Builder) + + CometChatConversations showing integration flow with conversation list navigating to messages screen + -During the initialization of **CometChatConversations,** users can provide this custom request builder. +--- -```ruby swift -// You can create ConversationRequestBuilder as per your requirement -let conversationRequestBuilder = ConversationRequest.ConversationRequestBuilder(limit: 20).set(conversationType: .both) +## Minimal Render -let cometChatConversations = CometChatConversations(conversationRequestBuilder: conversationRequestBuilder) -self.navigationController.pushViewController(cometChatConversations, animated: true) -``` +```swift lines +import CometChatUIKitSwift - +let conversations = CometChatConversations() +navigationController?.pushViewController(conversations, animated: true) +``` -If a navigation controller is already in use, opt for the `pushViewController` method instead of presenting the view controller. + + CometChatConversations showing minimal render with default configuration displaying conversation list + - +--- -### Actions +## Filtering -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. +Use `ConversationRequest.ConversationRequestBuilder` to filter which conversations appear in the list. The builder pattern allows chaining multiple filter conditions. -1. ##### set(onItemClick:) +```swift lines +import CometChatUIKitSwift +import CometChatSDK -`set(OnItemClick:)` is triggered when you click on a ListItem of the Conversations component. This `set(OnItemClick:)` method proves beneficial when a user intends to customize the on-click behavior in CometChatConversations. +// Create a custom request builder +let requestBuilder = ConversationRequest.ConversationRequestBuilder(limit: 30) + .set(conversationType: .both) - - -```swift -// syntax for set(onItemClick: @escaping ((_ conversation: Conversation, _ indexPath: IndexPath) -> Void)) -cometChatConversations.set(onItemClick: { conversation, indexPath in - // Override on item click -}) +let conversations = CometChatConversations(conversationRequestBuilder: requestBuilder) ``` - +### Filter Recipes - +| Recipe | Code | +|--------|------| +| Show only one-on-one chats | `.set(conversationType: .user)` | +| Show only group chats | `.set(conversationType: .group)` | +| Filter by tags | `.withTags(true).set(tags: ["support", "sales"])` | +| Limit results | `ConversationRequestBuilder(limit: 20)` | +| Include user/group tags | `.withUserAndGroupTags(true)` | -*** +--- -2. ##### set(OnItemLongClick:) +## Actions and Events -`set(OnItemLongClick:)` is triggered when you long press on a ListItem of the Conversations component. This `set(OnItemLongClick:)` method proves beneficial when a user intends to additional functionality on long press on list item in CometChatConversations. +### Callback Props - - -```swift -// syntax for set(onItemLongClick: @escaping ((_ conversation: Conversation, _ indexPath: IndexPath) -> Void)) -cometChatConversations.set(onItemLongClick: { conversation, indexPath in - // Override on item click +#### onItemClick + +Fires when a user taps on a conversation. Use this to navigate to the messages screen. + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let conversations = CometChatConversations() + +conversations.set(onItemClick: { [weak self] conversation, indexPath in + guard let self = self else { return } + + let messagesVC = CometChatMessages() + + if let user = conversation.conversationWith as? User { + messagesVC.set(user: user) + } else if let group = conversation.conversationWith as? Group { + messagesVC.set(group: group) + } + + self.navigationController?.pushViewController(messagesVC, animated: true) }) ``` - - - +#### onItemLongClick -*** +Fires when a user long-presses on a conversation. Use this to show additional options like delete or mute. -##### 3. set(onBack:) +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This `set(onBack:)` method becomes valuable when a user needs to override the action triggered upon pressing the back button in CometChatConversations. +let conversations = CometChatConversations() - - -```swift -// syntax for set(onBack: @escaping () -> Void) -cometChatConversations.set(onBack: { - // Override on back +conversations.set(onItemLongClick: { [weak self] conversation, indexPath in + guard let self = self else { return } + + let alert = UIAlertController(title: "Options", message: nil, preferredStyle: .actionSheet) + + alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { [weak self] _ in + self?.deleteConversation(conversation) + }) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + self.present(alert, animated: true) }) + +// Helper method to delete conversation using SDK +private func deleteConversation(_ conversation: Conversation) { + CometChat.deleteConversation( + conversationWith: conversation.conversationWith?.uid ?? "", + conversationType: conversation.conversationType + ) { success in + print("Conversation deleted successfully") + } onError: { error in + print("Delete failed: \(error?.errorDescription ?? "")") + } +} ``` - +#### onBack - +Fires when the back button is pressed. Use this for custom navigation handling. -*** +```swift lines +import CometChatUIKitSwift -##### 4. set(onSelection:) +let conversations = CometChatConversations() -The `set(onSelection:)` only gets trigger when selection mode is set to multiple of single. And this gets trigger on every selection, and returns the list of selected conversations. +conversations.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) +}) +``` - - -```swift +#### onSelection -conversations.set(onSelection: { conversations in - //Handle action +Fires when conversations are selected in selection mode. Returns the list of selected conversations. + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let conversations = CometChatConversations() +conversations.selectionMode = .multiple + +conversations.set(onSelection: { [weak self] selectedConversations in + print("Selected \(selectedConversations.count) conversations") }) ``` - - - +#### onError -*** +Fires when an error occurs while loading conversations. -##### 5. set(onError:) +```swift lines +import CometChatUIKitSwift -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatConversations. +let conversations = CometChatConversations() - - -```swift -// syntax for set(onError: @escaping ((_ error: CometChatException) -> Void)) -cometChatConversations.set(onError: { error in - // Override on error +conversations.set(onError: { error in + print("Error loading conversations: \(error.errorDescription)") }) ``` - +#### onEmpty - +Fires when the conversation list is empty. -*** - -##### 6. set(onEmpty:) +```swift lines +import CometChatUIKitSwift -This `set(onEmpty:)` method is triggered when the conversations list is empty in CometChatConversations. +let conversations = CometChatConversations() - - -```swift -// syntax for set(onEmpty: @escaping () -> Void) -cometChatConversations.set(onEmpty: { - // Handle empty state +conversations.set(onEmpty: { + print("No conversations found") }) ``` - - - +#### onLoad -*** +Fires when conversations are successfully loaded. -##### 7. setOnLoad +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This set(onLoad:) gets triggered when a conversation list is fully fetched and going to displayed on the screen, this return the list of conversations to get displayed on the screen. +let conversations = CometChatConversations() - - -```swift -// syntax for set(onLoad: @escaping ((_ conversations: [Conversation]) -> Void)) -cometChatConversations.set(onLoad: { conversations in - // Handle loaded conversations +conversations.set(onLoad: { conversations in + print("Loaded \(conversations.count) conversations") }) ``` - +### Actions Reference - +| Method | Description | Example | +|--------|-------------|---------| +| `set(onItemClick:)` | Triggered when a conversation is tapped | Navigate to messages | +| `set(onItemLongClick:)` | Triggered on long press | Show options menu | +| `set(onBack:)` | Triggered when back button is pressed | Custom navigation | +| `set(onSelection:)` | Triggered in selection mode | Multi-select conversations | +| `set(onError:)` | Triggered when an error occurs | Show error alert | +| `set(onEmpty:)` | Triggered when list is empty | Show empty state | +| `set(onLoad:)` | Triggered when conversations load | Analytics tracking | -*** +### Global UI Events -### Filters +| Event | Fires when | Payload | +|-------|------------|---------| +| `ccConversationDelete` | A conversation is deleted | `Conversation` | -You can set `ConversationsRequestBuilder` in the Conversations Component to filter the conversation list. You can modify the builder as per your specific requirements with multiple options available to know more refer to [ConversationRequestBuilder](/sdk/ios/retrieve-conversations). +```swift lines +import CometChatUIKitSwift +import CometChatSDK -You can set filters using the following parameters. +class MyViewController: UIViewController, CometChatConversationEventListener { + + override func viewDidLoad() { + super.viewDidLoad() + CometChatConversationEvents.addListener("my-listener", self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatConversationEvents.removeListener("my-listener") + } + + func ccConversationDelete(conversation: Conversation) { + print("Conversation deleted: \(conversation.conversationId ?? "")") + } +} +``` -1. **Conversation Type:** Filters on type of Conversation, `User` or `Groups` -2. **Limit:** Number of conversations fetched in a single request. -3. **WithTags:** Filter on fetching conversations containing tags -4. **Tags:** Filters on specific `Tag` -5. **UserTags:** Filters on specific User `Tag` -6. **GroupTags:** Filters on specific Group `Tag` +### SDK Events (Real-Time, Automatic) - - -```swift -// You can create ConversationRequestBuilder as per your requirement -let conversationRequestBuilder = ConversationRequest.ConversationRequestBuilder(limit: 20).set(conversationType: .both) +| SDK Listener | Internal behavior | +|--------------|-------------------| +| `onMessageReceived` | Updates last message and moves conversation to top | +| `onMessageEdited` | Updates last message preview if edited message is latest | +| `onMessageDeleted` | Updates last message preview if deleted message was latest | +| `onTypingStarted` | Shows typing indicator for the conversation | +| `onTypingEnded` | Hides typing indicator for the conversation | +| `onUserOnline` | Updates online status indicator for user conversations | +| `onUserOffline` | Updates offline status indicator for user conversations | +| `onGroupMemberJoined` | Updates group member count | +| `onGroupMemberLeft` | Updates group member count | -let cometChatConversations = CometChatConversations(conversationRequestBuilder: conversationRequestBuilder) -self.navigationController.pushViewController(cometChatConversations, animated: true) -``` +--- - +## Custom View Slots - +| Slot | Signature | Replaces | +|------|-----------|----------| +| `listItemView` | `(Conversation) -> UIView` | Entire conversation row | +| `leadingView` | `(Conversation) -> UIView` | Avatar / left section | +| `titleView` | `(Conversation) -> UIView` | Name / title text | +| `subtitleView` | `(Conversation) -> UIView` | Last message preview | +| `tailView` | `(Conversation) -> UIView` | Right side (time, badge) | +| `emptyStateView` | `() -> UIView` | Empty state display | +| `errorStateView` | `() -> UIView` | Error state display | +| `loadingStateView` | `() -> UIView` | Loading state display | - +### listItemView -If a navigation controller is already in use, opt for the `pushViewController` method instead of presenting the view controller. +Replace the entire conversation row with a custom design. - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -*** +let conversations = CometChatConversations() -### Events +conversations.set(listItemView: { conversation in + let customView = CustomConversationCell() + customView.configure(with: conversation) + return customView +}) +``` -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. +```swift lines +// CustomConversationCell.swift +class CustomConversationCell: UIView { + + private let avatarView = CometChatAvatar(image: UIImage()) + private let nameLabel = UILabel() + private let messageLabel = UILabel() + private let timeLabel = UILabel() + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + nameLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) + messageLabel.font = UIFont.systemFont(ofSize: 14) + messageLabel.textColor = UIColor.secondaryLabel + timeLabel.font = UIFont.systemFont(ofSize: 12) + timeLabel.textColor = UIColor.tertiaryLabel + + // Add subviews and constraints... + } + + func configure(with conversation: Conversation) { + if let user = conversation.conversationWith as? User { + nameLabel.text = user.name + avatarView.setAvatar(avatarUrl: user.avatar, with: user.name ?? "") + } else if let group = conversation.conversationWith as? Group { + nameLabel.text = group.name + avatarView.setAvatar(avatarUrl: group.icon, with: group.name ?? "") + } + + if let textMessage = conversation.lastMessage as? TextMessage { + messageLabel.text = textMessage.text + } + } +} +``` -##### 1. ConversationDeleted +### subtitleView -This event will be emitted when the user deletes a conversation +Customize just the subtitle area below the conversation name. - - -```swift Add Listener -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - public override func viewDidLoad() { - super.viewDidLoad() +let conversations = CometChatConversations() - // Subscribing for the listener to listen events from conversation module - CometChatConversationEvents.addListener("UNIQUE_ID", self as CometChatConversationEventListener) +conversations.set(subtitleView: { conversation in + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 13) + label.textColor = UIColor.secondaryLabel + + if let textMessage = conversation.lastMessage as? TextMessage { + label.text = textMessage.text + } else if conversation.lastMessage is MediaMessage { + label.text = "📷 Photo" + } else { + label.text = "No messages yet" } + + return label +}) +``` -} +### leadingView - // Listener events from conversation module -extension ViewController: CometChatConversationEventListener { +Customize the avatar / left section of the conversation row. - func ccConversationDelete(conversation: Conversation) { - // Do Stuff - } +| | | +|---|---| +| Signature | `(Conversation) -> UIView` | +| Replaces | Avatar / left section | -} -``` +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -```ruby Remove Listener -public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from conversation module - CometChatConversationEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") -} +let conversations = CometChatConversations() + +conversations.set(leadingView: { conversation in + let containerView = UIView() + containerView.translatesAutoresizingMaskIntoConstraints = false + + let avatarView = CometChatAvatar(image: UIImage()) + avatarView.translatesAutoresizingMaskIntoConstraints = false + + if let user = conversation.conversationWith as? User { + avatarView.setAvatar(avatarUrl: user.avatar, with: user.name ?? "") + } else if let group = conversation.conversationWith as? Group { + avatarView.setAvatar(avatarUrl: group.icon, with: group.name ?? "") + } + + containerView.addSubview(avatarView) + + // Add online indicator + let statusIndicator = UIView() + statusIndicator.backgroundColor = UIColor.systemGreen + statusIndicator.layer.cornerRadius = 6 + statusIndicator.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(statusIndicator) + + NSLayoutConstraint.activate([ + avatarView.widthAnchor.constraint(equalToConstant: 48), + avatarView.heightAnchor.constraint(equalToConstant: 48), + avatarView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor), + avatarView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor), + statusIndicator.widthAnchor.constraint(equalToConstant: 12), + statusIndicator.heightAnchor.constraint(equalToConstant: 12), + statusIndicator.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor), + statusIndicator.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor) + ]) + + return containerView +}) ``` - +{/* TODO: Add screenshot showing leadingView customization */} - +### titleView -## Customization +Customize the title area that displays the conversation name. -To align with your app's design specifications, you have the flexibility to customize the appearance of the conversation component. We offer accessible methods that empower you to tailor the experience and functionality to meet your unique requirements. +| | | +|---|---| +| Signature | `(Conversation) -> UIView` | +| Replaces | Name / title text area | -### Style +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +let conversations = CometChatConversations() -##### 1. Conversation Style +conversations.set(titleView: { conversation in + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 8 + stackView.alignment = .center + + // Name label + let nameLabel = UILabel() + nameLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) + nameLabel.textColor = UIColor.label + + if let user = conversation.conversationWith as? User { + nameLabel.text = user.name + } else if let group = conversation.conversationWith as? Group { + nameLabel.text = group.name + } + + stackView.addArrangedSubview(nameLabel) + + // Add verified badge for specific users + if let user = conversation.conversationWith as? User, + user.metadata?["verified"] as? Bool == true { + let badgeImage = UIImageView(image: UIImage(systemName: "checkmark.seal.fill")) + badgeImage.tintColor = UIColor.systemBlue + badgeImage.widthAnchor.constraint(equalToConstant: 16).isActive = true + badgeImage.heightAnchor.constraint(equalToConstant: 16).isActive = true + stackView.addArrangedSubview(badgeImage) + } + + return stackView +}) +``` -The CometChatConversation component allows developers to customize its appearance through the ConversationStyle class. This enables global-level or instance-specific styling. +{/* TODO: Add screenshot showing titleView customization */} -**Global level styling** +### tailView - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = 8 +Customize the right side of the conversation row (time, unread badge). Note: The setter method is `set(trailView:)`. -let customReceiptStyle = ReceiptStyle() -customReceiptStyle.backgroundColor = UIColor(hex: "#F76808") +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -var customBadgeStyle = BadgeStyle() -customBadgeStyle.backgroundColor = UIColor(hex: "#F76808") +let conversations = CometChatConversations() -CometChatConversation.style.backgroundColor = CometChatTheme.backgroundColor01 -CometChatConversation.style.avatarStyle = customAvatarStyle -CometChatConversation.style.receiptStyle = customReceiptStyle -CometChatConversation.style.badgeStyle = customBadgeStyle +conversations.set(trailView: { conversation in + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .trailing + stackView.spacing = 4 + + // Time label + let timeLabel = UILabel() + timeLabel.font = UIFont.systemFont(ofSize: 12) + timeLabel.textColor = UIColor.tertiaryLabel + + if let sentAt = conversation.lastMessage?.sentAt { + let date = Date(timeIntervalSince1970: TimeInterval(sentAt)) + let formatter = DateFormatter() + formatter.dateFormat = "h:mm a" + timeLabel.text = formatter.string(from: date) + } + + stackView.addArrangedSubview(timeLabel) + + // Unread badge + if conversation.unreadMessageCount > 0 { + let badge = UILabel() + badge.text = "\(conversation.unreadMessageCount)" + badge.font = UIFont.systemFont(ofSize: 12, weight: .bold) + badge.textColor = UIColor.white + badge.backgroundColor = UIColor.systemRed + badge.textAlignment = .center + badge.layer.cornerRadius = 10 + badge.clipsToBounds = true + badge.widthAnchor.constraint(greaterThanOrEqualToConstant: 20).isActive = true + badge.heightAnchor.constraint(equalToConstant: 20).isActive = true + stackView.addArrangedSubview(badge) + } + + return stackView +}) ``` - +{/* TODO: Add screenshot showing trailingView customization */} + +--- - +## Styling -**Instance level styling** +### Style Hierarchy - - -```swift -let conversationStyle = ConversationsStyle() -conversationStyle.backgroundColor = CometChatTheme.backgroundColor01 - -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = 8 +1. Global styles (`CometChatConversation.style`) apply to all instances +2. Instance styles override global for specific instances -let customReceiptStyle = ReceiptStyle() -customReceiptStyle.backgroundColor = UIColor(hex: "#F76808") +### Global Level Styling -let customBadgeStyle = BadgeStyle() -customBadgeStyle.backgroundColor = UIColor(hex: "#F76808") +```swift lines +import UIKit +import CometChatUIKitSwift -let customConversation = CometChatConversation() -customConversation.avatarStyle = customAvatarStyle -customConversation.receiptStyle = customReceiptStyle -customConversation.badgeStyle = customBadgeStyle -customConversation.style = conversationStyle +// Apply global styles that affect all CometChatConversations instances +CometChatConversation.style.backgroundColor = UIColor.systemBackground +CometChatConversation.style.titleFont = UIFont.systemFont(ofSize: 17, weight: .bold) +CometChatConversation.style.titleColor = UIColor.label +CometChatConversation.style.listItemTitleTextColor = UIColor.label +CometChatConversation.style.listItemSubTitleTextColor = UIColor.secondaryLabel + +// Custom avatar style +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor(red: 0.41, green: 0.32, blue: 0.84, alpha: 1.0) +avatarStyle.cornerRadius = 8 +CometChatConversation.style.avatarStyle = avatarStyle + +// Custom badge style for unread count +let badgeStyle = BadgeStyle() +badgeStyle.backgroundColor = UIColor.systemRed +badgeStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 10) +CometChatConversation.style.badgeStyle = badgeStyle ``` - +### Instance Level Styling - +```swift lines +import UIKit +import CometChatUIKitSwift + +// Create a custom style for a specific instance +var customStyle = ConversationsStyle() +customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +customStyle.titleColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0) +customStyle.listItemBackground = UIColor.white +customStyle.listItemCornerRadius = CometChatCornerStyle(cornerRadius: 12) + +let conversations = CometChatConversations() +conversations.style = customStyle +``` - + CometChatConversations with custom styling applied showing customized background, colors, and list item appearance -List of properties exposed by ConversationStyle - -| **Property** | **Description** | **Code** | -| ------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -| **Background Color** | Used to set the background color of the conversation screen. | `CometChatConversation.style.backgroundColor = UIColor.white` | -| **Background Drawable** | Used to set a background image for the conversation screen. | `CometChatConversation.style.backgroundDrawable = UIImage(named: "background")` | -| **Border Width** | Used to set the border width of the conversation UI. | `CometChatConversation.style.borderWidth = 2.0` | -| **Border Color** | Used to set the border color of the conversation UI. | `CometChatConversation.style.borderColor = UIColor.gray` | -| **Corner Radius** | Used to set the corner radius of the conversation UI. | `CometChatConversation.style.cornerRadius = 10.0` | -| **Back Icon Tint** | Used to set the tint color of the back icon in the conversation UI. | `CometChatConversation.style.backIconTint = UIColor.blue` | -| **Back Icon** | Used to set a custom back icon for the conversation UI. | `CometChatConversation.style.backIcon = UIImage(named: "customBackIcon")` | -| **Separator Color** | Used to set the color of separators in the conversation list. | `CometChatConversation.style.separatorColor = UIColor.lightGray` | -| **Separator Width** | Used to set the width of separators in the conversation list. | `CometChatConversation.style.separatorWidth = 1.0` | -| **Error Text Color** | Used to set the color of error messages in the conversation UI. | `CometChatConversation.style.errorTextColor = UIColor.red` | -| **Last Message Text Color** | Used to set the color of the last message text in the conversation list. | `CometChatConversation.style.lastMessageTextColor = UIColor.darkGray` | -| **Typing Indicator Color** | Used to set the color of the typing indicator in the conversation UI. | `CometChatConversation.style.typingIndicatorColor = UIColor.green` | -| **Title Appearance** | Used to customize the appearance of the conversation screen's title. | `CometChatConversation.style.titleAppearance = UIFont.boldSystemFont(ofSize: 18.0)` | -| **Last Message Appearance** | Used to customize the appearance of the last message text in the list. | `CometChatConversation.style.lastMessageAppearance = UIFont.italicSystemFont(ofSize: 14.0)` | -| **Thread Indicator Appearance** | Used to customize the appearance of thread indicators in the list. | `CometChatConversation.style.threadIndicatorTextAppearance = UIFont.systemFont(ofSize: 12.0)` | -| **Avatar Style** | Used to customize the appearance of avatars in the conversation list. | `CometChatConversation.style.avatarStyle = customAvatarStyle` | -| **Status Indicator Style** | Used to customize the style of status indicators for online/offline members. | `CometChatConversation.style.statusIndicatorStyle = customStatusIndicatorStyle` | -| **Date Style** | Used to customize the appearance of date labels in the conversation list. | `CometChatConversation.style.dateStyle = customDateStyle` | -| **Badge Style** | Used to customize the appearance of badges in the conversation list. | `CometChatConversation.style.badgeStyle = customBadgeStyle` | -| **List Item Style** | Used to customize the appearance of the list items in the conversation list. | `CometChatConversation.style.listItemStyle = customListItemStyle` | - -##### 2. Avatar Style - -To apply customized styles to the `Avatar` component in the `Conversations` Component, you can use the following code snippet. For more information, visit [Avatar Styles](/ui-kit/ios/component-styling#avatar). - -**Global level styling** - - - -```swift -CometChatAvatar.style.cornerRadius = CometChatCornerStyle(cornerRadius: 8) -CometChatAvatar.style.backgroundColor = UIColor(hex: "#F76808") -``` +### Key Style Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `backgroundColor` | `UIColor` | `CometChatTheme.backgroundColor01` | Background color of the list | +| `titleFont` | `UIFont?` | `CometChatTypography.setFont(size: 17, weight: .bold)` | Font for the navigation title | +| `titleColor` | `UIColor?` | `CometChatTheme.textColorPrimary` | Color for the navigation title | +| `listItemTitleTextColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Color for conversation names | +| `listItemTitleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Font for conversation names | +| `listItemSubTitleTextColor` | `UIColor` | `CometChatTheme.textColorSecondary` | Color for last message preview | +| `listItemSubTitleFont` | `UIFont` | `CometChatTypography.Body.regular` | Font for last message preview | +| `listItemBackground` | `UIColor` | `.clear` | Background color for list items | +| `listItemCornerRadius` | `CometChatCornerStyle` | `CometChatCornerStyle(cornerRadius: 0)` | Corner radius for list items | +| `borderWidth` | `CGFloat` | `0` | Border width for the component | +| `borderColor` | `UIColor` | `.clear` | Border color for the component | + +### Customization Matrix + +| What to change | Where | Property/API | Example | +|----------------|-------|--------------|---------| +| Background color | Style | `backgroundColor` | `UIColor.systemBackground` | +| Title appearance | Style | `titleFont`, `titleColor` | `UIFont.boldSystemFont(ofSize: 18)` | +| List item look | Style | `listItemBackground` | `UIColor(white: 0.95, alpha: 1.0)` | +| Unread badge | Style | `badgeStyle` | `BadgeStyle()` with custom colors | +| Avatar appearance | Style | `avatarStyle` | `AvatarStyle()` with custom radius | +| Hide search | Property | `hideSearch` | `conversations.hideSearch = true` | +| Hide receipts | Property | `hideReceipts` | `conversations.hideReceipts = true` | +| Custom row | View Slot | `set(listItemView:)` | See Custom View Slots section | - +--- + +## Methods - +### Swipe Action Methods -**Instance level styling** +#### set(options:) - - -```swift -var customAvatarStyle = AvatarStyle() -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) -customAvatarStyle.backgroundColor = UIColor(hex: "#F76808") +Sets custom swipe actions for conversation list items, replacing the default options. -let customAvatar = CometChatAvatar() -customAvatar.style = customAvatarStyle +```swift lines +@discardableResult +public func set(options: ((_ conversation: Conversation?) -> [CometChatConversationOption])?) -> Self ``` - +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((Conversation?) -> [CometChatConversationOption])?` | Closure that returns an array of swipe action options for a conversation | - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - - - +let conversations = CometChatConversations() + +conversations.set(options: { conversation in + var options = [CometChatConversationOption]() + + // Add delete option + let deleteOption = CometChatConversationOption( + id: "delete", + title: "Delete", + icon: UIImage(systemName: "trash"), + backgroundColor: .systemRed + ) { conv in + // Handle delete action + print("Delete conversation: \(conv?.conversationId ?? "")") + } + options.append(deleteOption) + + return options +}) +``` -##### 3. StatusIndicator Style +#### add(options:) -To apply customized styles to the Status Indicator component in the `Conversations` Component, you can use the following code snippet. For more information, visit [Indicator Styles](/ui-kit/ios/status-indicator). +Adds additional swipe actions to the existing default options. -**Global level styling** +```swift lines +@discardableResult +public func add(options: ((_ conversation: Conversation?) -> [CometChatConversationOption])?) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((Conversation?) -> [CometChatConversationOption])?` | Closure that returns additional swipe action options to append | + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +let conversations = CometChatConversations() - - -```swift -CometChatStatusIndicator.style.cornerRadius = CometChatCornerStyle(cornerRadius: 8) -CometChatStatusIndicator.style.backgroundColor = UIColor(hex: "#F76808") +conversations.add(options: { conversation in + var options = [CometChatConversationOption]() + + // Add mute option + let muteOption = CometChatConversationOption( + id: "mute", + title: "Mute", + icon: UIImage(systemName: "bell.slash"), + backgroundColor: .systemOrange + ) { conv in + print("Mute conversation: \(conv?.conversationId ?? "")") + } + options.append(muteOption) + + return options +}) ``` - +{/* TODO: Add screenshot showing swipe action options customization */} - +### Data Manipulation Methods -**Instance level styling** +#### insert(conversation:at:) - - -```swift -var customStatusIndicatorStyle = StatusIndicatorStyle() -customStatusIndicatorStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) -customStatusIndicatorStyle.backgroundColor = UIColor(hex: "#F76808") +Inserts a conversation at a specific index in the list. -CometChatStatusIndicator.style = customStatusIndicatorStyle +```swift lines +public func insert(conversation: Conversation, at index: Int) ``` - +| Parameter | Type | Description | +|-----------|------|-------------| +| `conversation` | `Conversation` | The conversation to insert | +| `index` | `Int` | The position at which to insert the conversation | - +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - - +let conversations = CometChatConversations() -##### 4. Badge Style +// Insert a conversation at the top of the list +if let conversation = someConversation { + conversations.insert(conversation: conversation, at: 0) +} +``` -To apply customized styles to the `Badge` component in the `Conversations` Component, you can use the following code snippet. For more information, visit [Badge Styles](https://www.cometchat.com/docs/ui-kit/ios/component-styling#badge) +#### getSelectedConversations() -**Global level styling** +Returns the list of currently selected conversations when in selection mode. - - -```swift -CometChatBadge.style.backgroundColor = UIColor(hex: "#F44649") -CometChatBadge.style.cornerRadius = CometChatCornerStyle(cornerRadius: 4) +```swift lines +public func getSelectedConversations() -> [Conversation] ``` - +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let conversations = CometChatConversations() +conversations.selectionMode = .multiple + +// Get selected conversations +let selectedConversations = conversations.getSelectedConversations() +print("Selected \(selectedConversations.count) conversations") +``` - +#### getConversationList() -**Instance level styling** +Returns the complete list of conversations currently displayed. - - -```swift -let customBadgeStyle = BadgeStyle() -customBadgeStyle.backgroundColor = UIColor(hex: "#F44649") -customBadgeStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 4) - -CometChatBadge.style = customBadgeStyle +```swift lines +public func getConversationList() -> [Conversation] ``` - +```swift lines +import CometChatUIKitSwift +import CometChatSDK - +let conversations = CometChatConversations() - - - +// Get all conversations in the list +let allConversations = conversations.getConversationList() +print("Total conversations: \(allConversations.count)") +``` -### Functionality +### Connection Methods -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. +#### connect() -Below is a list of customizations along with corresponding code snippets +Manually establishes the WebSocket connection for real-time updates. Use this when you need to reconnect after calling `disconnect()`. -| Property | Description | Code | -| ---------------------------- | ------------------------------------------ | ------------------------------------- | -| hideErrorView | Hides the error state view. | `hideErrorView = true` | -| hideNavigationBar | Hides or shows the navigation bar. | `hideNavigationBar = true` | -| hideSearch | Hides the search bar. | `hideSearch = true` | -| hideBackButton | Hides the back button. | `hideBackButton = true` | -| hideLoadingState | Hides the loading state indicator. | `hideLoadingState = true` | -| hideReceipts | Hides message read/delivery receipts. | `hideReceipts = true` | -| hideDeleteConversationOption | Hides the option to delete a conversation. | `hideDeleteConversationOption = true` | -| hideUserStatus | Hides the online/offline status of users. | `hideUserStatus = true` | -| hideGroupType | Hides the group type (private/public). | `hideGroupType = true` | +```swift lines +public func connect() +``` -### Advanced +```swift lines +import CometChatUIKitSwift -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. +let conversations = CometChatConversations() -*** +// Reconnect to receive real-time updates +conversations.connect() +``` -#### Date Time Formatter +#### disconnect() -The **CometChatConversations** component supports full customization of how date and time are displayed using the [CometChatDateTimeFormatter](/ui-kit/ios/localize#datetimeformatter). +Manually disconnects the WebSocket connection. Use this when you want to temporarily stop receiving real-time updates, such as when the view is not visible. -This enables developers to localize, format, or personalize the date and time strings shown next to each conversation—such as “Today”, “Yesterday”, “12:45 PM”, etc. +```swift lines +public func disconnect() +``` -1. Component-Level (Global) +```swift lines +import CometChatUIKitSwift - - -```swift -CometChatConversations.dateTimeFormatter.time = { timestamp in - return "at " + DateFormatter.localizedString(from: Date(timeIntervalSince1970: TimeInterval(timestamp)), dateStyle: .none, timeStyle: .short) -} +let conversations = CometChatConversations() -CometChatConversations.dateTimeFormatter.today = { timestamp in - return "Today • \(formattedTime(from: timestamp))" -} +// Disconnect when view is not visible +conversations.disconnect() -CometChatConversations.dateTimeFormatter.otherDay = { timestamp in // This will display older dates as "24 Apr 2025" instead of the default relative format. - let formatter = DateFormatter() - formatter.dateFormat = "dd MMM yyyy" - return formatter.string(from: Date(timeIntervalSince1970: TimeInterval(timestamp))) -} +// Later, reconnect when view becomes visible again +conversations.connect() ``` - +### Text Formatter Methods - +#### set(textFormatters:) -2. Instance-Level (Local) +Sets custom text formatters for processing and displaying message text in conversation subtitles. - - -```swift -let conversations = CometChatConversations() -conversations.dateTimeFormatter.yesterday = { timestamp in - return "Yesterday at " + formattedTime(from: timestamp) -} +```swift lines +@discardableResult +public func set(textFormatters: [CometChatTextFormatter]) -> Self ``` - +| Parameter | Type | Description | +|-----------|------|-------------| +| `textFormatters` | `[CometChatTextFormatter]` | Array of text formatters to apply to message text | - +```swift lines +import CometChatUIKitSwift -##### Available closures +let conversations = CometChatConversations() -| Property | Description | Code | -| --------- | ------------------------------------------------------------------- | -------------------------------------------------------------- | -| time | Called to format a timestamp as a standard time (e.g., "12:30 PM"). | `CometChatConversations.dateTimeFormatter.time = { ... }` | -| today | Called when rendering messages sent today. | `CometChatConversations.dateTimeFormatter.today = { ... }` | -| yesterday | Called for yesterday's messages. | `CometChatConversations.dateTimeFormatter.yesterday = { ... }` | -| lastweek | Called for messages within the last week. | `CometChatConversations.dateTimeFormatter.lastweek = { ... }` | -| otherDay | Called for dates older than last week. | `CometChatConversations.dateTimeFormatter.otherDay = { ... }` | -| minute | Called when referring to "a minute ago". | `CometChatConversations.dateTimeFormatter.minute = { ... }` | -| minutes | Called for "x minutes ago". | `CometChatConversations.dateTimeFormatter.minutes = { ... }` | -| hour | Called for "an hour ago". | `CometChatConversations.dateTimeFormatter.hour = { ... }` | -| hours | Called for "x hours ago". | `CometChatConversations.dateTimeFormatter.hours = { ... }` | +// Create custom text formatters +let mentionFormatter = CometChatMentionTextFormatter() +let urlFormatter = CometChatURLTextFormatter() -Each closure receives a timestamp (Int, representing UNIX time) and must return a String representing the formatted time. +conversations.set(textFormatters: [mentionFormatter, urlFormatter]) +``` -*** +--- -#### SetTextFormatters +## Props -You can modify the text formatters by using .set(textFormatters:). This method accepts an array of CometChatTextFormatter, allowing you to apply multiple text formatters to the conversation text. +All props are optional. Sorted alphabetically. - - -cometChatConversations.set(textFormatters: \[CometChatTextFormatter]) +### avatarStyle - +Customizes the appearance of avatars in conversation list items. - +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | -*** +```swift lines +import CometChatUIKitSwift -#### SetDatePattern +let conversations = CometChatConversations() -You can modify the date pattern to your requirement using .set(datePattern:). This method accepts a function with a return type String. Inside the function, you can create your own pattern and return it as a String. +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor.systemBlue +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) +avatarStyle.borderWidth = 1 +avatarStyle.borderColor = UIColor.systemGray4 - - -```swift -cometChatConversations.set(datePattern: { conversation in - if let time = conversation.lastMessage?.sentAt { - let date = Date(timeIntervalSince1970: TimeInterval(time)) - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "dd MMM, hh:mm a" - dateFormatter.amSymbol = "AM" - dateFormatter.pmSymbol = "PM" - return dateFormatter.string(from: date) - } - return "" -}) +conversations.set(avatarStyle: avatarStyle) ``` - +### badgeStyle - +Customizes the appearance of unread message count badges. -Demonstration +| | | +|---|---| +| Type | `BadgeStyle` | +| Default | `BadgeStyle()` | - - - - -*** +```swift lines +import CometChatUIKitSwift -#### SetOptions +let conversations = CometChatConversations() -You can define custom options for each conversation using .set(options:). This method allows you to return an array of CometChatConversationOption based on the conversation object. +let badgeStyle = BadgeStyle() +badgeStyle.backgroundColor = UIColor.systemRed +badgeStyle.textColor = UIColor.white +badgeStyle.textFont = UIFont.systemFont(ofSize: 12, weight: .bold) +badgeStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 10) - - -```swift -cometChatConversations.set(options: { conversation in - return [MuteOption(), DeleteOption()] -}) +conversations.set(badgeStyle: badgeStyle) ``` - +### conversationRequestBuilder - +Custom request builder for filtering which conversations appear. -*** +| | | +|---|---| +| Type | `ConversationRequest.ConversationRequestBuilder?` | +| Default | `nil` | -#### AddOptions +### dateStyle -You can dynamically add options to conversations using .add(options:). This method lets you return additional CometChatConversationOption elements. +Customizes the appearance of date/time labels in conversation list items. + +| | | +|---|---| +| Type | `DateStyle` | +| Default | `DateStyle()` | + +```swift lines +import CometChatUIKitSwift - - -```swift -cometChatConversations.add(options: { conversation in - return [ArchiveOption()] -}) +let conversations = CometChatConversations() + +let dateStyle = DateStyle() +dateStyle.textColor = UIColor.secondaryLabel +dateStyle.textFont = UIFont.systemFont(ofSize: 12) + +conversations.set(dateStyle: dateStyle) ``` - +### dateTimeFormatter + +Custom formatter for date/time display in conversation list items. - +| | | +|---|---| +| Type | `CometChatDateTimeFormatter?` | +| Default | `nil` | -*** +```swift lines +import CometChatUIKitSwift -#### SetCustomSoundForMessages +let conversations = CometChatConversations() -You can customize the notification sound for incoming messages using .set(customSoundForMessages:). This method accepts a URL pointing to the audio file. +let dateTimeFormatter = CometChatDateTimeFormatter() +dateTimeFormatter.todayFormat = "h:mm a" +dateTimeFormatter.yesterdayFormat = "'Yesterday'" +dateTimeFormatter.otherFormat = "MMM d" - - -```swift -let soundURL = Bundle.main.url(forResource: "notification_sound", withExtension: "mp3") -cometChatConversations.set(customSoundForMessages: soundURL!) +conversations.dateTimeFormatter = dateTimeFormatter ``` - +### customSoundForMessages - +Custom sound URL for new message notifications. -*** +| | | +|---|---| +| Type | `URL?` | +| Default | `nil` | -#### SetListItemView +### disableSoundForMessages -With this function, you can assign a custom ListItem view to the Conversations Component. +Disables notification sounds for new messages. - - -```swift -cometChatConversations.set(listItemView: { conversation in - let customListItem = CustomListItem() - customListItem.set(conversation: conversation) - return customListItem -}) +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### disableTyping + +Disables typing indicators in the conversation list. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let conversations = CometChatConversations() +conversations.disableTyping = true ``` - +### hideBackButton - +Hides the back button in the navigation bar. -Demonstration +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - - - +### hideDeleteConversationOption -You can create a `CustomListItemView` as a custom `UIView`. Which we will inflate in `setListItemView()` +Hides the delete option in conversation actions. -```swift swift +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -import UIKit -import CometChatUIKitSwift +### hideGroupType -class CustomListItem: UIView { - // Initialize UI components - private var profileImageView: CometChatAvatar = { - let imageView = CometChatAvatar(image: UIImage()) - imageView.translatesAutoresizingMaskIntoConstraints = false // Important for manual layout - return imageView - }() +Hides the public/private group type icons. - private var nameLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false // Important for manual layout - return label - }() +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - override init(frame: CGRect) { - super.init(frame: frame) - setupUI() - } +### hideNavigationBar - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } +Hides the entire navigation bar. - private func setupUI() { - addSubview(profileImageView) - addSubview(nameLabel) - - NSLayoutConstraint.activate([ - // Profile image constraints - profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), - profileImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - profileImageView.widthAnchor.constraint(equalToConstant: 40), - profileImageView.heightAnchor.constraint(equalToConstant: 40), - - nameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 8), - nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), - nameLabel.centerYAnchor.constraint(equalTo: centerYAnchor) - ]) - } +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - func set(conversation: Conversation) { - var avatarURL: String? - if let group = conversation.conversationWith as? Group { - nameLabel.text = group.name - avatarURL = group.icon - } +### hideReceipts - if let user = conversation.conversationWith as? User { - nameLabel.text = user.name - avatarURL = user.avatar - } +Hides read/delivered receipt indicators. +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | +### hideSearch +Hides the search bar. - self.profileImageView.setAvatar(avatarUrl: avatarURL, with: nameLabel.text) - } -} -``` +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideUserStatus + +Hides online/offline status indicators. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -*** +### onSearchClick -#### SetLeadingView +Callback triggered when the search button is clicked. -You can modify the leading view of a conversation cell using .set(leadingView:). +| | | +|---|---| +| Type | `(() -> Void)?` | +| Default | `nil` | - - -```swift -cometChatConversations.set(leadingView: { conversation in - let view = CustomLeadingView() - return view -}) +```swift lines +import CometChatUIKitSwift + +let conversations = CometChatConversations() + +conversations.set(onSearchClick: { [weak self] in + // Handle search button click + self?.presentSearchViewController() +}) ``` - +### privateGroupIcon - +Custom icon for private group conversations. -Demonstration +| | | +|---|---| +| Type | `UIImage?` | +| Default | `nil` | - - - +```swift lines +import CometChatUIKitSwift -You can create a `CustomLeadingView` as a custom `UIView`. Which we will inflate in `setLeadingView()` +let conversations = CometChatConversations() +conversations.privateGroupIcon = UIImage(systemName: "lock.fill") +``` - - -```swift -import UIKit +### protectedGroupIcon -class CustomLeadingView: UIView { - - private let chatIcon: UIImageView = { - let imageView = UIImageView() - let config = UIImage.SymbolConfiguration(pointSize: 20, weight: .bold) - imageView.image = UIImage(systemName: "bubble.left.and.bubble.right.fill", withConfiguration: config) - imageView.tintColor = .black - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - init() { - super.init(frame: .zero) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - backgroundColor = UIColor.purple.withAlphaComponent(0.2) - layer.cornerRadius = 8 - layer.borderWidth = 2 - layer.borderColor = UIColor.orange.cgColor - translatesAutoresizingMaskIntoConstraints = false - - addSubview(chatIcon) - - NSLayoutConstraint.activate([ - chatIcon.centerXAnchor.constraint(equalTo: centerXAnchor), - chatIcon.centerYAnchor.constraint(equalTo: centerYAnchor) - ]) - } -} +Custom icon for password-protected group conversations. + +| | | +|---|---| +| Type | `UIImage?` | +| Default | `nil` | + +```swift lines +import CometChatUIKitSwift + +let conversations = CometChatConversations() +conversations.protectedGroupIcon = UIImage(systemName: "lock.shield.fill") ``` - +### receiptStyle + +Customizes the appearance of message receipt indicators (sent, delivered, read). - +| | | +|---|---| +| Type | `ReceiptStyle` | +| Default | `ReceiptStyle()` | -*** +```swift lines +import CometChatUIKitSwift -#### SetTitleView +let conversations = CometChatConversations() -You can customize the title view of a conversation cell using .set(titleView:). +let receiptStyle = ReceiptStyle() +receiptStyle.sentIconTint = UIColor.systemGray +receiptStyle.deliveredIconTint = UIColor.systemGray +receiptStyle.readIconTint = UIColor.systemBlue - - -```swift -cometChatConversations.set(titleView: { conversation in - let view = CustomTitleView() - return view -}) +conversations.set(receiptStyle: receiptStyle) ``` - +### selectionMode - +Sets the selection mode for multi-select functionality. -Demonstration +| | | +|---|---| +| Type | `SelectionMode` | +| Default | `.none` | - - - +### statusIndicatorStyle -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +Customizes the appearance of online/offline status indicators. - - -```swift -import UIKit +| | | +|---|---| +| Type | `StatusIndicatorStyle` | +| Default | `StatusIndicatorStyle()` | -class CustomTitleView: UIView { - - private let avatarImageView: UIView = { - let view = UIView() - view.backgroundColor = UIColor.purple.withAlphaComponent(0.3) - view.layer.cornerRadius = 20 - view.translatesAutoresizingMaskIntoConstraints = false - - let initialsLabel = UILabel() - initialsLabel.text = "GA" - initialsLabel.font = UIFont.boldSystemFont(ofSize: 16) - initialsLabel.textColor = .white - initialsLabel.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(initialsLabel) - NSLayoutConstraint.activate([ - initialsLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), - initialsLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor) - ]) - - return view - }() - - private let onlineIndicator: UIView = { - let view = UIView() - view.backgroundColor = .green - view.layer.cornerRadius = 5 - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - - private let nameLabel: UILabel = { - let label = UILabel() - label.text = "George Alan" - label.font = UIFont.boldSystemFont(ofSize: 14) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private let statusLabel: UILabel = { - let label = UILabel() - label.text = "📅 In meeting" - label.textColor = .systemBlue - label.font = UIFont.systemFont(ofSize: 14) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private let timestampLabel: UILabel = { - let label = UILabel() - label.text = "07:35 PM" - label.textColor = .gray - label.font = UIFont.systemFont(ofSize: 12) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private let messageLabel: UILabel = { - let label = UILabel() - label.text = "I'll take it. Can you ship it?" - label.textColor = .darkGray - label.font = UIFont.systemFont(ofSize: 14) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - init() { - super.init(frame: .zero) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - addSubview(avatarImageView) - addSubview(onlineIndicator) - addSubview(nameLabel) - addSubview(statusLabel) - addSubview(timestampLabel) - addSubview(messageLabel) - - NSLayoutConstraint.activate([ - avatarImageView.leadingAnchor.constraint(equalTo: leadingAnchor), - avatarImageView.topAnchor.constraint(equalTo: topAnchor), - avatarImageView.widthAnchor.constraint(equalToConstant: 40), - avatarImageView.heightAnchor.constraint(equalToConstant: 40), - - onlineIndicator.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: -2), - onlineIndicator.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: -2), - onlineIndicator.widthAnchor.constraint(equalToConstant: 10), - onlineIndicator.heightAnchor.constraint(equalToConstant: 10), - - nameLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 8), - nameLabel.topAnchor.constraint(equalTo: topAnchor), - - statusLabel.leadingAnchor.constraint(equalTo: nameLabel.trailingAnchor, constant: 4), - statusLabel.centerYAnchor.constraint(equalTo: nameLabel.centerYAnchor), - - timestampLabel.trailingAnchor.constraint(equalTo: trailingAnchor), - timestampLabel.topAnchor.constraint(equalTo: topAnchor), - - messageLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor), - messageLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 2), - messageLabel.trailingAnchor.constraint(equalTo: trailingAnchor), - messageLabel.bottomAnchor.constraint(equalTo: bottomAnchor) - ]) - } -} - +```swift lines +import CometChatUIKitSwift + +let conversations = CometChatConversations() + +let statusIndicatorStyle = StatusIndicatorStyle() +statusIndicatorStyle.backgroundColor = UIColor.systemGreen +statusIndicatorStyle.borderWidth = 2 +statusIndicatorStyle.borderColor = UIColor.white + +conversations.set(statusIndicatorStyle: statusIndicatorStyle) ``` - +### textFormatters + +Array of text formatters for customizing message text display. + +| | | +|---|---| +| Type | `[CometChatTextFormatter]` | +| Default | `[]` | - +### typingIndicatorStyle -*** +Customizes the appearance of typing indicators in conversation list items. -#### SetTrailView +| | | +|---|---| +| Type | `TypingIndicatorStyle` | +| Default | `TypingIndicatorStyle()` | + +```swift lines +import CometChatUIKitSwift + +let conversations = CometChatConversations() -You can modify the trailing view of a conversation cell using .set(trailView:). +let typingIndicatorStyle = TypingIndicatorStyle() +typingIndicatorStyle.textColor = UIColor.systemGray +typingIndicatorStyle.textFont = UIFont.italicSystemFont(ofSize: 14) - - -```swift -cometChatConversations.set(trailView: { conversation in - let view = CustomTrailView() - return view -}) +conversations.set(typingIndicatorStyle: typingIndicatorStyle) ``` - +--- - +## Events -Demonstration +| Event | Payload | Fires when | +|-------|---------|------------| +| `ccConversationDelete` | `Conversation` | A conversation is deleted from the list | - - - +--- -You can create a `CustomTrailView` as a custom `UIView`. Which we will inflate in `setTrailView()` +## Date Time Formatter - - -```swift -import UIKit +Customize how timestamps appear in the conversation list using the `datePattern` callback. -class CustomTrailView: UIView { - - private let timeLabel: UILabel = { - let label = UILabel() - label.text = "10" - label.font = UIFont.boldSystemFont(ofSize: 20) - label.textColor = .purple - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() +### Global Level Formatting + +```swift lines +import CometChatUIKitSwift + +// Set a global date pattern for all conversations instances +CometChatConversations.datePattern = { conversation in + guard let sentAt = conversation.lastMessage?.sentAt else { return "" } - private let subtextLabel: UILabel = { - let label = UILabel() - label.text = "Mins ago" - label.font = UIFont.systemFont(ofSize: 14) - label.textColor = .purple - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() + let date = Date(timeIntervalSince1970: TimeInterval(sentAt)) + let formatter = DateFormatter() - init() { - super.init(frame: .zero) - setupUI() + if Calendar.current.isDateInToday(date) { + formatter.dateFormat = "h:mm a" + } else if Calendar.current.isDateInYesterday(date) { + return "Yesterday" + } else { + formatter.dateFormat = "MMM d" } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } + return formatter.string(from: date) +} +``` + +### Instance Level Formatting + +```swift lines +import CometChatUIKitSwift + +let conversations = CometChatConversations() + +conversations.set(datePattern: { conversation in + guard let sentAt = conversation.lastMessage?.sentAt else { return "" } - private func setupUI() { - backgroundColor = UIColor.purple.withAlphaComponent(0.2) - layer.cornerRadius = 8 - translatesAutoresizingMaskIntoConstraints = false - - addSubview(timeLabel) - addSubview(subtextLabel) - - NSLayoutConstraint.activate([ - timeLabel.centerXAnchor.constraint(equalTo: centerXAnchor), - timeLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8), - - subtextLabel.centerXAnchor.constraint(equalTo: centerXAnchor), - subtextLabel.topAnchor.constraint(equalTo: timeLabel.bottomAnchor, constant: 4), - subtextLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8) - ]) + let date = Date(timeIntervalSince1970: TimeInterval(sentAt)) + let formatter = DateFormatter() + + if Calendar.current.isDateInToday(date) { + formatter.dateFormat = "HH:mm" // 24-hour format + } else if Calendar.current.isDateInYesterday(date) { + return "Yesterday" + } else if Calendar.current.isDate(date, equalTo: Date(), toGranularity: .weekOfYear) { + formatter.dateFormat = "EEEE" // Day name + } else { + formatter.dateFormat = "dd/MM/yy" } -} - + + return formatter.string(from: date) +}) ``` - +### Available Formatters - +| Formatter | Purpose | Default Format | +|-----------|---------|----------------| +| `datePattern` | Format for all timestamps | `h:mm a` for today, `MMM d` for older | -*** +### Common Customizations -#### SetSubtitleView +```swift lines +import CometChatUIKitSwift -You can customize the subtitle view for each conversation item to meet your requirements +let conversations = CometChatConversations() + +// 24-hour time format +conversations.set(datePattern: { conversation in + guard let sentAt = conversation.lastMessage?.sentAt else { return "" } + let date = Date(timeIntervalSince1970: TimeInterval(sentAt)) + let formatter = DateFormatter() + formatter.dateFormat = "HH:mm" + return formatter.string(from: date) +}) - - -```swift -cometChatConversations.set(subtitleView: { conversation in - let customSubtitleView = CustomSubtitleView() - customSubtitleView.set(conversation: conversation) - return customSubtitleView +// Relative time (e.g., "2h ago") +conversations.set(datePattern: { conversation in + guard let sentAt = conversation.lastMessage?.sentAt else { return "" } + let date = Date(timeIntervalSince1970: TimeInterval(sentAt)) + let formatter = RelativeDateTimeFormatter() + formatter.unitsStyle = .abbreviated + return formatter.localizedString(for: date, relativeTo: Date()) }) ``` - +--- - +## Mention Configuration -Demonstration +Configure how @all mentions appear in conversation list items. When a message contains an @all mention, the conversation subtitle displays the mention with a customizable label. - - - +### setMentionAllLabel + +Sets a custom label for @all mentions displayed in conversation list items. -You need to create a `SubtitleView` a custom `UIView` `cocoa touch file` and inflate it in the setSubtitleView apply function. Then, you can define individual actions depending on your requirements. +```swift lines +@discardableResult +public func setMentionAllLabel(_ id: String, _ label: String) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `id` | `String` | The identifier for the @all mention (typically "all") | +| `label` | `String` | The display text shown to users when @all is mentioned | -* `SubtitleView` file should should appear as follows: +```swift lines +import CometChatUIKitSwift -```swift swift +let conversations = CometChatConversations() + +// Set a custom label for @all mentions +conversations.setMentionAllLabel("all", "Everyone") +``` + +```swift lines import UIKit import CometChatUIKitSwift import CometChatSDK -class CustomSubtitleView: UIView { - - // MARK: - Properties - private let subtitleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 14, weight: .regular) // Customize font - label.textColor = .darkGray // Customize text color - label.numberOfLines = 1 // Single line - label.textAlignment = .left // Align to the left - return label - }() +class MentionConfiguredViewController: UIViewController { - // MARK: - Initializers - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setupView() - } - - // MARK: - Setup - private func setupView() { - addSubview(subtitleLabel) + override func viewDidLoad() { + super.viewDidLoad() + + let conversations = CometChatConversations() + .setMentionAllLabel("all", "Team Members") + .set(onItemClick: { [weak self] conversation, indexPath in + self?.openMessages(for: conversation) + }) - // Constraints - NSLayoutConstraint.activate([ - subtitleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), - subtitleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), - subtitleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 4), - subtitleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4) - ]) + navigationController?.pushViewController(conversations, animated: true) } - // MARK: - Configuration - func set(conversation: Conversation) { - subtitleLabel.text = conversation.lastMessage + private func openMessages(for conversation: Conversation) { + let messagesVC = CometChatMessages() + + if let user = conversation.conversationWith as? User { + messagesVC.set(user: user) + } else if let group = conversation.conversationWith as? Group { + messagesVC.set(group: group) + } + + navigationController?.pushViewController(messagesVC, animated: true) } } ``` -*** +--- -#### SetLoadingView +## Common Patterns -You can set a custom loading view using .set(loadingView:). This method accepts a UIView to display while data is being fetched. +### Tab bar integration - - -```swift -let loadingIndicator = UIActivityIndicatorView(style: .medium) -loadingIndicator.startAnimating() -cometChatConversations.set(loadingView: loadingIndicator) -``` +Full implementation with tab bar showing CometChatConversations in a real app: - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - +class MainTabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + setupTabs() + } + + private func setupTabs() { + // Conversations Tab + let conversationsVC = ConversationsContainerViewController() + conversationsVC.tabBarItem = UITabBarItem( + title: "Chats", + image: UIImage(systemName: "message"), + selectedImage: UIImage(systemName: "message.fill") + ) + + // Users Tab + let usersVC = UINavigationController(rootViewController: CometChatUsers()) + usersVC.tabBarItem = UITabBarItem( + title: "Users", + image: UIImage(systemName: "person.2"), + selectedImage: UIImage(systemName: "person.2.fill") + ) + + // Groups Tab + let groupsVC = UINavigationController(rootViewController: CometChatGroups()) + groupsVC.tabBarItem = UITabBarItem( + title: "Groups", + image: UIImage(systemName: "person.3"), + selectedImage: UIImage(systemName: "person.3.fill") + ) + + viewControllers = [conversationsVC, usersVC, groupsVC] + } +} -*** +class ConversationsContainerViewController: UINavigationController { + + override func viewDidLoad() { + super.viewDidLoad() + + let conversations = CometChatConversations() + + // Navigate to messages on tap + conversations.set(onItemClick: { [weak self] conversation, _ in + let messagesVC = CometChatMessages() + + if let user = conversation.conversationWith as? User { + messagesVC.set(user: user) + } else if let group = conversation.conversationWith as? Group { + messagesVC.set(group: group) + } + + self?.pushViewController(messagesVC, animated: true) + }) + + setViewControllers([conversations], animated: false) + } +} +``` -#### SetErrorView +### Custom empty state with CTA -You can customize the error view using .set(errorView:). This method accepts a UIView that appears when an error occurs. +```swift lines +let conversations = CometChatConversations() - - -```swift -let errorLabel = UILabel() -errorLabel.text = "Something went wrong!" -errorLabel.textColor = .red -cometChatConversations.set(errorView: errorLabel) +conversations.set(emptyStateView: { + let emptyView = UIView() + + let label = UILabel() + label.text = "No conversations yet" + label.textAlignment = .center + label.textColor = .secondaryLabel + + let button = UIButton(type: .system) + button.setTitle("Start a conversation", for: .normal) + button.addTarget(self, action: #selector(startNewConversation), for: .touchUpInside) + + // Add subviews and constraints... + return emptyView +}) ``` - +### Hide all chrome — minimal list - +```swift lines +let conversations = CometChatConversations() +conversations.hideReceipts = true +conversations.hideUserStatus = true +conversations.hideGroupType = true +conversations.hideDeleteConversationOption = true +``` + +### Filter by conversation type -*** +```swift lines +// Only user conversations +let userOnlyBuilder = ConversationRequest.ConversationRequestBuilder(limit: 30) + .set(conversationType: .user) -#### SetEmptyView +let conversations = CometChatConversations(conversationRequestBuilder: userOnlyBuilder) -You can customize the empty state view using .set(emptyView:). This method accepts a UIView that appears when no conversations are available. +// Only group conversations +let groupOnlyBuilder = ConversationRequest.ConversationRequestBuilder(limit: 30) + .set(conversationType: .group) - - -```swift -let emptyLabel = UILabel() -emptyLabel.text = "No conversations found" -emptyLabel.textColor = .gray -emptyLabel.textAlignment = .center -cometChatConversations.set(emptyView: emptyLabel) +let groupConversations = CometChatConversations(conversationRequestBuilder: groupOnlyBuilder) ``` - +--- - +## Related Components -*** +- [Messages](/ui-kit/ios/messages) - Display messages in a conversation +- [Users](/ui-kit/ios/users) - List all users to start new conversations +- [Groups](/ui-kit/ios/groups) - List all groups +- [Message Composer](/ui-kit/ios/message-composer) - Send messages in a conversation +- [Conversation With Messages](/ui-kit/ios/conversation-with-messages) - Combined conversations and messages view diff --git a/ui-kit/ios/core-features.mdx b/ui-kit/ios/core-features.mdx index f8e942813..38d41039e 100644 --- a/ui-kit/ios/core-features.mdx +++ b/ui-kit/ios/core-features.mdx @@ -1,209 +1,916 @@ --- -title: "Core" +title: "Core Features" +description: "Essential chat features built into CometChat UI Kit for iOS" --- -## Overview - -The UI Kit comprises a variety of components, each designed to work seamlessly with one another to deliver a comprehensive and intuitive chat experience. - -Here's how different UI Kit components work together to achieve CometChat's Core features: + +```json +{ + "category": "messaging", + "features": [ + {"name": "instantMessaging", "description": "Send and receive text messages in real-time", "component": "CometChatMessages", "enabledByDefault": true}, + {"name": "mediaSharing", "description": "Share images, videos, audio files, and documents", "component": "CometChatMessageComposer", "enabledByDefault": true}, + {"name": "readReceipts", "description": "Show when messages are delivered and read", "component": "CometChatMessageList", "enabledByDefault": true}, + {"name": "typingIndicators", "description": "Show when users are typing in real-time", "component": "CometChatMessageHeader", "enabledByDefault": true}, + {"name": "userPresence", "description": "Display online/offline status for users", "component": "CometChatConversations", "enabledByDefault": true}, + {"name": "reactions", "description": "Let users react to messages with emojis", "component": "CometChatMessageList", "enabledByDefault": true}, + {"name": "mentions", "description": "Tag users in messages with @mentions", "component": "CometChatMessageComposer", "enabledByDefault": true}, + {"name": "threadedConversations", "description": "Reply to specific messages in threads", "component": "CometChatThreadedMessageHeader", "enabledByDefault": true}, + {"name": "groupChat", "description": "Create and manage group conversations", "component": "CometChatGroups", "enabledByDefault": true}, + {"name": "search", "description": "Search across conversations and messages", "component": "CometChatSearch", "enabledByDefault": true} + ], + "relatedComponents": ["CometChatMessages", "CometChatConversations", "CometChatMessageList", "CometChatMessageComposer"] +} +``` + + +CometChat UI Kit provides production-ready components that work together to deliver a complete chat experience. This guide shows how to implement each core feature with copy-paste code examples. ## Instant Messaging -At the heart of CometChat's functionality is the ability to support real-time text messaging. Users can send and receive instant messages, fostering quick and efficient communication. - -| Components | Functionality | -| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [MessageComposer](/ui-kit/ios/message-composer) | [MessageComposer](/ui-kit/ios/message-composer) is a Component that enables users to write and send a variety of messages. | -| [MessageList](/ui-kit/ios/message-list) | [MessageList](/ui-kit/ios/message-list) is a Component that renders a list of messages sent and messages received using [TextBubble](/ui-kit/ios/message-bubble-styling#text-bubble). | - -> [Messages](/ui-kit/ios/message-header) component in CometChat's UI Kit is a comprehensive component that includes both the [MessageComposer](/ui-kit/ios/message-composer) and the [MessageList](/ui-kit/ios/message-list) components. So, if you're looking to implement a messaging feature in your application, using the Messages component would be a straightforward and efficient way to do it. - -## Media Sharing - -Beyond text, CometChat allows users to share various media types within their conversations. This includes images, videos, audio files, and documents, enriching the chat experience and enabling more comprehensive communication. +Send and receive text messages in real-time. -| Components | Functionality | -| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [MessageComposer](/ui-kit/ios/message-composer) | [MessageComposer](/ui-kit/ios/message-composer) is a Component that has ActionSheet, ActionSheet is a menu that appears over the context of the app, providing multiple options for sharing media files. | -| [MessageList](/ui-kit/ios/message-list) | [MessageList](/ui-kit/ios/message-list) is a Component that renders different Media Message bubbles like [Image Bubble](/ui-kit/ios/message-bubble-styling-styling#image-bubble), [File Bubble](/ui-kit/ios/message-bubble-styling-styling), [Audio Bubble](/ui-kit/ios/message-bubble-styling-styling#audio-bubble) [Video Bubble](/ui-kit/ios/message-bubble-styling#video-bubble) | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // For one-on-one chat + let messagesVC = CometChatMessages() + + // Set the user to chat with + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + +**Components Used:** +- [MessageComposer](/ui-kit/ios/message-composer) - Text input and send button +- [MessageList](/ui-kit/ios/message-list) - Displays sent and received messages +- [Messages](/ui-kit/ios/message-header) - Complete messaging screen (includes both) -> [Messages](/ui-kit/ios/message-header) component in CometChat's UI Kit is a comprehensive component that includes both the [MessageComposer](/ui-kit/ios/message-composer) and the [MessageList](/ui-kit/ios/message-list) components. So, if you're looking to implement a messaging feature in your application, using the Messages component would be a straightforward and efficient way to do it. +## Media Sharing + +Share images, videos, audio files, and documents. + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class MediaChatViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + let messagesVC = CometChatMessages() + + // The message composer automatically includes media sharing options + // Users can tap the attachment button to share: + // - Photos from library + // - Camera capture + // - Documents + // - Audio files + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Send media programmatically + func sendImage(to receiverUID: String, imageURL: URL) { + let mediaMessage = MediaMessage( + receiverUid: receiverUID, + fileurl: imageURL.absoluteString, + messageType: .image, + receiverType: .user + ) + + CometChat.sendMediaMessage(message: mediaMessage) { message in + print("Image sent successfully") + } onError: { error in + print("Error sending image: \(error?.errorDescription ?? "")") + } + } +} +``` + +**Supported Media Types:** +| Type | Bubble Component | +|------|------------------| +| Images | [Image Bubble](/ui-kit/ios/message-bubble-styling#image-bubble) | +| Videos | [Video Bubble](/ui-kit/ios/message-bubble-styling#video-bubble) | +| Audio | [Audio Bubble](/ui-kit/ios/message-bubble-styling#audio-bubble) | +| Files | [File Bubble](/ui-kit/ios/message-bubble-styling#file-bubble) | ## Read Receipts -CometChat's Read Receipts feature provides visibility into the message status, letting users know when a message has been delivered and read. This brings clarity to the communication and ensures users are informed about the status of their messages. +Show when messages are delivered and read. -| Components | Functionality | -| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Conversations](/ui-kit/ios/conversations) | [Conversations](/ui-kit/ios/conversations) is a Component that renders Conversations item List, Conversation item also displays the delivery status of the last message providing users with real-time updates on the status of their messages. | -| [MessageList](/ui-kit/ios/message-list) | [MessageList](/ui-kit/ios/message-list) is a Component that renders different types of Message bubbles, Read Recept status is an integral part of all message bubbles, no matter the type, and provides real-time updates about the status of the message. | -| [MessageInformation](/ui-kit/ios/message-information) | [MessageInformation](/ui-kit/ios/message-information) component provides transparency into the status of each sent message, giving the sender insights into whether their message has been delivered and read. | - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ReceiptsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Read receipts are enabled by default + let messagesVC = CometChatMessages() + + // To hide receipts: + // messagesVC.hideReceipts = true + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // View detailed message information + func showMessageInfo(for message: BaseMessage) { + let messageInfo = CometChatMessageInformation() + messageInfo.set(message: message) + navigationController?.pushViewController(messageInfo, animated: true) + } +} +``` + +**Receipt States:** +- ✓ Sent - Message sent to server +- ✓✓ Delivered - Message delivered to recipient's device +- ✓✓ (blue) Read - Recipient has seen the message + +**Components Used:** +- [Conversations](/ui-kit/ios/conversations) - Shows receipt status on last message +- [MessageList](/ui-kit/ios/message-list) - Shows receipts on each message +- [MessageInformation](/ui-kit/ios/message-information) - Detailed delivery/read info ## Mark As Unread -Mark as Unread feature allows users to manually mark messages as unread, helping them keep track of important conversations they want to revisit later. When enabled, the message list can automatically start from the first unread message, making it easier to pick up where you left off. +Let users mark messages as unread to revisit later. -| Components | Functionality | -| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Message List](/ui-kit/ios/message-list) | [Message List](/ui-kit/ios/message-list#functionality) provides the "Mark as unread" option in message actions and supports starting from the first unread message when enabled. | -| [Conversations](/ui-kit/ios/conversations) | [Conversations](/ui-kit/ios/conversations#functionality) component listens to conversation updates and reflects the updated unread count in real-time. | - -## Typing Indicator - -The Typing Indicator feature in CometChat shows when a user is typing a response in real-time, fostering a more interactive and engaging chat environment. This feature enhances the real-time communication experience, making conversations feel more natural and fluid. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class UnreadMessagesViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + let messagesVC = CometChatMessages() + + // Enable starting from first unread message + messagesVC.scrollToUnreadMessages = true + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Mark a message as unread programmatically + func markAsUnread(message: BaseMessage) { + CometChat.markAsUnread( + baseMessage: message + ) { _ in + print("Marked as unread") + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + +## Typing Indicators + +Show when users are typing in real-time. -| Components | Functionality | -| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Conversations](/ui-kit/ios/conversations) | [Conversations](/ui-kit/ios/conversations) is a Component that renders Conversations item List, Conversations item also shows real-time typing status indicators. This means that if a user in a one-on-one chat or a participant in a group chat is currently typing a message | -| [Message Header](/ui-kit/ios/message-header) | [Message Header](/ui-kit/ios/message-header) that renders details of User or Groups in ToolBar. The MessageHeader also handles the Typing Indicator functionality. When a user or a member in a group is typing, the MessageHeader dynamically updates to display a 'typing...' status in real-time. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class TypingIndicatorViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Typing indicators are enabled by default in: + // - CometChatConversations (shows "typing..." in conversation list) + // - CometChatMessageHeader (shows "typing..." below user name) + + let messagesVC = CometChatMessages() + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Send typing indicator manually + func startTyping(to receiverUID: String) { + let typingIndicator = TypingIndicator( + receiverID: receiverUID, + receiverType: .user + ) + CometChat.startTyping(indicator: typingIndicator) + } + + func stopTyping(to receiverUID: String) { + let typingIndicator = TypingIndicator( + receiverID: receiverUID, + receiverType: .user + ) + CometChat.endTyping(indicator: typingIndicator) + } +} +``` + +**Components Used:** +- [Conversations](/ui-kit/ios/conversations) - Shows typing in conversation list +- [MessageHeader](/ui-kit/ios/message-header) - Shows typing below user/group name ## User Presence -CometChat's User Presence feature allows users to see whether their contacts are online, offline. This helps users know the best time to initiate a conversation and sets expectations about response times. +Display online/offline status for users. -| Components | Functionality | -| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Conversations](/ui-kit/ios/conversations) | [Conversations](/ui-kit/ios/conversations) is a Component that renders Conversations item List, Conversations item also shows user presence information. | -| [Message Header](/ui-kit/ios/message-header) | [Message Header](/ui-kit/ios/message-header) that renders details of User or Groups in ToolBar. The MessageHeader also handles user Presence information. | -| [Users](/ui-kit/ios/users) | [Users](/ui-kit/ios/users) renders list of users available in your app.It also responsible to render users Presence information. | -| [Group Members](/ui-kit/ios/group-members) | [Group Members](/ui-kit/ios/group-members) renders list of users available in the group. The Group Members component also handles user Presence information. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class PresenceViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // User presence is shown automatically in: + // - CometChatConversations (green dot for online users) + // - CometChatMessageHeader (shows "Online" or "Last seen") + // - CometChatUsers (green dot for online users) + // - CometChatGroupMembers (green dot for online members) + + let conversations = CometChatConversations() + + // To hide user status: + // conversations.hideUserStatus = true + + navigationController?.pushViewController(conversations, animated: true) + } + + // Listen for presence changes + func listenForPresenceChanges() { + CometChat.addUserListener("presence-listener", self) + } +} + +extension PresenceViewController: CometChatUserDelegate { + func onUserOnline(user: User) { + print("\(user.name ?? "") is now online") + } + + func onUserOffline(user: User) { + print("\(user.name ?? "") went offline") + } +} +``` ## Reactions -CometChat's Reactions feature adds a layer of expressiveness to your chat application by allowing users to react to messages. With Reactions, users can convey a range of emotions or express their thoughts on a particular message without typing out a full response, enhancing their user experience and fostering greater engagement. - -The number of reactions displayed depends on the width of the view. For instance, if a message contains 5 reactions but the width of the CometChatReactions view can only accommodate 4 reactions at a time, the first three reactions will be shown along with an additional UI element at the end of the row. This element indicates the number of other unique reactions that are not immediately visible, informing users of the total count of different reactions. - -In the example, tapping on this element (depicted as "+2" in the provided image) will by default trigger the CometChatReactionList component. This action opens a modal sheet from the bottom of the screen, displaying all reactions received by the message. +Let users react to messages with emojis. -| Components | Functionality | -| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [MessageList](/ui-kit/ios/message-list) | [MessageList](/ui-kit/ios/message-list) is a Component that renders different types of Message bubbles, Irrespective of the type of message bubble, Reactions are an integral part and offer a more engaging, expressive way for users to respond to messages. | -| [Messages](/ui-kit/ios/message-header) | [Messages](/ui-kit/ios/message-header) component in CometChat's UI Kit is a comprehensive component that includes both the [MessageComposer](/ui-kit/ios/message-composer) and the [MessageList](/ui-kit/ios/message-list) components. So, if you're looking to implement a messaging feature in your application, using the Messages component would be a straightforward and efficient way to do it. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ReactionsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Reactions are enabled by default + // Users can long-press a message to add reactions + + let messagesVC = CometChatMessages() + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Add reaction programmatically + func addReaction(to message: BaseMessage, emoji: String) { + CometChat.addReaction( + messageId: message.id, + reaction: emoji + ) { message in + print("Reaction added") + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Remove reaction + func removeReaction(from message: BaseMessage, emoji: String) { + CometChat.removeReaction( + messageId: message.id, + reaction: emoji + ) { message in + print("Reaction removed") + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` ## Mentions -Mentions is a robust feature provided by CometChat that enhances the interactivity and clarity of group or 1-1 chats by allowing users to directly address or refer to specific individuals in a conversation. +Tag users in messages with @mentions. -| Components | Functionality | -| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Conversations](/ui-kit/ios/conversations) | [Conversations](/ui-kit/ios/conversations) component provides an enhanced user experience by integrating the Mentions feature. This means that from the conversation list itself, users can see where they or someone else have been specifically mentioned. | -| [MessageComposer](/ui-kit/ios/message-composer) | [MessageComposer](/ui-kit/ios/message-composer)is a component that allows users to craft and send various types of messages, including the usage of the Mentions feature for direct addressing within the conversation. | -| [MessageList](/ui-kit/ios/message-list) | [MessageList](/ui-kit/ios/message-list) is a component that displays a list of sent and received messages. It also supports the rendering of Mentions, enhancing the readability and interactivity of conversations. | -| [Messages](/ui-kit/ios/message-header) | [Messages](/ui-kit/ios/message-header) The component is a comprehensive element in CometChat's UI Kit, encapsulating both the [MessageComposer](/ui-kit/ios/message-composer) and [MessageList](/ui-kit/ios/message-list) components. It fully supports the Mentions feature, providing a streamlined way to implement an interactive and engaging messaging function in your application. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class MentionsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Mentions are enabled by default + // Type @ in the composer to see mention suggestions + + let messagesVC = CometChatMessages() + + CometChat.getGroup(GUID: "group-123") { group in + DispatchQueue.main.async { + messagesVC.set(group: group) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Send message with mention programmatically + func sendMessageWithMention(to groupID: String, mentionedUser: User) { + let textMessage = TextMessage( + receiverUid: groupID, + text: "Hey @\(mentionedUser.name ?? ""), check this out!", + receiverType: .group + ) + + // Add mentioned users + textMessage.mentionedUsers = [mentionedUser] + + CometChat.sendTextMessage(message: textMessage) { message in + print("Message with mention sent") + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` ## Threaded Conversations -The Threaded Conversations feature enables users to respond directly to a specific message in a chat. This keeps conversations organized and enhances the user experience by maintaining context, especially in group chats. +Reply to specific messages in threads. -| Components | Functionality | -| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| [Threaded Messages](/ui-kit/ios/threaded-messages-header) | [Threaded Messages](/ui-kit/ios/threaded-messages-header) that displays all replies made to a particular message in a conversation. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ThreadedMessagesViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Threaded messages are enabled by default + // Users can tap "Reply in thread" on any message + + let messagesVC = CometChatMessages() + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Open thread view for a message + // Note: Thread replies are handled automatically by CometChatMessageList + // when user taps "Reply in thread". The thread view uses CometChatThreadedMessageHeader + // combined with CometChatMessageList and CometChatMessageComposer. + func openThread(for parentMessage: BaseMessage, user: User) { + // Create a view controller to host the threaded messages + let threadVC = UIViewController() + threadVC.view.backgroundColor = .systemBackground + + // Create threaded message header + let threadedHeader = CometChatThreadedMessageHeader() + threadedHeader.set(parentMessage: parentMessage) + threadedHeader.set(controller: threadVC) + threadedHeader.translatesAutoresizingMaskIntoConstraints = false + + // Create message list for thread replies + let messageList = CometChatMessageList() + messageList.set(user: user) + messageList.set(parentMessage: parentMessage) + messageList.set(controller: threadVC) + messageList.translatesAutoresizingMaskIntoConstraints = false + + // Create composer for thread replies + let composer = CometChatMessageComposer() + composer.set(user: user) + composer.set(parentMessage: parentMessage) + composer.set(controller: threadVC) + composer.translatesAutoresizingMaskIntoConstraints = false + + // Add to view + threadVC.view.addSubview(threadedHeader) + threadVC.view.addSubview(messageList) + threadVC.view.addSubview(composer) + + // Layout constraints + NSLayoutConstraint.activate([ + threadedHeader.topAnchor.constraint(equalTo: threadVC.view.safeAreaLayoutGuide.topAnchor), + threadedHeader.leadingAnchor.constraint(equalTo: threadVC.view.leadingAnchor), + threadedHeader.trailingAnchor.constraint(equalTo: threadVC.view.trailingAnchor), + + messageList.topAnchor.constraint(equalTo: threadedHeader.bottomAnchor), + messageList.leadingAnchor.constraint(equalTo: threadVC.view.leadingAnchor), + messageList.trailingAnchor.constraint(equalTo: threadVC.view.trailingAnchor), + messageList.bottomAnchor.constraint(equalTo: composer.topAnchor), + + composer.leadingAnchor.constraint(equalTo: threadVC.view.leadingAnchor), + composer.trailingAnchor.constraint(equalTo: threadVC.view.trailingAnchor), + composer.bottomAnchor.constraint(equalTo: threadVC.view.safeAreaLayoutGuide.bottomAnchor) + ]) + + navigationController?.pushViewController(threadVC, animated: true) + } + + // Send reply in thread programmatically + func sendThreadReply(parentMessage: BaseMessage, text: String) { + let reply = TextMessage( + receiverUid: parentMessage.receiverUid, + text: text, + receiverType: parentMessage.receiverType + ) + reply.parentMessageId = parentMessage.id + + CometChat.sendTextMessage(message: reply) { message in + print("Thread reply sent") + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + +**Component Used:** +- [ThreadedMessages](/ui-kit/ios/threaded-messages-header) - Displays thread replies ## Group Chat -CometChat facilitates Group Chats, allowing users to have conversations with multiple participants simultaneously. This feature is crucial for team collaborations, group discussions, social communities, and more. +Create and manage group conversations. -For a comprehensive understanding and guide on implementing and using the Groups feature in CometChat, you should refer to our detailed guide on [Groups](/ui-kit/ios/groups). - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class GroupChatViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + showGroupsList() + } + + // Show all groups + func showGroupsList() { + let groups = CometChatGroups() + + groups.set(onItemClick: { [weak self] group, _ in + self?.openGroupChat(group: group) + }) + + navigationController?.pushViewController(groups, animated: true) + } + + // Open chat for a group + func openGroupChat(group: Group) { + let messagesVC = CometChatMessages() + messagesVC.set(group: group) + navigationController?.pushViewController(messagesVC, animated: true) + } + + // Create a new group + func createGroup(name: String, type: CometChat.groupType) { + let group = Group( + guid: UUID().uuidString, + name: name, + groupType: type, + password: nil + ) + + CometChat.createGroup(group: group) { createdGroup in + print("Group created: \(createdGroup.name ?? "")") + DispatchQueue.main.async { + self.openGroupChat(group: createdGroup) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } + + // Join a public group + func joinGroup(guid: String) { + CometChat.joinGroup( + GUID: guid, + groupType: .public, + password: nil + ) { group in + print("Joined group: \(group.name ?? "")") + DispatchQueue.main.async { + self.openGroupChat(group: group) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + +**Related Guide:** [Groups](/ui-kit/ios/groups) ## Quoted Reply -Quoted Reply is a robust feature provided by CometChat that enables users to quickly reply to specific messages by selecting the "Reply" option from a message's action menu. This enhances context, keeps conversations organized, and improves overall chat experience in both 1-1 and group chats. +Reply to specific messages with context. -| Components | Functionality | -| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) supports replying to messages via the "Reply" option. Users can select "Reply" on a message to open the composer with the quoted reply pre-filled, maintaining context. | -| [Message Composer](/ui-kit/android/message-composer) | [Message Composer](/ui-kit/android/message-composer) works seamlessly with Quoted Message by showing the quoted reply above the input field, letting users compose their response in proper context. | - -## Conversation and Advanced Search - -Conversation and Advanced Search is a powerful feature provided by CometChat that enables users to quickly find conversations, messages, and media across chats in real time. It supports filters, scopes, and custom actions, allowing users to locate content efficiently while keeping the chat experience smooth and intuitive. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class QuotedReplyViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Quoted reply is enabled by default + // Users can swipe right on a message or tap "Reply" in message actions + + let messagesVC = CometChatMessages() + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + +## Search + +Search across conversations and messages. -| Components | Functionality | -| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Search](/ui-kit/ios/search) | [Search](/ui-kit/ios/search) allows users to search across conversations and messages in real time. Users can click on a result to open the conversation or jump directly to a specific message. | -| [Message Header](/ui-kit/ios/message-header) | [Message Header](/ui-kit/ios/message-header) shows the search button in the chat header, allowing users to search within a conversation. | -| [Message List](/ui-kit/ios/message-list) | [Message List](/ui-kit/ios/message-list) shows the selected message when clicked from search results and highlights it in the message list. | -| [Conversations](/ui-kit/ios/conversations) | [Conversations](/ui-kit/ios/conversations) displays the search input. | - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class SearchViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Search is available in: + // - CometChatConversations (search bar at top) + // - CometChatMessageHeader (search button) + + let conversations = CometChatConversations() + + // Search is enabled by default + // To hide search: + // conversations.hideSearch = true + + navigationController?.pushViewController(conversations, animated: true) + } + + // Open dedicated search screen + func openSearch() { + let search = CometChatSearch() + navigationController?.pushViewController(search, animated: true) + } +} +``` + +**Components Used:** +- [Search](/ui-kit/ios/search) - Dedicated search screen +- [MessageHeader](/ui-kit/ios/message-header) - Search within conversation +- [Conversations](/ui-kit/ios/conversations) - Search conversations ## Moderation -CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. +Automatically filter inappropriate content. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ModerationViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Moderation is handled automatically based on your + // CometChat dashboard settings + + // Blocked messages are displayed appropriately + // based on your moderation rules + + let messagesVC = CometChatMessages() + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + -Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. +Configure moderation rules in your [CometChat Dashboard](/moderation/overview). -| Components | Functionality | -| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Message List](/ui-kit/ios/message-list) | [Message List](/ui-kit/ios/message-list) automatically handles moderated messages, displaying blocked content appropriately based on your moderation settings. | - -After implementing moderation rules, users can report messages they find inappropriate or harmful. As a next step, you can enable the **[Report Message](#report-message)** feature to allow users to flag messages for review by moderators. - ## Report Message -The Report Message feature allows users to report inappropriate or harmful messages within the chat. Users can choose from predefined reasons and provide additional remarks for detailed context. This feature helps maintain a safe and respectful chat environment. - - -Learn more about how flagged messages are handled, reviewed, and moderated in the [Flagged Messages](/moderation/flagged-messages) documentation. - +Allow users to report inappropriate messages. -| Components | Functionality | -| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ReportMessageViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Report message is available in message actions + // Users can long-press a message and select "Report" + + let messagesVC = CometChatMessages() + + CometChat.getUser(UID: "cometchat-uid-1") { user in + DispatchQueue.main.async { + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} +``` + + +View and manage reported messages in [Flagged Messages](/moderation/flagged-messages). + + +{/* ## Complete Chat App Example + +Here's a production-ready implementation combining all core features: + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + // Initialize CometChat + let uiKitSettings = UIKitSettings() + .set(appID: "YOUR_APP_ID") + .set(authKey: "YOUR_AUTH_KEY") + .set(region: "YOUR_REGION") + .build() + + CometChatUIKit.init(uiKitSettings: uiKitSettings) { result in + switch result { + case .success: + self.loginAndShowChat() + case .failure(let error): + print("Init failed: \(error.localizedDescription)") + } + } + + return true + } + + private func loginAndShowChat() { + CometChatUIKit.login(uid: "cometchat-uid-1") { result in + switch result { + case .success(let user): + print("Logged in as: \(user.name ?? "")") + DispatchQueue.main.async { + self.showMainScreen() + } + case .failure(let error): + print("Login failed: \(error.localizedDescription)") + } + } + } + + private func showMainScreen() { + let tabBar = MainTabBarController() + window?.rootViewController = tabBar + window?.makeKeyAndVisible() + } +} + +class MainTabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Conversations Tab + let conversationsNav = UINavigationController() + let conversations = CometChatConversations() + conversations.set(onItemClick: { [weak conversationsNav] conversation, _ in + let messagesVC = CometChatMessages() + if let user = conversation.conversationWith as? User { + messagesVC.set(user: user) + } else if let group = conversation.conversationWith as? Group { + messagesVC.set(group: group) + } + conversationsNav?.pushViewController(messagesVC, animated: true) + }) + conversationsNav.setViewControllers([conversations], animated: false) + conversationsNav.tabBarItem = UITabBarItem( + title: "Chats", + image: UIImage(systemName: "message"), + selectedImage: UIImage(systemName: "message.fill") + ) + + // Users Tab + let usersNav = UINavigationController() + let users = CometChatUsers() + users.set(onItemClick: { [weak usersNav] user, _ in + let messagesVC = CometChatMessages() + messagesVC.set(user: user) + usersNav?.pushViewController(messagesVC, animated: true) + }) + usersNav.setViewControllers([users], animated: false) + usersNav.tabBarItem = UITabBarItem( + title: "Users", + image: UIImage(systemName: "person.2"), + selectedImage: UIImage(systemName: "person.2.fill") + ) + + // Groups Tab + let groupsNav = UINavigationController() + let groups = CometChatGroups() + groups.set(onItemClick: { [weak groupsNav] group, _ in + let messagesVC = CometChatMessages() + messagesVC.set(group: group) + groupsNav?.pushViewController(messagesVC, animated: true) + }) + groupsNav.setViewControllers([groups], animated: false) + groupsNav.tabBarItem = UITabBarItem( + title: "Groups", + image: UIImage(systemName: "person.3"), + selectedImage: UIImage(systemName: "person.3.fill") + ) + + viewControllers = [conversationsNav, usersNav, groupsNav] + } +} +``` */} + +{/* ## Feature Summary + +| Feature | Component | Enabled by Default | +|---------|-----------|-------------------| +| Text Messaging | [Messages](/ui-kit/ios/message-header) | ✅ | +| Media Sharing | [MessageComposer](/ui-kit/ios/message-composer) | ✅ | +| Read Receipts | [MessageList](/ui-kit/ios/message-list) | ✅ | +| Typing Indicators | [MessageHeader](/ui-kit/ios/message-header) | ✅ | +| User Presence | [Conversations](/ui-kit/ios/conversations) | ✅ | +| Reactions | [MessageList](/ui-kit/ios/message-list) | ✅ | +| Mentions | [MessageComposer](/ui-kit/ios/message-composer) | ✅ | +| Threads | [ThreadedMessages](/ui-kit/ios/threaded-messages-header) | ✅ | +| Search | [Search](/ui-kit/ios/search) | ✅ | +| Moderation | Dashboard Config | Configure in Dashboard | */} diff --git a/ui-kit/ios/events.mdx b/ui-kit/ios/events.mdx index ccdfc705d..cfeb45a75 100644 --- a/ui-kit/ios/events.mdx +++ b/ui-kit/ios/events.mdx @@ -1,1462 +1,798 @@ --- title: "Events" +description: "Listen and respond to user actions and state changes in CometChat UI Kit" --- -## Overview - -Events allow for a decoupled, flexible architecture where different parts of the application can interact without having to directly reference each other. This makes it easier to create complex, interactive experiences, as well as to extend and customize the functionality provided by the CometChat UI Kit. - -Both Components and Composite Components have the ability to emit events. These events are dispatched in response to certain changes or user interactions within the component. By emitting events, these components allow other parts of the application to react to changes or interactions, thus enabling dynamic and interactive behavior within the application. - -## User Events - -CometChatUserEvents emits events when the logged-in user executes some action on another user - -It contains the following properties and methods - -### observer - -This is a List of Dictionary that contains components listening to user events in key value pairs - -### Type - -`[String: CometChatUserEventListener]()` - -*** - -### addListener - -this method stores the passed listenerClass against the passed id in the usersListener. - -### Signature - -### Uses - - - -```swift -addListener(_ id: String,_ observer: CometChatUserEventListener) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | -------------------------- | -------------------------------------- | -| id | String | the key to store the component against | -| observer | CometChatUserEventListener | the component listening to user events | - -*** - -### removeListener - -this method removes the entry with the passed id from the usersListener. - -### Signature - - - -```swift -removeListener(_ id: String) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ------ | ------------------------------ | -| id | String | the key of the entry to remove | - -*** - -### onUserBlock - -This method is used to perform some task when the logged-in user has blocked a user - -### Signature - - - -```swift -onUserBlock(user: User) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ---- | ------------------------------ | -| user | User | the user that has been blocked | - -*** - -### onUserUnblock - -This method is used to perform some task when the logged-in user has unblocked a blocked user. - -### Signature - - - -```swift -onUserUnblock(user: User) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ---- | -------------------------------- | -| user | User | the user that has been unblocked | - -### Return Type - -`void` - -### Emitting User Events - -There are two types of user event listeners, one is for the SDK, which listens for events emitted from the backend for actions taken by users other than the logged in user and second, the events specific to the UI Kit which listens for events emitted from the client side for actions made by the logged-in user. The code snippets shared below contains how to emit such client-side user events to inform other UI components in your project that a user has been blocked or unblocked, the methods being used are static and hence they can be called without having to create an instance of CometChatUserEvents class. - - - -```swift -//pass the [User] object of the user which has been blocked by the logged in user - CometChatUserEvents.emitOnUserBlock(user: User) - -//pass the [User] object of the user which has been unblocked by the logged in user - CometChatUserEvents.emitOnUserUnblock(user: User) -``` - - - - - -*** - -### Listening to User Events - -Here we will go through how anyone can listen to these client-side User Events to update the state of the UI accordingly. - -| Events | Description | -| ----------------- | --------------------------------------------------------------------- | -| `onUserBlocked` | This will get triggered when the logged in user blocks another user | -| `onUserUnblocked` | This will get triggered when the logged in user unblocks another user | - - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { - - public override func viewDidLoad() { - super.viewDidLoad() - - // Subscribing for the listener to listen events from user module - CometChatUserEvents.addListener("UNIQUE_ID", self as CometChatUserEventListener) - } - - public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module - CometChatUserEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") - } - - -} - - // Listener events from user module -extension ViewController: CometChatUserEventListener { - - func onUserBlock(user: User) { - // Do Stuff - } - - func onUserUnblock(user: User) { - // Do Stuff - } -} -``` - - - - - -## Group Events - -CometChatGroupEvents emits events when the logged-in user executes some action on a group or group member - -It contains the following properties and methods: - -### observer - -This is a List of Dictionary that contains components listening to group events in key value pairs - -### Type - -`[String: CometChatGroupEventListener]()` - -*** - -### addListener - -this method stores the passed listenerClass against the passed listenerId in the observer. - -### Signature - - - -```swift -addListener(_ id: String,_ observer: CometChatGroupEventListener) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | --------------------------- | --------------------------------------- | -| id | String | the key to store the component against | -| observer | CometChatGroupEventListener | the component listening to group events | - -*** - -### removeListener - -this method removes the entry with the passed listenerId from the observer. - -### Signature - - - -```swift -removeListener(_ id: String) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ------ | ------------------------------ | -| id | String | the key of the entry to remove | - -*** - -### onGroupCreate - -This method is used to perform some task when the logged-in user has created a group - -### Signature - - - -```swift -onGroupCreate(group: Group) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----- | ----------------------------------- | -| group | Group | the new group that has been created | - -*** - -### onCreateGroupClick - -This method is used to perform some task when the logged-in user click on Create group button - -### Signature - - - -```swift -onCreateGroupClick() -``` - - - - - -*** - -### onGroupDelete - -This method is used to perform some task when the logged-in user has deleted a group. - -### Signature - - - -```swift -onGroupDelete(group: Group) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----- | ------------------------------- | -| group | Group | the group that has been deleted | - -*** - -### onGroupMemberLeave - -This method is used to perform some task when the logged-in user has left a group. - -### Signature - - - -```swift -onGroupMemberLeave(leftUser: User, leftGroup: Group) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----- | --------------------------------------------- | -| leftUser | User | the user that has left the group | -| leftGroup | Group | the group from which the logged-user has left | - -*** - -### onGroupMemberChangeScope - -This method is used to perform some task when the logged-in user has changed the scope of a member of a group. - -### Signature - - - -```swift -onGroupMemberChangeScope(updatedBy: User , updatedUser: User , scopeChangedTo: CometChat.MemberScope , scopeChangedFrom: CometChat.MemberScope, group: Group) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------------- | ------ | -------------------------------------------------- | -| updatedBy | User | the user who changed the scope of group member | -| updatedUser | User | the user whose scope has been changed | -| scopeChangedTo | String | the new scope | -| scopeChangedFrom | String | the old scope | -| group | Group | the group from where the scope change has occurred | - -*** - -### onGroupMemberBan - -This method is used to perform some task when the logged-in user has banned a user from the group. - -### Signature - - - -```swift -onGroupMemberBan(bannedUser: User, bannedGroup: Group, bannedBy: User) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----- | --------------------------------------------- | -| bannedUser | User | the user that has been banned | -| bannedBy | User | the user who has banned | -| bannedFrom | Group | the group from which the user has been banned | - -*** - -### onGroupMemberKick - -This method is used to perform some task when the logged-in user has kicked a user from the group. - -### Signature - - - -```swift -onGroupMemberKick(kickedUser: User, kickedGroup: Group, kickedBy: User) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ----------- | ----- | --------------------------------------------- | -| kickedUser | User | the banned user that has been kicked | -| kickedBy | User | the user who has kicked | -| kickedGroup | Group | the group from which the user has been kicked | - -*** - -### onGroupMemberUnban - -This method is used to perform some task when the logged-in user has unbanned a banned user from a group. - -### Signature - - - -```swift -onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group, unbannedBy: User) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ------------ | ----- | ------------------------------------------------------ | -| unbannedUser | User | the banned user that has been unbanned | -| unbannedBy | User | the user who has unbanned | -| unbannedFrom | Group | the group from which the banned user has been unbanned | - -*** - -### onGroupMemberJoin - -This method is used to perform some task when the logged-in user has joined a group. - -### Signature - - - -```swift -onGroupMemberJoin(joinedUser: User, joinedGroup: Group) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ----------- | ----- | -------------------------------------- | -| joinedUser | User | the user that has been unblocked | -| joinedGroup | Group | the group the users have been added to | - -*** - -### onGroupMemberAdd - -This method is used to perform some task when the logged-in user has added new members to the group - -### Signature - - - -```swift -onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----------- | ---------------------------------------- | -| members | List\ | the list of users added | -| group | Group | the group the users have been added to | -| addedBy | User | the user who has added those new members | - -*** - -### onOwnershipChange - -This method is used to perform some task when the logged-in user has transferred their ownership of a group. - -### Signature - - - -```swift -onOwnershipChange(group: Group?, member: GroupMember?) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----------- | ----------------------------------------------------- | -| group | Group | the group where the ownership has been changed | -| member | GroupMember | the group member who has been made owner of the group | - -*** - -### Emitting Group Events - -There are two types of group event listeners, one is for the SDK, which listens for events emitted from the backend for actions taken by users other than the logged in user and second, the events specific to the UI Kit which listens for events emitted from the client side for actions made by the logged-in user. The code snippets shared below contains how to emit such client-side group events to inform other UI components in a project that a group has been created or deleted or new members have been added to the group, the logged in user themselves have joined a group, members being banned by the logged in user or the change of ownership or scope of a group member, the methods being used are static and hence they can be called without having to create an instance of CometChatGroupEvents class. - - - -```swift -//you need to pass the [Group] object of the group which is created -CometChatGroupEvents.emitOnGroupCreate(group: Group) - -//you need to pass the [Group] object of the group which is deleted -CometChatGroupEvents.emitOnGroupDelete(group: Group) - -//emit this when logged in user leaves the group. -CometChatGroupEvents.emitOnGroupMemberLeave(leftUser: User, leftGroup: Group) - -//emit this when group member's scope is changed by logged in user. -CometChatGroupEvents.emitOnGroupMemberChangeScope(updatedBy: User , updatedUser: User , scopeChangedTo: CometChat.MemberScope , scopeChangedFrom: CometChat.MemberScope, group: Group) - -//emit this when group member is banned from the group by logged in user. -CometChatGroupEvents.emitOnGroupMemberBan(bannedUser: User, bannedGroup: Group, bannedBy: User) - -//emit this when group member is kicked from the group by logged in user. -CometChatGroupEvents.emitOnGroupMemberKick(kickedUser: User, kickedGroup: Group, kickedBy: User) - -//emit this when a banned group member is unbanned from group by logged in user. -CometChatGroupEvents.emitOnGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group, unbannedBy: User) - -//emit this when logged in user has joined a group successfully. -CometChatGroupEvents.emitOnGroupMemberJoin(joinedUser: User, joinedGroup: Group) - -//emit this when members are added to a group by the logged in user. -CometChatGroupEvents.emitOnGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) - -//emit this when ownership is changed by logged in user. -CometChatGroupEvents.emitOnGroupMemberChangeScope(updatedBy: User , updatedUser: User , scopeChangedTo: CometChat.MemberScope , scopeChangedFrom: CometChat.MemberScope, group: Group) -``` - - - - - -*** - -### Listening to Group Events - -Here we will go through how anyone can listen to these client-side Group Events to update the state of the UI accordingly. - -| Events | Description | -| -------------------------- | ---------------------------------------------------------------------------------------------------------- | -| `onGroupCreate` | This will get triggered when the logged in user creates a group | -| `onGroupDelete` | This will get triggered when the logged in user deletes a group | -| `onGroupMemberLeave` | This will get triggered when the logged in user leaves a group | -| `onGroupMemberChangeScope` | This will get triggered when the logged in user changes the scope of another group member | -| `onGroupMemberBan` | This will get triggered when the logged in user bans a group member from the group | -| `onGroupMemberKick` | This will get triggered when the logged in user kicks another group member from the group | -| `onGroupMemberUnban` | This will get triggered when the logged in user unbans a user banned from the group | -| `onGroupMemberJoin` | This will get triggered when the logged in user joins a group | -| `onGroupMemberAdd` | This will get triggered when the logged in user add new members to the group | -| `onOwnershipChange` | This will get triggered when the logged in user transfer the ownership of their group to some other member | - - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { - - public override func viewDidLoad() { - super.viewDidLoad() - - // Subscribing for the listener to listen events from user module - CometChatGroupEvents.addListener("UNIQUE_ID", self as CometChatGroupEventListener) - } - - public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module - CometChatGroupEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") - } - - -} - - // Listener events from groups module -extension ViewController: CometChatGroupEventListener { - - public func onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) { - // Do Stuff - } - - public func onCreateGroupClick() { - // Do Stuff - } - - public func onGroupCreate(group: Group) { - // Do Stuff - } - - public func onGroupDelete(group: Group) { - // Do Stuff - } - - public func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) { - // Do Stuff - } - - public func onGroupMemberLeave(leftUser: User, leftGroup: Group) { - // Do Stuff - } - - public func onGroupMemberBan(bannedUser: User, bannedGroup: Group) { - // Do Stuff - } - - public func onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group) { - // Do Stuff - } - - public func onGroupMemberKick(kickedUser: User, kickedGroup: Group) { - // Do Stuff - } - - public func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) { - // Do Stuff - } - - public func onOwnershipChange(group: Group?, member: GroupMember?) { - // Do Stuff - } -} -``` - - - - - -## Conversation Events - -CometChatConversationEvents emits events when the logged-in user executes some action on a conversation object - -It contains the following properties and methods: - -* `ccConversationDeleted`: Triggered when the logged-in user deletes a conversation. -* `ccUpdateConversation`: Triggered when there is an update in the conversation. - -### observer - -This is a List of Dictionary that contains components listening to user events in key value pairs - -### Type - -`[String: CometChatConversationEventListener]()` - -*** - -### addListener - -this method stores the passed listenerClass against the passed listenerId in the observer. - -### Signature - - - -```swift -addListener(_ id: String, _ observer: CometChatConversationEventListener) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | --------------------------- | ---------------------------------------------- | -| id | String | the key to store the component against | -| observer | CometChatConversationEvents | the component listening to conversation events | - -*** - -### removeListener - -this method removes the entry with the passed id from the observer. - -### Signature - - - -```swift -removeListener(_ id: String) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ------ | ------------------------------ | -| id | String | the key of the entry to remove | - -### Return Type - -`void` - -*** - -### Parameters - -| Parameters | Type | Description | -| ------------ | ------------ | ------------------------------ | -| conversation | Conversation | the user that has been deleted | - -*** - -### Emitting Conversation Events - -Here we will go through how to emit events specific to the UI Kit which listens for events emitted from the client side for actions made by the logged-in user. The code snippets shared below contains how to emit such client-side conversation events to inform other UI components in a project that a conversation has been deleted, the methods being used are static and hence they can be called without having to create an instance of CometChatConversationEvents class. - - - -```swift -//pass the conversation object you want to delete -CometChatConversationEvents.ccConversationDelete(conversation: Conversation) -CometChatConversationEvents.ccUpdateConversation(conversation: Conversation) -``` - - - - - -*** - -### Listening to Conversation Events - -Here we will go through how anyone can listen to these client-side Conversation Events to update the state of the UI accordingly. - -| Event | Description | -| ---------------------- | --------------------------------------------------------------------------- | -| `onConversationDelete` | This event will be triggered when the logged in user deletes a conversation | -| `ccUpdateConversation` | This event will be triggered when the logged in user updates a conversation | - - - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { - public override func viewDidLoad() { - super.viewDidLoad() - - // Subscribing for the listener to listen events from conversation module - CometChatConversationEvents.addListener("UNIQUE_ID", self as CometChatConversationEventListener) - } - - public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from conversation module - CometChatConversationEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") - } -} - - // Listener events from conversation module -extension ViewController: CometChatConversationEventListener { - - func ccConversationDeleted(conversation: Conversation) { - // Do stuff - } - - func ccUpdateConversation(conversation: Conversation) { - // Do stuff - } -} -``` - - - - - -## Message Events - -CometChatMessageEvents emits events when the logged-in user executes some action involving any message object. - -It contains the following properties and methods: - -### observer - -This is a List of Dictionary that contains components listening to message events in key value pairs - -### Type - -`[String: CometChatMessageEventListener]()` - -*** - -### addListener - -this method stores the passed listenerClass against the passed id in the observer. - -### Signature - - - -```swift -addListener(_ id: String,_ observer: CometChatMessageEventListener) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----------------------------- | ----------------------------------------- | -| id | String | the key to store the component against | -| observer | CometChatMessageEventListener | the component listening to message events | - -*** - -### removeListener - -this method removes the entry with the passed id from the observer. - -### Signature - - - -```swift -removeListener(_ id: String) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ------ | ------------------------------ | -| id | String | the key of the entry to remove | - -*** - -### onMessageSent - -This method is used to perform some task when the logged-in user has sent a message - -### Signature - - - -```swift -onMessageSent(message: BaseMessage, status: MessageStatus) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ------------- | ------------- | -------------------------------------------------------------------- | -| message | BaseMessage | the message that has been sent | -| messageStatus | MessageStatus | the status of the message, it can be `inProgress`, `sent` or `error` | - -*** - -### onMessageEdit - -This method is used to perform some task when the logged-in user has edited a message - -### Signature - - - -```swift -onMessageEdit(message: BaseMessage, status: MessageStatus) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ------------- | ----------------- | -------------------------------------------------------------- | -| message | BaseMessage | the message that has been sent | -| messageStatus | MessageEditStatus | the status of the message, it can be `inProgress` or `success` | - -*** - -### onMessageDelete - -This method is used to perform some task when the logged-in user has deleted a message - -### Signature - - - -```swift -onMessageDelete(message: BaseMessage) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ------------- | ----------- | -------------------------------------------------------------- | -| message | BaseMessage | the message that has been sent | -| messageStatus | EventStatus | the status of the message, it can be `inProgress` or `success` | - -*** - -### onMessageRead - -This method is used to perform some task when the logged-in user has read a message - -### Signature - - - -```swift -onMessageRead(message: BaseMessage) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ----------- | ------------------------------ | -| message | BaseMessage | the message that has been read | - -*** - -### onLiveReaction - -This method is used to perform some task when the logged-in user has a sent a transient message - -### Signature - - - -```swift -onLiveReaction(reaction: TransientMessage) -``` - - - - - -### Parameters - -| Parameters | Type | Description | -| ---------- | ---------------- | -------------------------------------- | -| reaction | TransientMessage | the image to send as transient message | - -*** - -### onViewInformation - -This method is used to perform some task when the logged-in user click on detail button. - -### Signature - - - -```swift -onViewInformation(group: Group) + +```json +{ + "category": "events", + "subscriptionPattern": { + "addListener": "CometChat{Category}Events.addListener(listenerId, self)", + "removeListener": "CometChat{Category}Events.removeListener(listenerId)" + }, + "eventCategories": [ + { + "name": "userEvents", + "listenerClass": "CometChatUserEvents", + "protocol": "CometChatUserEventListener", + "events": [ + {"name": "ccUserBlocked", "payload": "User", "description": "User was blocked"}, + {"name": "ccUserUnblocked", "payload": "User", "description": "User was unblocked"} + ] + }, + { + "name": "groupEvents", + "listenerClass": "CometChatGroupEvents", + "protocol": "CometChatGroupEventListener", + "events": [ + {"name": "ccGroupCreated", "payload": "Group", "description": "New group created"}, + {"name": "ccGroupDeleted", "payload": "Group", "description": "Group deleted"}, + {"name": "ccGroupMemberJoined", "payload": "(User, Group)", "description": "User joined group"}, + {"name": "ccGroupLeft", "payload": "(ActionMessage, User, Group)", "description": "User left group"}, + {"name": "ccGroupMemberKicked", "payload": "(ActionMessage, User, User, Group)", "description": "Member kicked"}, + {"name": "ccGroupMemberBanned", "payload": "(ActionMessage, User, User, Group)", "description": "Member banned"}, + {"name": "ccOwnershipChanged", "payload": "(Group, GroupMember)", "description": "Ownership transferred"} + ] + }, + { + "name": "conversationEvents", + "listenerClass": "CometChatConversationEvents", + "protocol": "CometChatConversationEventListener", + "events": [ + {"name": "ccConversationDeleted", "payload": "Conversation", "description": "Conversation deleted"}, + {"name": "ccUpdateConversation", "payload": "Conversation", "description": "Conversation updated"} + ] + }, + { + "name": "messageEvents", + "listenerClass": "CometChatMessageEvents", + "protocol": "CometChatMessageEventListener", + "events": [ + {"name": "onMessageSent", "payload": "(BaseMessage, MessageStatus)", "description": "Message sent"}, + {"name": "onMessageEdit", "payload": "(BaseMessage, MessageStatus)", "description": "Message edited"}, + {"name": "onMessageDelete", "payload": "(BaseMessage, MessageStatus)", "description": "Message deleted"}, + {"name": "onMessageRead", "payload": "BaseMessage", "description": "Message read"}, + {"name": "onMessageReact", "payload": "(BaseMessage, Reaction)", "description": "Reaction added"} + ] + }, + { + "name": "callEvents", + "listenerClass": "CometChatCallEvents", + "protocol": "CometChatCallEventListener", + "events": [ + {"name": "onCallInitiated", "payload": "Call", "description": "Outgoing call started"}, + {"name": "onCallEnded", "payload": "Call", "description": "Call ended"}, + {"name": "onIncomingCallAccepted", "payload": "Call", "description": "Incoming call accepted"}, + {"name": "onOutgoingCallAccepted", "payload": "Call", "description": "Outgoing call accepted"} + ] + } + ] +} ``` + - - - - -| Parameters | Type | Description | -| ---------- | ----- | -------------------------------------------------- | -| group | Group | the group for which the information has been shown | +Events allow different parts of your app to communicate without direct dependencies. When a user performs an action (like blocking someone, deleting a conversation, or sending a message), events are emitted so other components can react accordingly. -*** +## How Events Work -### onParentMessageUpdate +1. **Subscribe** to events using `addListener` in `viewDidLoad` +2. **React** to events in your listener callback methods +3. **Unsubscribe** using `removeListener` in `viewWillDisappear` -This method is used to perform some task when the logged-in user updates a message that has replies. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -### Signature - - - -```swift -onParentMessageUpdate(message: BaseMessage) +class MyViewController: UIViewController { + + private let listenerId = "my-unique-listener" + + override func viewDidLoad() { + super.viewDidLoad() + + // Subscribe to events + CometChatUserEvents.addListener(listenerId, self) + CometChatGroupEvents.addListener(listenerId, self) + CometChatConversationEvents.addListener(listenerId, self) + CometChatMessageEvents.addListener(listenerId, self) + CometChatCallEvents.addListener(listenerId, self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + // Unsubscribe to prevent memory leaks + CometChatUserEvents.removeListener(listenerId) + CometChatGroupEvents.removeListener(listenerId) + CometChatConversationEvents.removeListener(listenerId) + CometChatMessageEvents.removeListener(listenerId) + CometChatCallEvents.removeListener(listenerId) + } +} ``` - - - - -| Parameters | Type | Description | -| ---------- | ----------- | --------------------------------- | -| message | BaseMessage | the message that has been updated | - -*** - -### Emitting Message Events +## User Events -There are two types of message event listeners, one is for the SDK, which listens for events emitted from the backend for actions taken by users other than the logged in user; and second, the events specific to the UI Kit which listens for events emitted from the client side for actions made by the logged-in user. The code snippets shared below contains how to emit such client-side message events to inform other UI components in a project. +Listen for user-related actions like blocking and unblocking. - - -```swift -//emit this when the logged in user has sent a message. Pass the object of the [TextMessage], [MediaMessage] or [CustomMessage] being sent and the [MessageStatus] if [inProgress], [sent] successfully or failed with [error]*_ -CometChatMessageEvents.emitOnMessageSent(message: BaseMessage, status: MessageStatus) +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -//emit this for when a message is edited by logged-in user. Pass the object of the [TextMessage], [MediaMessage] or [CustomMessage] being edited and the [MessageEditStatus] if [inProgress] or [success]*_ -CometChatMessageEvents.emitOnMessageEdit(message: BaseMessage, status: MessageStatus) +class UserEventsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + CometChatUserEvents.addListener("user-listener", self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatUserEvents.removeListener("user-listener") + } +} -//emit this when a message is being deleted by logged-in user. Pass the object of the [TextMessage], [MediaMessage] or [CustomMessage] being deleted and also pass the [EventStatus] if [inProgress] or [success]*_ -CometChatMessageEvents.emitOnMessageDelete(message: BaseMessage) +extension UserEventsViewController: CometChatUserEventListener { + + func ccUserBlocked(user: User) { + print("Blocked: \(user.name ?? "")") + // Update UI - hide user from lists, disable messaging + } + + func ccUserUnblocked(user: User) { + print("Unblocked: \(user.name ?? "")") + // Update UI - show user in lists, enable messaging + } +} +``` -//emit this when a message is read by logged-in user. Pass the object of the [TextMessage], [MediaMessage] or [CustomMessage] being read*_ -CometChatMessageEvents.emitOnMessageRead(message: BaseMessage) +### Emit User Events -//emit this when a transient message is sent by logged-in user. Pass a [String] asset image of the Live Reaction to show in the animation*_ -CometChatMessageEvents.emitOnLiveReaction(reaction: TransientMessage) +Notify other components when you block/unblock a user: -//emit this when the logged in user clicked on detail icon.*_ -CometChatMessageEvents.emitOnViewInformation(user: User) +```swift lines +// After blocking a user +CometChatUserEvents.ccUserBlocked(user: blockedUser) -//emit this when the logged in user updates a message that contains replies.*_ -CometChatMessageEvents.emitOnParentMessageUpdate(message: BaseMessage) +// After unblocking a user +CometChatUserEvents.ccUserUnblocked(user: unblockedUser) ``` - - - +### User Events Reference -*** +| Event | Description | +|-------|-------------| +| `ccUserBlocked` | User was blocked by logged-in user | +| `ccUserUnblocked` | User was unblocked by logged-in user | -### Listening to Message Events - -Here we will go through how anyone can listen to these client-side Message Events to update the state of the UI accordingly. +## Group Events -| Events | Description | -| --------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| onMessageSent | Triggers whenever a loggedIn user sends any message, it will have two states such as: inProgress & sent | -| onMessageEdit | Triggers whenever a loggedIn user edits any message from the list of messages .it will have two states such as: inProgress & sent | -| onMessageDelete | Triggers whenever a loggedIn user deletes any message from the list of messages | -| onMessageRead | Triggers whenever a loggedIn user reads any message. | -| onLiveReaction | Triggers whenever a loggedIn user clicks on live reaction | -| onViewInformation | Triggers whenever a loggedIn user clicks on detail icon | -| onParentMessageUpdate | Triggers whenever a loggedIn user updates a message that contains replies. | +Listen for group-related actions like creating groups, adding members, and role changes. - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - public override func viewDidLoad() { +class GroupEventsViewController: UIViewController { + + override func viewDidLoad() { super.viewDidLoad() - - // Subscribing for the listener to listen events from message module - CometChatMessageEvents.addListener("UNIQUE_ID", self as CometChatMessageEventListener) + CometChatGroupEvents.addListener("group-listener", self) } - - public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from message module - CometChatMessageEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatGroupEvents.removeListener("group-listener") } - - } - // Listener events from message module -extension ViewController: CometChatMessageEventListener { - - func onMessageSent(message: BaseMessage, status: MessageStatus) { - // Do Stuff - } - - func onMessageEdit(message: BaseMessage, status: MessageStatus) { - // Do Stuff - } - - func onMessageDelete(message: BaseMessage, status: MessageStatus) { - // Do Stuff +extension GroupEventsViewController: CometChatGroupEventListener { + + // Group lifecycle + func onGroupCreate(group: Group) { + print("Group created: \(group.name ?? "")") } - - func onMessageReply(message: BaseMessage, status: MessageStatus) { - // Do Stuff + + func onGroupDelete(group: Group) { + print("Group deleted: \(group.name ?? "")") } - - func onMessageRead(message: BaseMessage) { - // Do Stuff + + func onCreateGroupClick() { + print("Create group button tapped") } - - func onLiveReaction(reaction: TransientMessage) { - // Do Stuff + + // Member join/leave + func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) { + print("\(joinedUser.name ?? "") joined \(joinedGroup.name ?? "")") } - - func onMessageError(error: CometChatException) { - // Do Stuff + + func onGroupMemberLeave(leftUser: User, leftGroup: Group) { + print("\(leftUser.name ?? "") left \(leftGroup.name ?? "")") } - - func onVoiceCall(user: User) { - // Do Stuff + + func onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) { + print("\(members.count) members added to \(group.name ?? "")") } - - func onVoiceCall(group: Group) { - // Do Stuff + + // Moderation + func onGroupMemberKick(kickedUser: User, kickedGroup: Group) { + print("\(kickedUser.name ?? "") kicked from \(kickedGroup.name ?? "")") } - - func onVideoCall(user: User) { - // Do Stuff + + func onGroupMemberBan(bannedUser: User, bannedGroup: Group) { + print("\(bannedUser.name ?? "") banned from \(bannedGroup.name ?? "")") } - - func onVideoCall(group: Group) { - // Do Stuff + + func onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group) { + print("\(unbannedUserUser.name ?? "") unbanned") } - - func onViewInformation(user: User) { - // Do Stuff + + // Role changes + func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) { + print("\(updatedUser.name ?? "") role: \(scopeChangedFrom) → \(scopeChangedTo)") } - - func onMessageReact(message: BaseMessage, reaction: CometChatMessageReaction) { - // Do Stuff + + func onOwnershipChange(group: Group?, member: GroupMember?) { + print("Ownership transferred to \(member?.name ?? "")") } - } ``` - - - - -## Call Events - -CometChatCallEvents emits events when the logged-in user executes some action involving any call object. +### Emit Group Events -It contains the following properties and methods: +Notify other components about group actions: -### observer +```swift lines +// Group created +CometChatGroupEvents.emitOnGroupCreate(group: newGroup) -This is a List of Dictionary that contains components listening to call events in key value pairs +// Group deleted +CometChatGroupEvents.emitOnGroupDelete(group: deletedGroup) -### Type +// Member joined +CometChatGroupEvents.emitOnGroupMemberJoin(joinedUser: user, joinedGroup: group) -`[String:`CometChatCallEventListener]\() +// Member left +CometChatGroupEvents.emitOnGroupMemberLeave(leftUser: user, leftGroup: group) -*** +// Members added +CometChatGroupEvents.emitOnGroupMemberAdd(group: group, members: newMembers, addedBy: currentUser) -### addListener +// Member kicked +CometChatGroupEvents.emitOnGroupMemberKick(kickedUser: user, kickedGroup: group, kickedBy: admin) -This method stores the passed listenerClass against the passed id in the addListener. +// Member banned +CometChatGroupEvents.emitOnGroupMemberBan(bannedUser: user, bannedGroup: group, bannedBy: admin) -### Signature +// Member unbanned +CometChatGroupEvents.emitOnGroupMemberUnban(unbannedUserUser: user, unbannedUserGroup: group, unbannedBy: admin) - - -```swift -addListener(_ id: String,_ observer: CometChatCallEventListener) +// Role changed +CometChatGroupEvents.emitOnGroupMemberChangeScope( + updatedBy: admin, + updatedUser: member, + scopeChangedTo: .admin, + scopeChangedFrom: .participant, + group: group +) ``` - - - +### Group Events Reference -| Parameters | Type | Description | -| ---------- | -------------------------- | -------------------------------------- | -| id | String | the key to store the component against | -| observer | CometChatCallEventListener | the component listening to call events | +| Event | Description | +|-------|-------------| +| `onGroupCreate` | New group created | +| `onGroupDelete` | Group deleted | +| `onCreateGroupClick` | Create group button tapped | +| `onGroupMemberJoin` | User joined a group | +| `onGroupMemberLeave` | User left a group | +| `onGroupMemberAdd` | Members added to group | +| `onGroupMemberKick` | Member kicked from group | +| `onGroupMemberBan` | Member banned from group | +| `onGroupMemberUnban` | Member unbanned | +| `onGroupMemberChangeScope` | Member role changed | +| `onOwnershipChange` | Group ownership transferred | -*** +## Conversation Events -### removeListener +Listen for conversation-level actions like delete and update. -This method removes the entry with the passed id from the observer. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -### Signature +class ConversationEventsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + CometChatConversationEvents.addListener("conversation-listener", self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatConversationEvents.removeListener("conversation-listener") + } +} - - -```swift -removeListener(_ id: String) +extension ConversationEventsViewController: CometChatConversationEventListener { + + func ccConversationDeleted(conversation: Conversation) { + print("Conversation deleted: \(conversation.conversationId ?? "")") + // Remove from local list, update UI + } + + func ccUpdateConversation(conversation: Conversation) { + print("Conversation updated: \(conversation.conversationId ?? "")") + // Refresh conversation data in UI + } +} ``` - - - - -| Parameter | Type | Description | -| --------- | ------ | ------------------------------ | -| id | String | the key of the entry to remove | - -*** - -### onIncomingCallAccepted +### Emit Conversation Events -This method is used to perform some task when the logged-in user accepts the incoming call +```swift lines +// Conversation deleted +CometChatConversationEvents.ccConversationDelete(conversation: deletedConversation) -### Signature - - - -```swift -onIncomingCallAccepted(call: Call) +// Conversation updated +CometChatConversationEvents.ccUpdateConversation(conversation: updatedConversation) ``` - - - +### Conversation Events Reference -| Parameters | Type | Description | -| ---------- | ---- | ------------------------------- | -| call | Call | the call that has been accepted | +| Event | Description | +|-------|-------------| +| `ccConversationDeleted` | Conversation was deleted | +| `ccUpdateConversation` | Conversation was updated | -*** +## Message Events -### onIncomingCallRejected +Listen for message-related actions like send, edit, delete, and reactions. -This method is used to perform some task when the logged-in user rejects the incoming call +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -### Signature +class MessageEventsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + CometChatMessageEvents.addListener("message-listener", self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatMessageEvents.removeListener("message-listener") + } +} - - -```swift -onIncomingCallRejected(call: Call) +extension MessageEventsViewController: CometChatMessageEventListener { + + // Message lifecycle + func onMessageSent(message: BaseMessage, status: MessageStatus) { + switch status { + case .inProgress: + print("Sending...") + case .success: + print("Message sent: \(message.id)") + case .error: + print("Send failed") + @unknown default: + break + } + } + + func onMessageEdit(message: BaseMessage, status: MessageStatus) { + print("Message edited: \(message.id)") + } + + func onMessageDelete(message: BaseMessage, status: MessageStatus) { + print("Message deleted: \(message.id)") + } + + func onMessageRead(message: BaseMessage) { + print("Message read: \(message.id)") + } + + func onMessageReply(message: BaseMessage, status: MessageStatus) { + print("Reply sent to: \(message.id)") + } + + // Reactions + func onMessageReact(message: BaseMessage, reaction: CometChatMessageReaction) { + print("Reaction: \(reaction.reaction ?? "")") + } + + func onLiveReaction(reaction: TransientMessage) { + print("Live reaction received") + } + + // Thread updates + func onParentMessageUpdate(message: BaseMessage) { + print("Thread parent updated: \(message.id)") + } + + // Navigation + func onViewInformation(user: User) { + print("View user info: \(user.name ?? "")") + } + + func onViewInformation(group: Group) { + print("View group info: \(group.name ?? "")") + } + + // Calls from message screen + func onVoiceCall(user: User) { + print("Voice call to: \(user.name ?? "")") + } + + func onVideoCall(user: User) { + print("Video call to: \(user.name ?? "")") + } + + func onVoiceCall(group: Group) { + print("Group voice call: \(group.name ?? "")") + } + + func onVideoCall(group: Group) { + print("Group video call: \(group.name ?? "")") + } + + // Errors + func onMessageError(error: CometChatException) { + print("Error: \(error.errorDescription)") + } +} ``` - +### Emit Message Events - +```swift lines +// Message sent (with status) +CometChatMessageEvents.emitOnMessageSent(message: sentMessage, status: .success) -| Parameters | Type | Description | -| ---------- | ---- | ------------------------------- | -| call | Call | the call that has been rejected | +// Message edited +CometChatMessageEvents.emitOnMessageEdit(message: editedMessage, status: .success) -*** +// Message deleted +CometChatMessageEvents.emitOnMessageDelete(message: deletedMessage) -### onCallInitiated +// Message read +CometChatMessageEvents.emitOnMessageRead(message: readMessage) -This method is used to perform some task when the logged-in user initiates a call +// Live reaction +CometChatMessageEvents.emitOnLiveReaction(reaction: transientMessage) -### Signature +// View user/group info +CometChatMessageEvents.emitOnViewInformation(user: selectedUser) - - -```swift -onCallInitiated(call: Call) +// Thread parent updated +CometChatMessageEvents.emitOnParentMessageUpdate(message: parentMessage) ``` - +### Message Events Reference - +| Event | Description | +|-------|-------------| +| `onMessageSent` | Message sent (inProgress, success, or error) | +| `onMessageEdit` | Message edited | +| `onMessageDelete` | Message deleted | +| `onMessageRead` | Message marked as read | +| `onMessageReply` | Reply sent to a message | +| `onMessageReact` | Reaction added to message | +| `onLiveReaction` | Live reaction sent | +| `onParentMessageUpdate` | Thread parent message updated | +| `onViewInformation` | Info button tapped (user or group) | +| `onVoiceCall` | Voice call initiated | +| `onVideoCall` | Video call initiated | +| `onMessageError` | Message operation failed | -| Parameters | Type | Description | -| ---------- | ---- | -------------------------------- | -| call | Call | the call that has been initiated | - -*** +## Call Events -### onCallEnded +Listen for call-related actions like initiating, accepting, and ending calls. -This method is used to perform some task when the ongoing or outgoing call ends. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -### Signature +class CallEventsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + CometChatCallEvents.addListener("call-listener", self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatCallEvents.removeListener("call-listener") + } +} - - -```swift -onCallEnded(call: Call) +extension CallEventsViewController: CometChatCallEventListener { + + // Outgoing calls + func onCallInitiated(call: Call) { + print("Calling: \(call.receiverUid)") + } + + func onOutgoingCallAccepted(call: Call) { + print("Call accepted by recipient") + } + + func onOutgoingCallRejected(call: Call) { + print("Call rejected by recipient") + } + + // Incoming calls + func onIncomingCallAccepted(call: Call) { + print("You accepted the call") + } + + func onIncomingCallRejected(call: Call) { + print("You rejected the call") + } + + // Call ended + func onCallEnded(call: Call) { + print("Call ended") + } +} ``` - +### Emit Call Events - +```swift lines +// Call initiated +CometChatCallEvents.emitOnCallInitiated(call: outgoingCall) -| Parameters | Type | Description | -| ---------- | ---- | ---------------------------- | -| call | Call | the call that has been ended | +// Call ended +CometChatCallEvents.emitOnCallEnded(call: endedCall) -*** +// Incoming call accepted +CometChatCallEvents.emitOnIncomingCallAccepted(call: acceptedCall) -### onOutgoingCallAccepted +// Incoming call rejected +CometChatCallEvents.emitOnIncomingCallRejected(call: rejectedCall) -This method is used to perform some task when the outgoing call is accepted. +// Outgoing call accepted +CometChatCallEvents.emitOnOutgoingCallAccepted(call: acceptedCall) -### Signature - - - -```swift -onOutgoingCallAccepted(call: Call) +// Outgoing call rejected +CometChatCallEvents.emitOnOutgoingCallRejected(call: rejectedCall) ``` - - - - -| Parameters | Type | Description | -| ---------- | ---- | -------------------------------------------------- | -| call | Call | the call that has been accepted by the other user. | - -*** +### Call Events Reference -### onOutgoingCallRejected +| Event | Description | +|-------|-------------| +| `onCallInitiated` | Outgoing call started | +| `onOutgoingCallAccepted` | Recipient accepted the call | +| `onOutgoingCallRejected` | Recipient rejected the call | +| `onIncomingCallAccepted` | You accepted an incoming call | +| `onIncomingCallRejected` | You rejected an incoming call | +| `onCallEnded` | Call ended (any reason) | -This method is used to perform some task when the outgoing call is rejected. +## Complete Example: App-Wide Event Manager -### Signature +Create a centralized event manager to handle events across your entire app: - - -```swift -onOutgoingCallRejected(call: Call) -``` - - - - - -| Parameters | Type | Description | -| ---------- | ---- | -------------------------------------------------- | -| call | Call | the call that has been rejected by the other user. | +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -*** - -### Emitting Call Events +// MARK: - Singleton Event Manager +class ChatEventManager { + + static let shared = ChatEventManager() + private let listenerId = "app-event-manager" + + private init() {} + + func startListening() { + CometChatUserEvents.addListener(listenerId, self) + CometChatGroupEvents.addListener(listenerId, self) + CometChatConversationEvents.addListener(listenerId, self) + CometChatMessageEvents.addListener(listenerId, self) + CometChatCallEvents.addListener(listenerId, self) + } + + func stopListening() { + CometChatUserEvents.removeListener(listenerId) + CometChatGroupEvents.removeListener(listenerId) + CometChatConversationEvents.removeListener(listenerId) + CometChatMessageEvents.removeListener(listenerId) + CometChatCallEvents.removeListener(listenerId) + } +} -There are two types of call event listeners, one for the SDK, which listens for events emitted from the backend for actions taken by users other than the logged-in user; and another for events specific to the UI Kit, which listens for events emitted from the client side for actions made by the logged-in user. The code snippets shared below contain how to emit such client-side call events to inform other UI components in a project. +// MARK: - User Events +extension ChatEventManager: CometChatUserEventListener { + func onUserBlock(user: User) { + NotificationCenter.default.post(name: .userBlocked, object: user) + } + + func onUserUnblock(user: User) { + NotificationCenter.default.post(name: .userUnblocked, object: user) + } +} - - -```swift -//emit this when logged in user initiates a call -CometChatCallEvents.emitOnCallInitiated(call: Call) +// MARK: - Group Events +extension ChatEventManager: CometChatGroupEventListener { + func onGroupCreate(group: Group) { + NotificationCenter.default.post(name: .groupCreated, object: group) + } + + func onGroupDelete(group: Group) { + NotificationCenter.default.post(name: .groupDeleted, object: group) + } + + func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) { + NotificationCenter.default.post(name: .memberJoined, object: nil, + userInfo: ["user": joinedUser, "group": joinedGroup]) + } + + func onGroupMemberLeave(leftUser: User, leftGroup: Group) { + NotificationCenter.default.post(name: .memberLeft, object: nil, + userInfo: ["user": leftUser, "group": leftGroup]) + } + + // Implement other required methods... + func onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) {} + func onGroupMemberKick(kickedUser: User, kickedGroup: Group) {} + func onGroupMemberBan(bannedUser: User, bannedGroup: Group) {} + func onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group) {} + func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) {} + func onOwnershipChange(group: Group?, member: GroupMember?) {} + func onCreateGroupClick() {} +} -//emit this when logged in user cancels a call -CometChatCallEvents.emitOnCallEnded(call: Call) +// MARK: - Conversation Events +extension ChatEventManager: CometChatConversationEventListener { + func ccConversationDeleted(conversation: Conversation) { + NotificationCenter.default.post(name: .conversationDeleted, object: conversation) + } + + func ccUpdateConversation(conversation: Conversation) { + NotificationCenter.default.post(name: .conversationUpdated, object: conversation) + } +} -//emit this when logged in user accepts the incoming call -CometChatCallEvents.emitOnIncomingCallAccepted(call: Call) +// MARK: - Message Events +extension ChatEventManager: CometChatMessageEventListener { + func onMessageSent(message: BaseMessage, status: MessageStatus) { + if status == .success { + NotificationCenter.default.post(name: .messageSent, object: message) + } + } + + // Implement other required methods... + func onMessageEdit(message: BaseMessage, status: MessageStatus) {} + func onMessageDelete(message: BaseMessage, status: MessageStatus) {} + func onMessageRead(message: BaseMessage) {} + func onLiveReaction(reaction: TransientMessage) {} + func onMessageReact(message: BaseMessage, reaction: CometChatMessageReaction) {} + func onParentMessageUpdate(message: BaseMessage) {} + func onViewInformation(user: User) {} + func onViewInformation(group: Group) {} + func onVoiceCall(user: User) {} + func onVideoCall(user: User) {} + func onVoiceCall(group: Group) {} + func onVideoCall(group: Group) {} + func onMessageError(error: CometChatException) {} + func onMessageReply(message: BaseMessage, status: MessageStatus) {} +} -//emit this when logged in user rejects the incoming call -CometChatCallEvents.emitOnIncomingCallRejected(call: Call) -//emit this when the other user accepts the call -CometChatCallEvents.emitOnOutgoingCallAccepted(call: Call) +// MARK: - Call Events +extension ChatEventManager: CometChatCallEventListener { + func onCallInitiated(call: Call) { + NotificationCenter.default.post(name: .callStarted, object: call) + } + + func onCallEnded(call: Call) { + NotificationCenter.default.post(name: .callEnded, object: call) + } + + func onIncomingCallAccepted(call: Call) {} + func onIncomingCallRejected(call: Call) {} + func onOutgoingCallAccepted(call: Call) {} + func onOutgoingCallRejected(call: Call) {} +} -//emit this when the other user rejects a call -CometChatCallEvents.emitOnOutgoingCallRejected(call: Call) +// MARK: - Notification Names +extension Notification.Name { + static let userBlocked = Notification.Name("userBlocked") + static let userUnblocked = Notification.Name("userUnblocked") + static let groupCreated = Notification.Name("groupCreated") + static let groupDeleted = Notification.Name("groupDeleted") + static let memberJoined = Notification.Name("memberJoined") + static let memberLeft = Notification.Name("memberLeft") + static let conversationDeleted = Notification.Name("conversationDeleted") + static let conversationUpdated = Notification.Name("conversationUpdated") + static let messageSent = Notification.Name("messageSent") + static let callStarted = Notification.Name("callStarted") + static let callEnded = Notification.Name("callEnded") +} ``` - - - +### Using the Event Manager -### Listening to Call Events - -Here we will go through how anyone can listen to these client-side Call Events to update the state of the UI accordingly. - -| Event | Description | -| ---------------------- | ------------------------------------------------------- | -| onIncomingCallAccepted | Triggers whenever incoming call is accepted by the user | -| onIncomingCallRejected | Triggers whenever incoming call is rejected by the user | -| onCallEnded | Triggers whenever the call is ended | -| onCallInitiated | Triggers whenever the call is getting initiated | -| onOutgoingCallAccepted | Triggers whenever outgoing call is accepted by the user | -| onOutgoingCallRejected | Triggers whenever outgoing call is rejected by the user | - - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { +```swift lines +// AppDelegate.swift +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + // Start listening for events app-wide + ChatEventManager.shared.startListening() + + return true + } +} - public override func viewDidLoad() { +// Any ViewController +class MyViewController: UIViewController { + + override func viewDidLoad() { super.viewDidLoad() - - // Subscribing for the listener to listen events from user module - CometChatCallEvents.addListener("UNIQUE_ID", self as CometChatCallEventListener) + + // Listen for specific events via NotificationCenter + NotificationCenter.default.addObserver( + self, + selector: #selector(handleUserBlocked), + name: .userBlocked, + object: nil + ) } - - public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module - CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") + + @objc private func handleUserBlocked(_ notification: Notification) { + guard let user = notification.object as? User else { return } + print("User blocked: \(user.name ?? "")") + // Update your UI + } + + deinit { + NotificationCenter.default.removeObserver(self) } - - } +``` - // Listener events from user module -extension ViewController: CometChatCallEventListener { +## Best Practices - func onIncomingCallAccepted(call: Call) { - // Do Stuff - } +1. **Always remove listeners** - Call `removeListener` in `viewWillDisappear` to prevent memory leaks - func onIncomingCallRejected(call: Call) - // Do Stuff - } +2. **Use unique listener IDs** - Avoid conflicts between components by using descriptive, unique IDs - func onCallEnded(call: Call) { - // Do Stuff - } +3. **Update UI on main thread** - Dispatch UI updates to the main thread when handling events - func onCallInitiated(call: Call) - // Do Stuff - } +4. **Don't emit unnecessarily** - Only emit events when state actually changes - func onOutgoingCallAccepted(call: Call) { - // Do Stuff - } +5. **Use a central manager** - For app-wide event handling, create a singleton manager - func onOutgoingCallRejected(call: Call) - // Do Stuff - } -} -``` +--- - +## Next Steps + + + + Reference for UI Kit wrapper methods. + + + Display and customize chat messages. + + + Manage conversation lists. + + + Work with group chat functionality. + + - +--- diff --git a/ui-kit/ios/extensions.mdx b/ui-kit/ios/extensions.mdx index fef6939e0..399619aa3 100644 --- a/ui-kit/ios/extensions.mdx +++ b/ui-kit/ios/extensions.mdx @@ -1,131 +1,200 @@ --- title: "Extensions" +description: "Enable powerful chat features with zero code using CometChat extensions" --- -## Overview +| Field | Value | +|-------|-------| +| Dashboard setup | CometChat Dashboard → Extensions | +| Activation | Enable in dashboard, features appear automatically in UI Kit | +| Code required | None — extensions work out of the box | +| Platforms | Works across iOS, Android, and Web with the same configuration | -CometChat’s UI Kit comes with built-in support for a wide variety of extensions that provide additional functionality. These extensions enhance the chatting experience, making it more interactive, secure, and efficient. +Extensions add powerful features to your chat app without writing any code. Simply enable them in your [CometChat Dashboard](https://app.cometchat.com), and they automatically appear in the UI Kit components. -Activating any of the extensions in CometChat is a simple process done through your application's dashboard. Refer to our guide For detailed information on [Extensions](/fundamentals/extensions-overview) +## How Extensions Work -Once you have successfully enabled the desired extension in your dashboard, it will be reflected in your CometChat application upon initialization and successful login. Please note, that the extension features will only be available if they are supported by CometChat UI Kit. +1. Log in to your [CometChat Dashboard](https://app.cometchat.com) +2. Navigate to the **Extensions** section +3. Enable the extensions you want +4. The features automatically appear in your app after initialization -CometChat’s UI Kit offers built-in support for 12 powerful extensions. This seamless integration makes it easy for you to enhance your chat application with engaging features without any extra coding effort. Just enable the desired extensions from the CometChat Dashboard, and they will be automatically reflected in the relevant components of your application, providing a richer and more engaging experience for your users. + +Extensions are enabled at the dashboard level. Once activated, they work across all platforms (iOS, Android, Web) using the same CometChat app. + -## Built-in Extensions +## Composer Extensions -Here's a guide on how you can enable and integrate these extensions: +These extensions add new options to the [Message Composer](/ui-kit/ios/message-composer) attachment menu or action sheet. ### Stickers -The Stickers extension allows users to express their emotions more creatively. It adds a much-needed fun element to the chat by allowing users to send various pre-designed stickers. For a comprehensive understanding and guide on implementing and using the Sticker Extension, refer to our specific guide on the [Sticker Extension](/fundamentals/stickers). - -Once you have successfully activated the [Sticker Extension](/fundamentals/stickers) from your CometChat Dashboard, the feature will automatically be incorporated into the [Message Composer](/ui-kit/ios/message-composer) component of UI Kits. +Let users express emotions with fun, pre-designed stickers. -### Polls +| Component | Setup Guide | +|-----------|-------------| +| [Message Composer](/ui-kit/ios/message-composer) | [Sticker Extension](/fundamentals/stickers) | -The Polls extension enhances group discussions by allowing users to create polls. Users can ask questions with a predefined list of answers, enabling a quick, organized way to gather group opinions. For a comprehensive understanding and guide on implementing and using the Polls Extension, refer to our specific guide on the [Polls Extension](/fundamentals/polls). +### Polls -Once you have successfully activated the [Polls Extension](/fundamentals/polls) from your CometChat Dashboard, the feature will automatically be incorporated into the Action Sheet of the [Message Composer](/ui-kit/ios/message-composer) component of UI Kits. +Create polls to gather opinions in group chats quickly. -### Collaborative Whiteboard +| Component | Setup Guide | +|-----------|-------------| +| [Message Composer](/ui-kit/ios/message-composer) | [Polls Extension](/fundamentals/polls) | -The Collaborative Whiteboard extension facilitates real-time collaboration. Users can draw, brainstorm, and share ideas on a shared digital whiteboard. For a comprehensive understanding and guide on implementing and using the Collaborative Whiteboard Extension, refer to our specific guide on the [Collaborative Whiteboard Extension](/fundamentals/collaborative-whiteboard). +### Collaborative Whiteboard -Once you have successfully activated the [Collaborative Whiteboard Extension](/fundamentals/collaborative-whiteboard) from your CometChat Dashboard, the feature will automatically be incorporated into the Action Sheet of the [Message Composer](/ui-kit/ios/message-composer) component of UI Kits. +Real-time whiteboard for drawing, brainstorming, and sharing ideas together. -### Collaborative Document +| Component | Setup Guide | +|-----------|-------------| +| [Message Composer](/ui-kit/ios/message-composer) | [Collaborative Whiteboard](/fundamentals/collaborative-whiteboard) | -With the Collaborative Document extension, users can work together on a shared document. This feature is essential for remote teams where document collaboration is a recurring requirement. For a comprehensive understanding and guide on implementing and using the Collaborative Document Extension, refer to our specific guide on the [Collaborative Document Extension](/fundamentals/collaborative-document). +### Collaborative Document -Once you have successfully activated the [Collaborative Document Extension](/fundamentals/collaborative-document) from your CometChat Dashboard, the feature will automatically be incorporated into the Action Sheet of the [Message Composer](/ui-kit/ios/message-composer) component of UI Kits. +Work together on shared documents in real-time with other users. -### Message Reactions +| Component | Setup Guide | +|-----------|-------------| +| [Message Composer](/ui-kit/ios/message-composer) | [Collaborative Document](/fundamentals/collaborative-document) | + +### Smart Replies -Message Reactions extension lets users express their emotions towards a message by choosing from a range of emojis. It provides a quick way to respond to any shared message. For a comprehensive understanding and guide on implementing and using the Message Reactions Extension, refer to our specific guide on the [Message Reactions Extension](/fundamentals/reactions). +AI-powered suggested responses for faster, more efficient conversations. -Once you have successfully activated the [Message Reactions Extension](/fundamentals/reactions) from your CometChat Dashboard, the feature will automatically be incorporated into the Action Sheet of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +| Component | Setup Guide | +|-----------|-------------| +| [Message Composer](/ui-kit/ios/message-composer) | [Smart Replies](/fundamentals/smart-replies) | + +## Message List Extensions + +These extensions enhance messages displayed in the [Message List](/ui-kit/ios/message-list). + +### Message Reactions + +Let users react to messages with a range of emojis for quick responses. -### Message Translation +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Reactions Extension](/fundamentals/reactions) | -The Message Translation extension in CometChat is designed to translate any message into your local. It eliminates language barriers, making the chat more inclusive. For a comprehensive understanding and guide on implementing and using the Message Translation Extension, refer to our specific guide on the [Message Translation Extension](/fundamentals/message-translation). +### Message Translation -Once you have successfully activated the [Message Translation Extension](/fundamentals/message-translation) from your CometChat Dashboard, the feature will automatically be incorporated into the Action Sheet of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Translate messages into any language instantly, eliminating language barriers. -### Link Preview +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Message Translation](/fundamentals/message-translation) | -The Link Preview extension provides a summary of the URL shared in the chat. It includes the title, a description, and a thumbnail image from the web page. For a comprehensive understanding and guide on implementing and using the Link Preview Extension, refer to our specific guide on the [Link Preview Extension](/fundamentals/link-preview). +### Link Preview -Once you have successfully activated the [Link Preview Extension](/fundamentals/link-preview) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Show rich previews for URLs shared in chat including title, description, and thumbnail. -### Profanity Filter +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Link Preview](/fundamentals/link-preview) | -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). +### Thumbnail Generation -Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Automatically create smaller preview images for faster loading and reduced bandwidth. - + -### Data Masking +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Thumbnail Generation](/fundamentals/thumbnail-generation) | + +## Moderation Extensions -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). +These extensions help maintain a safe chat environment by filtering content automatically. -Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +### Profanity Filter + +Automatically censor inappropriate and obscene words in messages. - + -### Image Moderation +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Legacy Extensions](/moderation/legacy-extensions) | -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). +### Data Masking -Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Automatically mask sensitive data like credit card numbers and phone numbers. - + -### Thumbnail Generation +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Legacy Extensions](/moderation/legacy-extensions) | -The Thumbnail Generation extension automatically creates a smaller preview image whenever a larger image is shared, helping to reduce the upload/download time and bandwidth usage. For a comprehensive understanding and guide on implementing and using the Thumbnail Generation Extension, refer to our specific guide on the [Thumbnail Generation Extension](/fundamentals/thumbnail-generation). +### Image Moderation -Once you have successfully activated the [Thumbnail Generation Extension](/fundamentals/thumbnail-generation) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Detect and filter inappropriate or explicit images using AI/ML. - + -### Smart Replies - -Smart Replies extension provides automated, predictive text responses, making the conversation more efficient by reducing the response time. For a comprehensive understanding and guide on implementing and using the Smart Replies Extension, refer to our specific guide on the [Smart Replies Extension](/fundamentals/smart-replies). +| Component | Setup Guide | +|-----------|-------------| +| [Message List](/ui-kit/ios/message-list) | [Legacy Extensions](/moderation/legacy-extensions) | + +## Extensions Summary + +| Extension | Category | Component | Use Case | +|-----------|----------|-----------|----------| +| Stickers | Composer | Message Composer | Fun expression | +| Polls | Composer | Message Composer | Group decisions | +| Whiteboard | Composer | Message Composer | Visual collaboration | +| Document | Composer | Message Composer | Document collaboration | +| Smart Replies | Composer | Message Composer | Quick responses | +| Reactions | Message List | Message List | Quick responses | +| Translation | Message List | Message List | Multi-language support | +| Link Preview | Message List | Message List | Rich URL previews | +| Thumbnails | Message List | Message List | Faster loading | +| Profanity Filter | Moderation | Message List | Content moderation | +| Data Masking | Moderation | Message List | Privacy protection | +| Image Moderation | Moderation | Message List | Safe content | + +## Next Steps + +- [Extensions Overview](/fundamentals/extensions-overview) — Full extension documentation +- [Moderation](/moderation/overview) — Content moderation features +- [Message Composer](/ui-kit/ios/message-composer) — Where composer extensions appear +- [Message List](/ui-kit/ios/message-list) — Where message extensions appear diff --git a/ui-kit/ios/getting-started.mdx b/ui-kit/ios/getting-started.mdx index 0fabda03d..1d938dc54 100644 --- a/ui-kit/ios/getting-started.mdx +++ b/ui-kit/ios/getting-started.mdx @@ -1,448 +1,344 @@ --- -title: "Getting Started With CometChat iOS UI Kit" +title: "iOS Integration" sidebarTitle: "Integration" +description: "Add CometChat to an iOS app in 5 steps: create project, install, init, login, render." --- -The **CometChat UI Kit for iOS** streamlines the integration of in-app chat functionality by providing a **comprehensive set of prebuilt UI elements**. It offers seamless **theming options**, including **light and dark modes**, customizable fonts, colors, and extensive styling capabilities. + -With built-in support for **one-to-one and group conversations**, developers can efficiently enable chat features within their applications. Follow this guide to **quickly integrate chat functionality** using the CometChat iOS UI Kit. +| Field | Value | +| --- | --- | +| Package | `CometChatUIKitSwift` | +| Version | `5.1.9` | +| Requirements | Xcode 16+, iOS 13.0+, Swift 5.0+ | +| Init | `CometChatUIKit.init(uiKitSettings:)` — must complete before `login()` | +| Login | `CometChatUIKit.login(uid:)` — must complete before rendering components | +| Order | `init()` → `login()` → render. Breaking this order = blank screen | +| Auth Key | Dev/testing only. Use Auth Token in production | +| Calling | Optional. Install `CometChatCallsSDK 4.2.2` to enable | +| Dependencies | `CometChatSDK 4.1.0` (installed automatically) | + + + +This guide walks you through adding CometChat to an iOS app. By the end you'll have a working chat UI. -*** - -## **Prerequisites** - -Before installing the **CometChat UI Kit for iOS**, you must first **create a CometChat application** via the **[CometChat Dashboard](https://app.cometchat.com/)**. The dashboard provides all the essential chat service components, including: - -* **User Management** -* **Group Chat & Messaging** -* **Voice & Video Calling** -* **Real-time Notifications** - - - -To initialize the **UI Kit**, you will need the following credentials from your **CometChat application**: - -1. **App ID** -2. **Auth Key** -3. **Region** - -Ensure you have these details ready before proceeding with the installation and configuration. - - - -*** - -## **Register & Set Up CometChat** - -Follow these steps to **register on CometChat** and **set up your development environment**. - -### **Step 1: Register on CometChat** - -To use **CometChat UI Kit**, you first need to register on the **CometChat Dashboard**. - -🔗 **[Click here to Sign Up](https://app.cometchat.com/login)** - -### **Step 2: Get Your Application Keys** - -After registering, create a **new app** and retrieve your **authentication details**: - -1. Navigate to the **QuickStart** or **API & Auth Keys section**. - -2. Note down the following keys: - - * **App ID** - * **Auth Key** - * **Region** - - - -Each CometChat application can be integrated with a **single client app**. Users within the same application can communicate across multiple platforms, including **web and mobile**. - - - -### **Step 3: Set Up Your Development Environment** +--- -Ensure your system meets the following **prerequisites** before proceeding with integration. +## Prerequisites -**System Requirements:** +You need three things from the [CometChat Dashboard](https://app.cometchat.com/): -* **Xcode 16 or later** installed on your machine. -* An **iOS device or simulator** with iOS version 13.0 or above. -* **Swift 5.0**. -* **macOS**. +| Credential | Where to find it | +| --- | --- | +| App ID | Dashboard → Your App → Credentials | +| Auth Key | Dashboard → Your App → Credentials | +| Region | Dashboard → Your App → Credentials (e.g. `us`, `eu`, `in`) | -*** +You also need: +- Xcode 16 or later +- iOS device or simulator running iOS 13.0+ +- Swift 5.0+ +- macOS -## **Integration Steps** + +Auth Key is for development only. In production, generate Auth Tokens server-side via the [REST API](https://api-explorer.cometchat.com/) and use [`loginWithAuthToken()`](/ui-kit/ios/methods#login-using-auth-token). Never ship Auth Keys in client code. + -### **Create an iOS Project** +--- -To get started, open Xcode and create a new project for UI Kit in the Project window as follows: +## Step 1 — Create an iOS Project -1. Select **iOS App** in the **Choose a template for your new project** window and click Next. -2. Enter your project name in the **Name** field in the **Choose options for your new project** window. -3. Enter your identifier in the **Bundle Identifier** field in the **Choose options for your new project** window. -4. Select **Storyboard** in the **Interface** field in the **Choose options for your new project** window. -5. Select **Swift** in the **Language** field in the **Choose options for your new project** window. +Open Xcode and create a new project: -*** +1. Select **iOS App** in the template picker and click Next +2. Enter your project name and bundle identifier +3. Select **Storyboard** for Interface +4. Select **Swift** for Language -### **Install Dependencies** +--- -This developer kit is an add-on feature to CometChat iOS SDK so installing it will also install the core Chat SDK. You can install CometChat UI Kit into your iOS project using CocoaPods or Swift Package Manager (SPM). +## Step 2 — Install the UI Kit -We recommend using CocoaPods, as they are the most advanced way of managing iOS project dependencies. +1. Create a Podfile in your project root: -1. Create pod file by running the following command in your project's base level: - -```ruby Swift +```bash pod init ``` -2. Add CometChat SDKs to Your Podfile: +2. Add CometChat to your Podfile: -```ruby Swift +```ruby title="Podfile" platform :ios, '13.0' use_frameworks! target 'YourApp' do - # CometChat UI Kit for Swift - pod 'CometChatUIKitSwift', '5.1.7' - - # Optional: Include if you're using Audio/Video Calling + pod 'CometChatUIKitSwift', '5.1.9' + + # Optional: Voice/Video Calling pod 'CometChatCallsSDK', '4.2.2' end ``` -3. Install the CometChat UI Kit framework through CocoaPods: - -```ruby Swift -pod install -``` - -If you're facing any issues while installing pods, use the following command: +3. Install dependencies: -```ruby Swift +```bash pod install --repo-update ``` -To get the latest version of CometChat UI Kit, use: - -```ruby Swift -pod update CometChatUIKitSwift -pod update CometChatCallsSDK -``` +4. Close the `.xcodeproj` file and open the `.xcworkspace` file instead. CocoaPods creates a workspace that includes your project and the installed pods. - -Always ensure to open the XCFramework file after adding the dependencies. - +Always open the `.xcworkspace` file after installing pods — opening the `.xcodeproj` will cause build errors. Having issues? See [CocoaPods Troubleshooting](/ui-kit/ios/troubleshooting#cocoapods-issues). - - -**Swift Package Manager** (SPM) is Apple's built-in tool for managing dependencies in Swift projects. It allows developers to integrate and manage third-party libraries seamlessly. - -1. Go to **File** tab and select **Add Package Dependencies.** + +1. Go to **File → Add Package Dependencies** -2. Enter the repository URL of the Swift package: +2. Enter the repository URL: ``` https://github.com/cometchat/cometchat-uikit-ios ``` -3. To add the package, select Version Rules, enter Up to Exact Version and click Add package. - - Exact Version: - - ``` - 5.1.7 - ``` - -4. Add `CometChatSDK` repeating the above steps for following link and exact version: - - Link: +3. Select **Up to Exact Version** and enter: - ``` - https://github.com/cometchat/chat-sdk-ios - ``` +``` +5.1.9 +``` - Exact Version: +4. Add the Chat SDK separately using: - ``` - 4.1.0 - ``` +``` +https://github.com/cometchat/chat-sdk-ios +``` + Exact Version: `4.1.0` - -*** - -### **Configure Privacy Permissions** - -1. To enable media messaging in your app, you must allow **Camera**, **Microphone**, and **Photo Library** access in `Info.plist`. These permissions are required for sending and receiving media files. - - ```ruby Info.plist - NSCameraUsageDescription - Allow access to the camera to capture photos and videos. - - NSMicrophoneUsageDescription - Enable microphone access for voice and video communication. - - NSPhotoLibraryAddUsageDescription - Allow saving photos and videos to your device's photo library. - - NSPhotoLibraryUsageDescription - Grant access to select and upload photos from your library. - ``` - - - - - -2. Navigate to your Build Settings and disable the User Script Sandboxing option. - - Disabling User Script Sandboxing ensures that WebView can load and execute scripts necessary for collaborative tools. - - - - - -*** +--- -### **Step 4: Initialize & Login to CometChat UI Kit** +## Step 3 — Configure Permissions -To authenticate a user, you need a **`UID`**. You can either: +Add these keys to your `Info.plist` for media messaging: -1. **Create new users** on the **[CometChat Dashboard](https://app.cometchat.com)**, **[CometChat SDK Method](/ui-kit/react/methods#create-user)** or **[via the API](https://api-explorer.cometchat.com/reference/creates-user)**. +```xml title="Info.plist" +NSCameraUsageDescription +Allow access to the camera to capture photos and videos. -2. **Use pre-generated test users**: +NSMicrophoneUsageDescription +Enable microphone access for voice and video communication. - * `cometchat-uid-1` - * `cometchat-uid-2` - * `cometchat-uid-3` - * `cometchat-uid-4` - * `cometchat-uid-5` +NSPhotoLibraryAddUsageDescription +Allow saving photos and videos to your device's photo library. -The **Login** method returns a **User object** containing all relevant details of the logged-in user. +NSPhotoLibraryUsageDescription +Grant access to select and upload photos from your library. +``` -*** + + + - +Also disable **User Script Sandboxing** in Build Settings to ensure WebView can load scripts for collaborative tools: -**Security Best Practices** +1. Select your project in the Navigator +2. Select your app target +3. Go to **Build Settings** tab +4. Search for "User Script Sandboxing" +5. Set it to **No** -* The **Auth Key** method is recommended for **proof-of-concept (POC) development** and early-stage testing. -* For **production environments**, it is strongly advised to use an **[Auth Token](/ui-kit/ios/methods#login-using-auth-token)** instead of an **Auth Key** to enhance security and prevent unauthorized access. + + + - +--- -You can initialize CometChat and log in a user in your `SceneDelegate.swift` file: +## Step 4 — Initialize & Login -> ⚠️ **Important:** Initialization and login are independent steps. However, the CometChat SDK **must be initialized before** you call the login method. +Add this to your `SceneDelegate.swift`. Init must complete before login, and login must complete before rendering any UI. -```swift SceneDelegate.swift highlight={13-15} lines +```swift title="SceneDelegate.swift" import UIKit import CometChatUIKitSwift +import CometChatSDK class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } let uikitSettings = UIKitSettings() - .set(appID: "<#Enter Your App ID Here#>") - .set(region: "<#Enter Your Region Code Here#>") - .set(authKey: "<#Enter Your AuthKey Here#>") + .set(appID: "APP_ID") // Replace with your App ID + .set(region: "REGION") // Replace with your Region + .set(authKey: "AUTH_KEY") // Replace with your Auth Key (dev only) .subscribePresenceForAllUsers() .build() CometChatUIKit.init(uiKitSettings: uikitSettings) { result in switch result { case .success: - debugPrint("CometChat UI Kit initialization succeeded") - - let uid = "cometchat-uid-1" - + debugPrint("CometChat initialized") + + let uid = "cometchat-uid-1" // Test user + CometChatUIKit.login(uid: uid) { loginResult in switch loginResult { case .success: - debugPrint("CometChat UI Kit login succeeded") - - // ✅ Option 1: Launch One-to-One or Group Chat Screen - // DispatchQueue.main.async { - // self.setUpOneOneOrGroupConversation(windowScene: windowScene, uid: "cometchat-uid-2") - // } - - // ✅ Option 2: Launch Conversation List + Message View (Split-Screen Style) - // DispatchQueue.main.async { - // self.setupConversationsView(windowScene: windowScene) - // } - - // ✅ Option 3: Launch Tab-Based Chat Experience (Chats, Calls, Users, Groups) - // DispatchQueue.main.async { - // self.setupTabbedView(windowScene: windowScene) - // } - + debugPrint("Login successful") + + // ✅ Option 1: Launch One-to-One or Group Chat Screen + // DispatchQueue.main.async { + // self.setUpOneOneOrGroupConversation(windowScene: windowScene, uid: "cometchat-uid-2") + // } + + // ✅ Option 2: Launch Conversation List + Message View + // DispatchQueue.main.async { + // self.setupConversationsView(windowScene: windowScene) + // } + + // ✅ Option 3: Launch Tab-Based Chat Experience + // DispatchQueue.main.async { + // self.setupTabbedView(windowScene: windowScene) + // } + case .onError(let error): - debugPrint("CometChat UI Kit login failed with error: \(error.description)") + debugPrint("Login failed: \(error.description)") @unknown default: break } } - + case .failure(let error): - debugPrint("CometChat UI Kit initialization failed with error: \(error.localizedDescription)") + debugPrint("Init failed: \(error.localizedDescription)") } } } } ``` - - -Ensure you replace the following placeholders with your actual CometChat credentials: - -* App ID → Your CometChat App ID -* Auth Key → Your CometChat Auth Key -* Region → Your App Region +For development, use one of the pre-created test UIDs: -These values are required for proper authentication and seamless integration. +`cometchat-uid-1` · `cometchat-uid-2` · `cometchat-uid-3` · `cometchat-uid-4` · `cometchat-uid-5` - +Or create new users via the [CometChat Dashboard](https://app.cometchat.com), [SDK method](/ui-kit/ios/methods#create-user), or [REST API](https://api-explorer.cometchat.com/reference/creates-user). -After running the app, you should see the following log message: +After running the app, you should see: -```sh Console -"CometChat UI Kit initialization succeeded" -"CometChat UI Kit login succeeded" +```sh +"CometChat initialized" +"Login successful" ``` -*** + +`init()` must complete before you call `login()`. If you call `login()` before init completes, it will fail silently. + -### **Step 5: Choose a Chat Experience** + +For production, use [`loginWithAuthToken()`](/ui-kit/ios/methods#login-using-auth-token) instead of Auth Key. Generate tokens server-side via the REST API. + + + +Having issues? Check the [Troubleshooting Guide](/ui-kit/ios/troubleshooting) for common problems and solutions. + -Integrate a conversation view that suits your application's **UX requirements**. Below are the available options: +--- -*** +## Step 5 — Choose a Chat Experience -### **1️⃣ Conversation List + Message View** +Integrate a conversation view that suits your app's UX. Each option below includes a step-by-step guide. -**Best for:** Native iOS apps using **stack-based navigation** to switch between conversations and messages. +### Conversation List + Message View -**Highlights:** +Two-panel layout — conversation list with push navigation to messages. Think iMessage or WhatsApp. -* **Push-Based Navigation** – Taps on conversations open full message views. -* **Supports One-to-One & Group Chats** – Handles all CometChat conversation types. -* **Real-Time Sync** – Messages auto-refresh using live CometChat event listeners. -* **Session-Aware** – Message states persist across app sessions and devices. -* **Customizable UI** – Modify styling, actions, or behavior using CometChat UI Kit. +- Push-based navigation between conversations and messages +- Supports one-to-one and group chats +- Real-time sync with CometChat event listeners +- Session-aware — message states persist across app sessions -**Use When:** + + Step-by-step guide to build this layout + -* You need a **native iOS chat experience** with clean transitions. -* Your app supports **private and group messaging**. -* You want **seamless sync and navigation** between list and messages. - -[Integrate Conversation List + Message View](./ios-conversation) - -*** - -### **2️⃣ One-to-One / Group Chat** +--- -**Best for:** iOS apps that launch **directly into a conversation screen** without showing a list. +### One-to-One / Group Chat -**Highlights:** +Single chat window — no sidebar. Good for support chat, contextual messaging, or focused conversations. -* **Single View Chat** – Use `CometChatMessages` with a passed user or group object. -* **No Sidebar or List** – Ideal for contextual entry points (support, match, invite, etc.). -* **Works with UINavigationController & SwiftUI NavigationStack** -* **Lightweight** – Launches faster and uses minimal memory. -* **Full-Screen Messaging** – Clear, immersive chat UI. +- Dedicated chat window for one-on-one or group messaging +- No conversation list — users go directly into the chat +- Full-screen experience optimized for mobile +- Ideal for support workflows, community replies, or invitations -**Use When:** - -* Your app starts directly with a **specific user or group chat**. -* You want a **clean, distraction-free** chat experience. -* Ideal for **support workflows, community replies, or invitations.** - -[Integrate One-to-One / Group Chat](./ios-one-to-one-chat) + + Step-by-step guide to build this layout + -*** - -### **3️⃣ Tab-Based Messaging UI (All-in-One)** +--- -**Best for:** iOS apps needing a **multi-tab interface** with seamless transitions between Chats, Users, Calls, and Settings. +### Tab-Based Chat -**Highlights:** +Tabbed navigation — Chats, Calls, Users, Groups in separate tabs. Good for full-featured apps. -* **UITabBarController or SwiftUI TabView** – Native navigation pattern for iOS. -* **Modular UI** – Isolated controllers or views for each tab. -* **Full-Screen Messaging** – Dedicated message views within the Chat tab. -* **Extensible** – Add future tabs like Notifications, Search, or Profile. -* **Responsive Layouts** – Works across iPhones and iPads. -* **Great for SuperApps & Enterprise Tools** +- UITabBarController or SwiftUI TabView navigation +- Full-screen messaging within each tab +- Modular UI — isolated controllers for each tab +- Scales well for adding future features like notifications or settings -**Use When:** - -* You need a **structured layout** for navigating chat, calls, and contacts. -* Your app supports **multiple modules** (e.g., user directory, history, chat). -* Designed for **enterprise, support, or social use cases**. - -[Integrate Tab-Based Chat](./ios-tab-based-chat) - -*** - -## **Build Your Own Chat Experience** + + Step-by-step guide to build this layout + -**Best for:** Developers who need complete control over their chat interface, allowing customization of components, themes, and features to align with their app’s design and functionality. Whether you're enhancing an existing chat experience or building from scratch, this approach provides the flexibility to tailor every aspect to your needs. - -**Recommended for:** - -* Apps that require **a fully customized chat experience**. -* Developers who want to **extend functionalities and modify UI components**. -* Businesses integrating chat seamlessly into **existing platforms**. - -**Key Areas to Explore:** - -* **[iOS Sample App](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp)** – Fully functional sample applications to accelerate your development. -* **[Core Features](./core-features)** – Learn about messaging, real-time updates, and other essential capabilities. -* **[Components](./components-overview)** – Utilize prebuilt UI elements or customize them to fit your design. -* **[Themes](./theme-introduction)** – Adjust colors, fonts, and styles to match your branding. -* **[Build Your Own UI](/sdk/javascript/overview)** – Prefer a custom UI over our UI Kits? Explore our SDKs to create a tailored chat experience. +--- -*** +## Build Your Own Chat Experience -## **Next Steps** +Need full control over the UI? Use individual components, customize themes, and wire up your own layouts. -Now that you’ve selected your **chat experience**, proceed to the **integration guide**: +- [Sample App](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) — Working reference app to compare against +- [Components](/ui-kit/ios/components-overview) — All prebuilt UI elements with customization options +- [Core Features](/ui-kit/ios/core-features) — Messaging, real-time updates, and other capabilities +- [Theming](/ui-kit/ios/theme-introduction) — Colors, fonts, dark mode, and custom styling +- [Build Your Own UI](/sdk/ios/overview) — Skip the UI Kit entirely and build on the raw SDK -* **[Integrate Conversation List + Message](/ui-kit/ios/ios-conversation)** -* **[Integrate One-to-One Chat](/ui-kit/ios/ios-one-to-one-chat)** -* **[Integrate Tab-Based Chat](/ui-kit/ios/ios-tab-based-chat)** -* **[Advanced Customizations](/ui-kit/ios/theme-introduction)** +--- -*** +## Next Steps + + + + Browse all prebuilt UI components + + + Customize colors, fonts, and styles + + + Chat features included out of the box + + + SDK methods and API reference + + diff --git a/ui-kit/ios/group-members.mdx b/ui-kit/ios/group-members.mdx index 0d7d3e211..fde68adc1 100644 --- a/ui-kit/ios/group-members.mdx +++ b/ui-kit/ios/group-members.mdx @@ -1,1080 +1,1299 @@ --- title: "Group Members" +description: "Display and manage members of a CometChat group" --- -## Overview - -`CometChatGroupMembers` is a versatile [Component](/ui-kit/ios/components-overview#components) designed to showcase all users who are either added to or invited to a group, thereby enabling them to participate in group discussions, access shared content, and engage in collaborative activities. Group members have the capability to communicate in real-time through messaging, voice and video calls, and various other interactions. Additionally, they can interact with each other, share files, and join calls based on the permissions established by the group administrator or owner. +The `CometChatGroupMembers` component displays all members of a group with their roles (owner, admin, moderator, participant). It supports member management actions like kick, ban, and role changes based on the logged-in user's permissions. - + CometChatGroupMembers showing a list of group members with their avatars, names, and role badges indicating owner, admin, moderator, and participant status -The `CometChatGroupMembers` component is composed of the following BaseComponents: - -| Components | Description | -| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [CometChatListBase](/ui-kit/ios/list-base) | `CometChatListBase` serves as a container component equipped with a title (navigationBar), search functionality (search-bar), background settings, and a container for embedding a list view. | -| [CometChatListItem](/ui-kit/ios/list-item) | This component renders information extracted from a `User` object onto a tile, featuring a title, subtitle, leading view, and trailing view. experience, facilitating seamless navigation and interaction within the component. | + +```json +{ + "component": "CometChatGroupMembers", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays all members of a group with their roles and supports member management actions like kick, ban, and role changes.", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onItemClick", + "type": "(GroupMember, IndexPath) -> Void" + }, + "props": { + "data": { + "group": { + "type": "Group", + "required": true, + "note": "The group whose members to display" + }, + "groupMembersRequestBuilder": { + "type": "GroupMembersRequest.GroupMembersRequestBuilder?", + "default": "nil", + "note": "Custom request builder for filtering members" + } + }, + "callbacks": { + "onItemClick": "(GroupMember, IndexPath) -> Void", + "onItemLongClick": "(GroupMember, IndexPath) -> Void", + "onBack": "() -> Void", + "onSelection": "([GroupMember]) -> Void", + "onSelectedItemProceed": "([GroupMember]) -> Void", + "onError": "(CometChatException) -> Void", + "onEmpty": "() -> Void", + "onLoad": "([GroupMember]) -> Void" + }, + "visibility": { + "hideSearch": { "type": "Bool", "default": false }, + "hideNavigationBar": { "type": "Bool", "default": false }, + "hideBackIcon": { "type": "Bool", "default": false }, + "hideUserStatus": { "type": "Bool", "default": false }, + "hideKickMemberOption": { "type": "Bool", "default": false }, + "hideBanMemberOption": { "type": "Bool", "default": false }, + "hideScopeChangeOption": { "type": "Bool", "default": false }, + "hideErrorView": { "type": "Bool", "default": false }, + "hideLoadingState": { "type": "Bool", "default": false } + }, + "selection": { + "selectionMode": { "type": "SelectionMode", "default": ".none" } + }, + "styling": { + "avatarStyle": { "type": "AvatarStyle", "default": "AvatarStyle()" }, + "statusIndicatorStyle": { "type": "StatusIndicatorStyle", "default": "StatusIndicatorStyle()" } + }, + "viewSlots": { + "listItemView": "(GroupMember?) -> UIView", + "leadingView": "(GroupMember?) -> UIView", + "titleView": "(GroupMember?) -> UIView", + "subtitleView": "(GroupMember?) -> UIView", + "trailView": "(GroupMember?) -> UIView", + "emptyStateView": "UIView", + "errorStateView": "UIView", + "loadingStateView": "UIView" + } + }, + "methods": { + "swipeActions": { + "set(options:)": "((Group, GroupMember?) -> [CometChatGroupMemberOption])? - Sets custom swipe actions", + "add(options:)": "((Group, GroupMember?) -> [CometChatGroupMemberOption])? - Adds additional swipe actions" + }, + "dataManipulation": { + "add(groupMember:)": "GroupMember - Adds a member to the list", + "update(groupMember:)": "GroupMember - Updates a member in the list", + "remove(groupMember:)": "GroupMember - Removes a member from the list", + "insert(groupMember:at:)": "GroupMember, Int - Inserts a member at a specific index", + "clearList()": "Void - Removes all members from the list", + "size()": "Int - Returns the number of members in the list" + } + }, + "events": [ + { + "name": "ccGroupMemberKicked", + "payload": "{ user: User, group: Group }", + "description": "Fires when a member is kicked" + }, + { + "name": "ccGroupMemberBanned", + "payload": "{ user: User, group: Group }", + "description": "Fires when a member is banned" + }, + { + "name": "ccGroupMemberScopeChanged", + "payload": "{ user: User, group: Group, scope: MemberScope }", + "description": "Fires when a member's scope is changed" + } + ], + "sdkListeners": [ + "onGroupMemberKicked", + "onGroupMemberBanned", + "onGroupMemberUnbanned", + "onGroupMemberScopeChanged", + "onMemberAddedToGroup" + ], + "compositionExample": { + "description": "GroupMembers is typically accessed from group details or settings", + "components": ["CometChatGroups", "CometChatGroupMembers", "CometChatMessages"], + "flow": "User opens group → views members → taps member → starts direct chat" + }, + "types": { + "GroupMember": { + "uid": "String", + "name": "String", + "avatar": "String?", + "scope": "MemberScope", + "joinedAt": "Int" + }, + "MemberScope": { + "owner": "Group owner with full permissions", + "admin": "Administrator with management permissions", + "moderator": "Moderator with limited management", + "participant": "Regular member" + } + } +} +``` + -*** +| Field | Value | +|-------|-------| +| Component | `CometChatGroupMembers` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | -## Usage +--- -### Integration +## Where It Fits -`CometChatGroupMembers`, as a custom **view controller**, offers flexible integration options, allowing it to be launched directly via button clicks or any user-triggered action. Additionally, it seamlessly integrates into tab view controllers. With group members, users gain access to a wide range of parameters and methods for effortless customization of its user interface. +`CometChatGroupMembers` displays all members of a specific group. It's typically accessed from group details or settings screens. -The following code snippet exemplifies how you can seamlessly integrate the GroupMembers component into your application. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let group = Group(guid: <#T##String#>, name: <#T##String#>, groupType: <#T##CometChat.groupType#>, password: <#T##String?#>) -let cometChatGroupMembers = CometChatGroupMembers(group: group) -let naviVC = UINavigationController(rootViewController: cometChatGroupMembers) -self.present(naviVC, animated: true) +class GroupDetailViewController: UIViewController { + + var group: Group! + + override func viewDidLoad() { + super.viewDidLoad() + setupGroupMembers() + } + + private func setupGroupMembers() { + let groupMembers = CometChatGroupMembers(group: group) + + // Handle member tap - start direct chat + groupMembers.set(onItemClick: { [weak self] member, indexPath in + self?.startDirectChat(with: member) + }) + + let navController = UINavigationController(rootViewController: groupMembers) + present(navController, animated: true) + } + + private func startDirectChat(with member: GroupMember) { + let messagesVC = CometChatMessages() + messagesVC.set(user: member) + navigationController?.pushViewController(messagesVC, animated: true) + } +} ``` - + + CometChatGroupMembers displaying group members in a navigation context with search functionality and member details + - +--- - +## Minimal Render -If you are already using a navigation controller, you can use the pushViewController function instead of presenting the view controller. +```swift lines +import CometChatUIKitSwift +import CometChatSDK - +let groupMembers = CometChatGroupMembers(group: group) +let navController = UINavigationController(rootViewController: groupMembers) +present(navController, animated: true) +``` -*** + + CometChatGroupMembers showing minimal render with default configuration displaying member list + -### Actions +--- -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. +## Filtering -1. ##### set(onItemClick:) +Use `GroupMembersRequest.GroupMembersRequestBuilder` to filter which members appear in the list. -`set(OnItemClick:)` is triggered when you click on a ListItem of the groups component. This `set(OnItemClick:)` method proves beneficial when a user intends to customize the on-click behavior in CometChatGroupMembers. +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift -cometChatGroupMembers.set(onItemClick: { user, indexPath in - // Override on item click -}) +// Create a custom request builder +let requestBuilder = GroupMembersRequest.GroupMembersRequestBuilder(guid: group.guid) + .set(limit: 30) + .set(scopes: ["admin", "moderator"]) + +let groupMembers = CometChatGroupMembers( + group: group, + groupMembersRequestBuilder: requestBuilder +) ``` - +### Filter Recipes + +| Recipe | Code | +|--------|------| +| Admins only | `.set(scopes: ["admin"])` | +| Admins and moderators | `.set(scopes: ["admin", "moderator"])` | +| Search by name | `.set(searchKeyword: "john")` | +| Limit results | `.set(limit: 20)` | - +--- + +## Actions and Events + +### Callback Props -*** +#### onItemClick -2. ##### set(OnItemLongClick:) +Fires when a user taps on a member. Use this to start a direct chat or view profile. -`set(OnItemLongClick:)` is triggered when you long press on a ListItem of the group members component. This `set(OnItemLongClick:)` method proves beneficial when a user intends to additional functionality on long press on list item in CometChatGroupMembers. +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift -cometChatGroupMembers.set(onItemLongClick: { groupMember, indexPath in - // Override on item click +let groupMembers = CometChatGroupMembers(group: group) + +groupMembers.set(onItemClick: { [weak self] member, indexPath in + guard let self = self else { return } + + let messagesVC = CometChatMessages() + messagesVC.set(user: member) + self.navigationController?.pushViewController(messagesVC, animated: true) }) ``` - - - +#### onItemLongClick -*** +Fires when a user long-presses on a member. Use this to show member options. -##### 3. set(onBack:) +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This `set(onBack:)` method becomes valuable when a user needs to override the action triggered upon pressing the back button in CometChatGroupMembers. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -cometChatGroupMembers.set(onBack: { - // Override on back +groupMembers.set(onItemLongClick: { [weak self] member, indexPath in + guard let self = self else { return } + + let alert = UIAlertController(title: member.name, message: nil, preferredStyle: .actionSheet) + + alert.addAction(UIAlertAction(title: "Message", style: .default) { _ in + // Start direct chat + }) + + alert.addAction(UIAlertAction(title: "View Profile", style: .default) { _ in + // View profile + }) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + self.present(alert, animated: true) }) ``` - +#### onBack - +Fires when the back button is pressed. -*** +```swift lines +import CometChatUIKitSwift -##### 4. set(onSelection:) +let groupMembers = CometChatGroupMembers(group: group) -The `set(onSelection:)` only gets trigger when selection mode is set to multiple of single. And this gets trigger on every selection, and returns the list of selected group members. +groupMembers.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) +}) +``` + +#### onSelection + +Fires when members are selected in selection mode. + +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift +let groupMembers = CometChatGroupMembers(group: group) +groupMembers.selectionMode = .multiple -cometChatGroupMembers.set(onSelection: { groupMembers in - //Handle action +groupMembers.set(onSelection: { [weak self] selectedMembers in + print("Selected \(selectedMembers.count) members") }) ``` - - - +#### onError -*** +Fires when an error occurs while loading members. -##### 5. set(onError:) +```swift lines +import CometChatUIKitSwift -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatGroupMembers. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -cometChatGroupMembers.set(onError: { error in - // Override on error +groupMembers.set(onError: { error in + print("Error loading members: \(error.errorDescription)") }) ``` - +#### onEmpty - +Fires when the member list is empty. -*** - -##### 6. set(onEmpty:) +```swift lines +import CometChatUIKitSwift -This `set(onEmpty:)` method is triggered when the groups list is empty in CometChatGroupMembers. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -cometChatGroupMembers.set(onEmpty: { - // Handle empty state +groupMembers.set(onEmpty: { + print("No members found") }) ``` - +#### onLoad - +Fires when members are successfully loaded. -*** - -##### 7. setOnLoad +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This set(onLoad:) gets triggered when a group members list is fully fetched and going to displayed on the screen, this return the list of group members to get displayed on the screen. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -cometChatGroupMembers.set(onLoad: { groups in - // Handle loaded users +groupMembers.set(onLoad: { members in + print("Loaded \(members.count) members") }) ``` - +### Actions Reference - +| Method | Description | Example | +|--------|-------------|---------| +| `set(onItemClick:)` | Triggered when a member is tapped | Start direct chat | +| `set(onItemLongClick:)` | Triggered on long press | Show options menu | +| `set(onBack:)` | Triggered when back button is pressed | Custom navigation | +| `set(onSelection:)` | Triggered in selection mode | Multi-select members | +| `set(onError:)` | Triggered when an error occurs | Show error alert | +| `set(onEmpty:)` | Triggered when list is empty | Show empty state | +| `set(onLoad:)` | Triggered when members load | Analytics tracking | -*** +### Global UI Events -### Filters +| Event | Fires when | Payload | +|-------|------------|---------| +| `ccGroupMemberKicked` | A member is kicked | `User, Group` | +| `ccGroupMemberBanned` | A member is banned | `User, Group` | +| `ccGroupMemberScopeChanged` | A member's role is changed | `User, Group, MemberScope` | -**Filters** allow you to customize the data displayed in a list within a `Component`. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using `RequestBuilders` of Chat SDK. +```swift lines +import CometChatUIKitSwift +import CometChatSDK -##### 1. GroupsRequestBuilder +class MyViewController: UIViewController, CometChatGroupEventListener { + + override func viewDidLoad() { + super.viewDidLoad() + CometChatGroupEvents.addListener("my-listener", self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatGroupEvents.removeListener("my-listener") + } + + func onGroupMemberKick(kickedUser: User, kickedGroup: Group) { + print("\(kickedUser.name ?? "") was kicked from \(kickedGroup.name ?? "")") + } + + func onGroupMemberBan(bannedUser: User, bannedGroup: Group) { + print("\(bannedUser.name ?? "") was banned from \(bannedGroup.name ?? "")") + } + + func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) { + print("\(updatedUser.name ?? "") role changed to \(scopeChangedTo)") + } +} +``` -The [GroupsRequestBuilder](/sdk/ios/retrieve-groups) enables you to filter and customize the group list based on available parameters in GroupsRequestBuilder. This feature allows you to create more specific and targeted queries when fetching groups. The following are the parameters available in [GroupsRequestBuilder](/sdk/ios/retrieve-groups) +### SDK Events (Real-Time, Automatic) -| Methods | Type | Description | -| -------------------- | --------- | ------------------------------------------------------------------------------------------------------------------- | -| **setLimit** | Int | Configure the maximum number of groups to fetch in a single request, optimizing pagination for smoother navigation. | -| **setSearchKeyword** | String | Employed to retrieve groups that match the provided string, facilitating precise searches. | -| **scopes** | \[String] | used for fetching group members based on multiple scopes | +| SDK Listener | Internal behavior | +|--------------|-------------------| +| `onGroupMemberKicked` | Removes member from list | +| `onGroupMemberBanned` | Removes member from list | +| `onGroupMemberUnbanned` | Updates member info | +| `onGroupMemberScopeChanged` | Updates member role badge | +| `onMemberAddedToGroup` | Adds new member to list | -**Example** +--- -In the example below, we are applying a filter to the Group List based on limit and scope. +## Custom View Slots - - -```swift -let group = Group(guid: "mrc-uid", name: "", groupType: .public, password: .none) -let groupMembersRequestBuilder = GroupMembersRequest.GroupMembersRequestBuilder(guid: group.guid).set(limit: 2).set(scopes: ["admin"]) +| Slot | Setter Method | Signature | Replaces | +|------|---------------|-----------|----------| +| `listItemView` | `set(listItemView:)` | `(GroupMember?) -> UIView` | Entire member row | +| `leadingView` | `set(leadingView:)` | `(GroupMember?) -> UIView` | Avatar / left section | +| `titleView` | `set(titleView:)` | `(GroupMember?) -> UIView` | Name / title text | +| `subtitleView` | `set(subtitleView:)` | `(GroupMember?) -> UIView` | Role / subtitle text | +| `trailView` | `set(trailView:)` | `(GroupMember?) -> UIView` | Right side (role badge) | +| `emptyStateView` | - | `UIView` | Empty state display | +| `errorStateView` | - | `UIView` | Error state display | +| `loadingStateView` | - | `UIView` | Loading state display | -let cometChatGroupMembers = CometChatGroupMembers(group: group, groupMembersRequestBuilder: groupMembersRequestBuilder) +### set(titleView:) -let naviVC = UINavigationController(rootViewController: cometChatGroupMembers) -self.present(naviVC, animated: true) -``` +Replaces the default title view (member name) with a custom implementation. - +| | | +|---|---| +| Signature | `(GroupMember?) -> UIView` | +| Replaces | Member name / title text | - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -##### 2. SearchRequestBuilder +let groupMembers = CometChatGroupMembers(group: group) -The SearchRequestBuilder uses [GroupsRequestBuilder](/sdk/ios/retrieve-groups) enables you to filter and customize the search list based on available parameters in GroupsRequestBuilder. This feature allows you to keep uniformity between the displayed Groups List and searched Group List. +groupMembers.set(titleView: { member in + let containerView = UIView() + + let nameLabel = UILabel() + nameLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) + nameLabel.textColor = UIColor.label + nameLabel.text = member?.name ?? "Unknown" + nameLabel.translatesAutoresizingMaskIntoConstraints = false + + let roleLabel = UILabel() + roleLabel.font = UIFont.systemFont(ofSize: 10, weight: .medium) + roleLabel.textColor = UIColor.white + roleLabel.textAlignment = .center + roleLabel.layer.cornerRadius = 4 + roleLabel.clipsToBounds = true + roleLabel.translatesAutoresizingMaskIntoConstraints = false + + // Set role badge color based on scope + switch member?.scope { + case .owner: + roleLabel.text = " Owner " + roleLabel.backgroundColor = UIColor.systemOrange + case .admin: + roleLabel.text = " Admin " + roleLabel.backgroundColor = UIColor.systemPurple + case .moderator: + roleLabel.text = " Mod " + roleLabel.backgroundColor = UIColor.systemBlue + default: + roleLabel.text = "" + roleLabel.backgroundColor = .clear + } + + containerView.addSubview(nameLabel) + containerView.addSubview(roleLabel) + + NSLayoutConstraint.activate([ + nameLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + nameLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor), + + roleLabel.leadingAnchor.constraint(equalTo: nameLabel.trailingAnchor, constant: 8), + roleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor) + ]) + + return containerView +}) +``` + +### set(leadingView:) -**Example** +Replaces the default leading view (avatar) with a custom implementation. - - -```swift -let group = Group(guid: "mrc-uid", name: "", groupType: .public, password: .none) -let groupMembersRequestBuilder = GroupMembersRequest.GroupMembersRequestBuilder(guid: group.guid) - .set(searchKeyword: "") +| | | +|---|---| +| Signature | `(GroupMember?) -> UIView` | +| Replaces | Avatar / left section | + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -let cometChatGroupMembers = CometChatGroupMembers(group: group, groupMembersRequestBuilder: groupMembersRequestBuilder) +let groupMembers = CometChatGroupMembers(group: group) -let naviVC = UINavigationController(rootViewController: cometChatGroupMembers) -self.present(naviVC, animated: true) +groupMembers.set(leadingView: { member in + let containerView = UIView() + containerView.translatesAutoresizingMaskIntoConstraints = false + + // Create avatar + let avatar = CometChatAvatar(image: UIImage()) + avatar.setAvatar(avatarUrl: member?.avatar, with: member?.name ?? "") + avatar.translatesAutoresizingMaskIntoConstraints = false + + // Create role badge overlay + let badgeView = UIView() + badgeView.layer.cornerRadius = 10 + badgeView.layer.borderWidth = 2 + badgeView.layer.borderColor = UIColor.white.cgColor + badgeView.translatesAutoresizingMaskIntoConstraints = false + + // Set badge color based on scope + switch member?.scope { + case .owner: + badgeView.backgroundColor = UIColor.systemOrange + case .admin: + badgeView.backgroundColor = UIColor.systemPurple + case .moderator: + badgeView.backgroundColor = UIColor.systemBlue + default: + badgeView.backgroundColor = UIColor.systemGray + } + + let badgeIcon = UIImageView(image: UIImage(systemName: "star.fill")) + badgeIcon.tintColor = .white + badgeIcon.translatesAutoresizingMaskIntoConstraints = false + badgeView.addSubview(badgeIcon) + + containerView.addSubview(avatar) + containerView.addSubview(badgeView) + + NSLayoutConstraint.activate([ + avatar.topAnchor.constraint(equalTo: containerView.topAnchor), + avatar.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), + avatar.widthAnchor.constraint(equalToConstant: 40), + avatar.heightAnchor.constraint(equalToConstant: 40), + + badgeView.widthAnchor.constraint(equalToConstant: 20), + badgeView.heightAnchor.constraint(equalToConstant: 20), + badgeView.bottomAnchor.constraint(equalTo: avatar.bottomAnchor, constant: 2), + badgeView.trailingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: 2), + + badgeIcon.centerXAnchor.constraint(equalTo: badgeView.centerXAnchor), + badgeIcon.centerYAnchor.constraint(equalTo: badgeView.centerYAnchor), + badgeIcon.widthAnchor.constraint(equalToConstant: 12), + badgeIcon.heightAnchor.constraint(equalToConstant: 12) + ]) + + return containerView +}) ``` - +### subtitleView - +Customize the subtitle area below the member name. -*** +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -### Events +let groupMembers = CometChatGroupMembers(group: group) -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. +groupMembers.set(subtitleView: { member in + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 12) + label.textColor = UIColor.secondaryLabel + + guard let member = member else { return label } + + let date = Date(timeIntervalSince1970: Double(member.joinedAt)) + let formatter = DateFormatter() + formatter.dateStyle = .medium + label.text = "Joined: \(formatter.string(from: date))" + + return label +}) +``` -Events emitted by the Join Group component is as follows. +{/* TODO: Add screenshot showing subtitleView customization */} -| Event | Description | -| ---------------------------- | ----------------------------------------------------------------- | -| **onGroupMemberBan** | Triggers when the group member banned from the group successfully | -| **onGroupMemberKick** | Triggers when the group member kicked from the group successfully | -| **onGroupMemberChangeScope** | Triggers when the group member scope is changed in the group | +### tailView - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { +Customize the right side of the member row (role badge). Note: The setter method is `set(trailView:)`. - public override func viewDidLoad() { - super.viewDidLoad() +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - // Subscribing for the listener to listen events from user module - CometChatGroupEvents.addListener("UNIQUE_ID", self as CometChatGroupEventListener) - } -} - // Listener events from groups module -extension ViewController: CometChatGroupEventListener { - public func onGroupMemberBan(bannedUser: User, bannedGroup: Group) { - // Do Stuff - } - public func onGroupMemberKick(kickedUser: User, kickedGroup: Group) { - // Do Stuff - } - public func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) { - // Do Stuff +let groupMembers = CometChatGroupMembers(group: group) + +groupMembers.set(trailView: { member in + let badge = UILabel() + badge.font = UIFont.systemFont(ofSize: 10, weight: .semibold) + badge.textAlignment = .center + badge.layer.cornerRadius = 10 + badge.clipsToBounds = true + + guard let member = member else { return badge } + + switch member.scope { + case .owner: + badge.text = "Owner" + badge.textColor = UIColor.systemOrange + badge.backgroundColor = UIColor.systemOrange.withAlphaComponent(0.2) + case .admin: + badge.text = "Admin" + badge.textColor = UIColor.systemPurple + badge.backgroundColor = UIColor.systemPurple.withAlphaComponent(0.2) + case .moderator: + badge.text = "Mod" + badge.textColor = UIColor.systemBlue + badge.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.2) + default: + badge.text = "Member" + badge.textColor = UIColor.systemGray + badge.backgroundColor = UIColor.systemGray.withAlphaComponent(0.2) } -} + + return badge +}) ``` -```swift Emitting Group Events -///emit this when group member is banned from the group by logged in user. -CometChatGroupEvents.emitOnGroupMemberBan(bannedUser: User, bannedGroup: Group, bannedBy: User) +{/* TODO: Add screenshot showing trailingView customization */} -///emit this when group member is kicked from the group by logged in user. -CometChatGroupEvents.emitOnGroupMemberKick(kickedUser: User, kickedGroup: Group, kickedBy: User) +--- -///emit this when group member's scope is changed by logged in user. -CometChatGroupEvents.emitOnGroupMemberChangeScope(updatedBy: User , updatedUser: User , scopeChangedTo: CometChat.MemberScope , scopeChangedFrom: CometChat.MemberScope, group: Group) +## Styling + +### Style Hierarchy + +1. Global styles (`CometChatGroupMembers.style`) apply to all instances +2. Instance styles override global for specific instances + +### Global Level Styling + +```swift lines +import UIKit +import CometChatUIKitSwift + +// Apply global styles +CometChatGroupMembers.style.backgroundColor = UIColor.systemBackground +CometChatGroupMembers.style.titleColor = UIColor.label +CometChatGroupMembers.style.titleFont = UIFont.systemFont(ofSize: 20, weight: .bold) +CometChatGroupMembers.style.listItemTitleTextColor = UIColor.label + +// Custom avatar style +let avatarStyle = AvatarStyle() +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) +CometChatGroupMembers.avatarStyle = avatarStyle ``` - +### Instance Level Styling - +```swift lines +import UIKit +import CometChatUIKitSwift -*** +var customStyle = GroupMembersStyle() +customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +customStyle.titleColor = UIColor.darkGray +customStyle.listItemBackground = UIColor.white - - -```swift View Controller -public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module -CometChatGroupEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") -} +let groupMembers = CometChatGroupMembers(group: group) +groupMembers.style = customStyle ``` - + + CometChatGroupMembers with custom styling showing modified background color, title appearance, and list item styling + + +### Key Style Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `backgroundColor` | `UIColor` | `CometChatTheme.backgroundColor01` | Background color | +| `titleColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Navigation title color | +| `titleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Navigation title font | +| `listItemTitleTextColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Member name color | +| `listItemTitleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Member name font | +| `listItemSubTitleTextColor` | `UIColor` | `CometChatTheme.textColorSecondary` | Subtitle color | +| `listItemBackground` | `UIColor` | `.clear` | List item background | + +### Customization Matrix + +| What to change | Where | Property/API | Example | +|----------------|-------|--------------|---------| +| Background color | Style | `backgroundColor` | `UIColor.systemBackground` | +| Title appearance | Style | `titleColor`, `titleFont` | Custom colors and fonts | +| List item look | Style | `listItemBackground` | `UIColor.white` | +| Avatar appearance | Style | `avatarStyle` | `AvatarStyle()` with custom radius | +| Hide search | Property | `hideSearch` | `groupMembers.hideSearch = true` | +| Hide kick option | Property | `hideKickMemberOption` | `groupMembers.hideKickMemberOption = true` | +| Custom row | View Slot | `set(listItemView:)` | See Custom View Slots | + +--- - +## Props -## Customization +All props are optional except `group`. Sorted alphabetically. -To fit your app's design requirements, you can customize the appearance of the Groups component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. +### avatarStyle -### Style +Customizes the appearance of member avatars in the list. -Using **Style** you can **customize** the look and feel of the component in your app, These parameters typically control elements such as the **color**, **size**, **shape**, and **fonts** used within the component. +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | -##### 1. GroupMembers Style +```swift lines +import CometChatUIKitSwift -You can set the `GroupMembersStyle` to the `Group Memebers` Component to customize the styling. +let groupMembers = CometChatGroupMembers(group: group) -**Global level styling** +let avatarStyle = AvatarStyle() +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) +avatarStyle.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.1) - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) - -CometChatGroupMembers.style.titleColor = UIColor(hex: "#F76808") -CometChatGroupMembers.style.titleFont = UIFont(name: "Times-New-Roman", size: 34) -CometChatGroupMembers.avatarStyle = customAvatarStyle +groupMembers.avatarStyle = avatarStyle ``` - +### group (required) - +The group whose members to display. -**Instance level styling** +| | | +|---|---| +| Type | `Group` | +| Required | `true` | - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) - -let groupMembersStyle = GroupMembersStyle() -groupMembersStyle.titleColor = UIColor(hex: "#F76808") -groupMembersStyle.titleFont = UIFont(name: "Times-New-Roman", size: 34) - -let groupMember = CometChatGroupMembers() -groupMember.style = groupMembersStyle -groupMember.avatarStyle = customAvatarStyle -``` +### groupMembersRequestBuilder - +Custom request builder for filtering members. - +| | | +|---|---| +| Type | `GroupMembersRequest.GroupMembersRequestBuilder?` | +| Default | `nil` | - - - +### hideBackIcon -List of properties exposed by GroupMemberStyle - -| Property | Description | Code | -| --------------------------------- | ---------------------------------------------------- | ------------------------------------------------ | -| retryButtonTextColor | Sets the text color for the retry button. | `.retryButtonTextColor: UIColor` | -| retryButtonTextFont | Sets the text font for the retry button. | `.retryButtonTextFont: UIFont` | -| retryButtonBackgroundColor | Sets the background color for the retry button. | `.retryButtonBackgroundColor: UIColor` | -| retryButtonBorderColor | Sets the border color for the retry button. | `.retryButtonBorderColor: UIColor` | -| retryButtonBorderWidth | Sets the border width for the retry button. | `.retryButtonBorderWidth: CGFloat` | -| retryButtonCornerRadius | Sets the corner radius for the retry button. | `.retryButtonCornerRadius: CometChatCornerStyle` | -| listItemSelectedBackground | Sets the background color for selected list items. | `.listItemSelectedBackground: UIColor` | -| listItemDeSelectedImageTint | Sets the tint color for deselected list item images. | `.listItemDeSelectedImageTint: UIColor` | -| listItemSelectionImageTint | Sets the tint color for selected list item images. | `.listItemSelectionImageTint: UIColor` | -| listItemSelectedImage | Sets the image for selected list items. | `.listItemSelectedImage: UIImage` | -| listItemDeSelectedImage | Sets the image for deselected list items. | `.listItemDeSelectedImage: UIImage` | -| backgroundColor | Sets the background color. | `.backgroundColor: UIColor` | -| borderWidth | Sets the border width. | `.borderWidth: CGFloat` | -| borderColor | Sets the border color. | `.borderColor: UIColor` | -| cornerRadius | Sets the corner radius style. | `.cornerRadius: CometChatCornerStyle` | -| titleFont | Sets the font for the title. | `.titleFont: UIFont?` | -| largeTitleFont | Sets the font for the large title. | `.largeTitleFont: UIFont?` | -| titleColor | Sets the color for the title text. | `.titleColor: UIColor?` | -| largeTitleColor | Sets the color for the large title text. | `.largeTitleColor: UIColor?` | -| navigationBarTintColor | Sets the tint color for the navigation bar. | `.navigationBarTintColor: UIColor?` | -| navigationBarItemsTintColor | Sets the tint color for navigation bar items. | `.navigationBarItemsTintColor: UIColor?` | -| errorTitleTextFont | Sets the font for the error title text. | `.errorTitleTextFont: UIFont` | -| errorTitleTextColor | Sets the color for the error title text. | `.errorTitleTextColor: UIColor` | -| errorSubTitleFont | Sets the font for the error subtitle text. | `.errorSubTitleFont: UIFont` | -| errorSubTitleTextColor | Sets the color for the error subtitle text. | `.errorSubTitleTextColor: UIColor` | -| emptyTitleTextFont | Sets the font for the empty state title text. | `.emptyTitleTextFont: UIFont` | -| emptyTitleTextColor | Sets the color for the empty state title text. | `.emptyTitleTextColor: UIColor` | -| emptySubTitleFont | Sets the font for the empty state subtitle text. | `.emptySubTitleFont: UIFont` | -| emptySubTitleTextColor | Sets the color for the empty state subtitle text. | `.emptySubTitleTextColor: UIColor` | -| tableViewSeparator | Sets the color for the table view separator. | `.tableViewSeparator: UIColor` | -| listItemTitleTextColor | Sets the text color for list item titles. | `.listItemTitleTextColor: UIColor` | -| listItemTitleFont | Sets the font for list item titles. | `.listItemTitleFont: UIFont` | -| listItemSubTitleTextColor | Sets the text color for list item subtitles. | `.listItemSubTitleTextColor: UIColor` | -| listItemSubTitleFont | Sets the font for list item subtitles. | `.listItemSubTitleFont: UIFont` | -| listItemBackground | Sets the background color for list items. | `.listItemBackground: UIColor` | -| listItemBorderWidth | Sets the border width for list items. | `.listItemBorderWidth: CGFloat` | -| listItemBorderColor | Sets the border color for list items. | `.listItemBorderColor: UIColor` | -| listItemCornerRadius | Sets the corner radius for list items. | `.listItemCornerRadius: CometChatCornerStyle` | -| messageTypeImageTint | Sets the tint color for message type icons. | `.messageTypeImageTint: UIColor` | -| passwordGroupImageTintColor | Sets the tint color for password group icons. | `.passwordGroupImageTintColor: UIColor` | -| passwordGroupImageBackgroundColor | Sets the background color for password group icons. | `.passwordGroupImageBackgroundColor: UIColor` | -| privateGroupImageTintColor | Sets the tint color for private group icons. | `.privateGroupImageTintColor: UIColor` | -| privateGroupImageBackgroundColor | Sets the background color for private group icons. | `.privateGroupImageBackgroundColor: UIColor` | - -*** - -### Functionality - -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. - - - -```swift -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.set(title: "Cc", mode: .automatic) -cometChatGroupMembers.disable(usersPresence: true) -``` +Hides the back button in the navigation bar. - +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - +### hideBanMemberOption -| Method | Description | Code | -| -------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------- | -| set(groupMembersRequestBuilder:) | Sets the request builder for fetching group members. | `set(groupMembersRequestBuilder: GroupMembersRequest.GroupMembersRequestBuilder)` | -| set(searchRequestBuilder:) | Sets the request builder for searching group members. | `set(searchRequestBuilder: searchRequestBuilder)` | -| set(searchKeyword:) | Sets the search keyword to filter group members. | `set(searchKeyword: "group_name")` | -| hideError | Hides the error state view. | `hideError = true` | -| hideUserStatus | Hides the online/offline status of users. | `hideUserStatus = true` | -| hideNavigationBar | Hides or shows the navigation bar. | `hideNavigationBar = true` | -| hideLoadingState | Hides the loading state indicator. | `hideLoadingState = true` | -| hideBackIcon | Hides the back button/icon. | `hideBackIcon = true` | -| hideKickMemberOption | Hides the option to kick a member from the group. | `hideKickMemberOption = true` | -| hideBanMemberOption | Hides the option to ban a member from the group. | `hideBanMemberOption = true` | -| hideScopeChangeOption | Hides the option to change a member’s scope (role). | `hideScopeChangeOption = true` | -| hideSearch | Hides the search bar. | `hideSearch = true` | +Hides the ban member option in swipe actions. -### Advanced +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your own views, layouts, and UI elements and then incorporate those into the component. +### hideErrorView -The `Join Group` component does not provide additional functionalities beyond this level of customization. +Hides the error state view. -#### SetListItemView +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -Utilize this property to assign a custom ListItem to the GroupMembers Component, allowing for enhanced customization and flexibility in its rendering. +### hideKickMemberOption - - -```swift -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.set(listItemView:{ groupMember in - let customListItemGroupView = CustomListItemGroupView() - customListItemGroupView.configure(with: groupMember!) // pass group member here - return customListItemGroupView -}) -``` +Hides the kick member option in swipe actions. - +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - +### hideLoadingState -**Example** +Hides the loading state indicator. - - - +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -In this example, we will create a UIView file `CustomListItemGroupView` and pass it inside the `setListItemView()` method. +### hideNavigationBar -```swift CustomListItemGroupView +Hides the entire navigation bar. -import UIKit -import CometChatSDK -import CometChatUIKitSwift +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -class CustomListItemView: UIView { - - private let profileImageView: CometChatAvatar = { - let imageView = CometChatAvatar() - imageView.layer.cornerRadius = 12 // Rounded corners - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - private let nameLabel: UILabel = { - let label = UILabel() - label.textColor = .black - label.font = UIFont.boldSystemFont(ofSize: 18) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private let roleBadgeButton: UIButton = { - let button = UIButton(type: .system) - button.setTitle("Owner", for: .normal) - button.setTitleColor(.white, for: .normal) - button.backgroundColor = UIColor.purple - button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) - button.layer.cornerRadius = 12 - button.translatesAutoresizingMaskIntoConstraints = false - return button - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setupView() - } - - private func setupView() { - addSubview(profileImageView) - addSubview(nameLabel) - addSubview(roleBadgeButton) - - NSLayoutConstraint.activate([ - // Profile Image Constraints - profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor), - profileImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - profileImageView.widthAnchor.constraint(equalToConstant: 50), - profileImageView.heightAnchor.constraint(equalToConstant: 50), - - // Name Label Constraints - nameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 12), - nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor), - - // Role Badge Button Constraints - roleBadgeButton.leadingAnchor.constraint(greaterThanOrEqualTo: nameLabel.trailingAnchor, constant: 12), - roleBadgeButton.trailingAnchor.constraint(equalTo: trailingAnchor), - roleBadgeButton.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor), - roleBadgeButton.heightAnchor.constraint(equalToConstant: 24), - roleBadgeButton.widthAnchor.constraint(equalToConstant: 70) - ]) - } - - // Method to configure the view with data - func configure(with groupMember: GroupMember) { - nameLabel.text = groupMember.name ?? "" - profileImageView.setAvatar(avatarUrl: groupMember.avatar ?? "") - roleBadgeButton.setTitle("\(groupMember.scope)", for: .normal) - } -} -``` +### hideScopeChangeOption -*** +Hides the role change option in swipe actions. -#### SetLeadingView +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -You can modify the leading view of a group member cell using .set(leadingView:). +### hideSearch - - -```swift -cometChatGroupMember.set(leadingView: { groupMember in - let view = CustomLeadingView() - view.configure(with groupMember: groupMember) - return view -}) -``` +Hides the search bar. - +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - +### hideUserStatus -Demonstration +Hides online/offline status indicators. - - - +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -You can create a `CustomLeadingView` as a custom `UIView`. Which we will inflate in `setLeadingView()` +### selectionMode - - -```swift -import UIKit +Sets the selection mode for multi-select functionality. -class CustomLeadingView: UIView { - - private let profileImageView: CometChatAvatar = { - let imageView = CometChatAvatar() - imageView.layer.cornerRadius = 12 // Rounded corners - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - private let badgeContainer: UIView = { - let view = UIView() - view.backgroundColor = UIColor.blue - view.layer.cornerRadius = 8 - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - - private let starIcon: UIImageView = { - let imageView = UIImageView() - imageView.image = UIImage(systemName: "star.fill") // SF Symbol for star - imageView.tintColor = .yellow - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - private let roleLabel: UILabel = { - let label = UILabel() - label.textColor = .white - label.font = UIFont.boldSystemFont(ofSize: 16) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setupView() - } - - private func setupView() { - addSubview(profileImageView) - addSubview(badgeContainer) - badgeContainer.addSubview(starIcon) - badgeContainer.addSubview(roleLabel) - - NSLayoutConstraint.activate([ - profileImageView.topAnchor.constraint(equalTo: topAnchor), - profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor), - profileImageView.trailingAnchor.constraint(equalTo: trailingAnchor), - profileImageView.heightAnchor.constraint(equalTo: profileImageView.widthAnchor), // Square shape - - badgeContainer.leadingAnchor.constraint(equalTo: profileImageView.leadingAnchor), - badgeContainer.trailingAnchor.constraint(equalTo: profileImageView.trailingAnchor), - badgeContainer.bottomAnchor.constraint(equalTo: profileImageView.bottomAnchor), - badgeContainer.heightAnchor.constraint(equalToConstant: 40), - - starIcon.leadingAnchor.constraint(equalTo: badgeContainer.leadingAnchor, constant: 10), - starIcon.centerYAnchor.constraint(equalTo: badgeContainer.centerYAnchor), - starIcon.widthAnchor.constraint(equalToConstant: 20), - starIcon.heightAnchor.constraint(equalToConstant: 20), - - roleLabel.leadingAnchor.constraint(equalTo: starIcon.trailingAnchor, constant: 5), - roleLabel.centerYAnchor.constraint(equalTo: badgeContainer.centerYAnchor) - ]) - } - - func configure(with groupMember: GroupMember) { - if let avatarUrl = groupMember.avatar { - groupImageView.setAvatar(avatarUrl: avatarUrl, with: groupMember.name ?? "") - } - roleLabel.text = "\(groupMember.scope)" - } -} -``` +| | | +|---|---| +| Type | `SelectionMode` | +| Default | `.none` | + +### statusIndicatorStyle - +Customizes the appearance of online/offline status indicators. - +| | | +|---|---| +| Type | `StatusIndicatorStyle` | +| Default | `StatusIndicatorStyle()` | -*** +```swift lines +import CometChatUIKitSwift -#### SetTitleView +let groupMembers = CometChatGroupMembers(group: group) -You can customize the title view of a group member cell using .set(titleView:). +let statusIndicatorStyle = StatusIndicatorStyle() +statusIndicatorStyle.backgroundColor = UIColor.systemGreen +statusIndicatorStyle.borderWidth = 2 +statusIndicatorStyle.borderColor = UIColor.white - - -```swift -cometChatGroupMember.set(titleView: { groupMember in - let view = CustomTitleView() - view.configure(with groupMember: groupMember) - return view -}) +groupMembers.statusIndicatorStyle = statusIndicatorStyle ``` - +--- - +## Events -Demonstration +| Event | Payload | Fires when | +|-------|---------|------------| +| `ccGroupMemberKicked` | `User, Group` | A member is kicked | +| `ccGroupMemberBanned` | `User, Group` | A member is banned | +| `ccGroupMemberScopeChanged` | `User, Group, MemberScope` | A member's role is changed | - - - +--- -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +## Methods - - -```swift - import UIKit +### Swipe Action Methods -class CustomTitleView: UIView { - - private let nameLabel: UILabel = { - let label = UILabel() - label.font = UIFont.boldSystemFont(ofSize: 20) - label.textColor = .black - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private let roleButton: UIButton = { - let button = UIButton() - button.setTitleColor(.white, for: .normal) - button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14) - button.backgroundColor = .blue - button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 10, bottom: 5, right: 10) - button.layer.cornerRadius = 12 - button.translatesAutoresizingMaskIntoConstraints = false - return button - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } +#### set(options:) + +Sets custom swipe actions for group member list items, replacing the default options. These options appear when the user swipes on a member cell. + +```swift lines +@discardableResult +public func set(options: ((_ group: Group, _ member: GroupMember?) -> [CometChatGroupMemberOption])?) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((Group, GroupMember?) -> [CometChatGroupMemberOption])?` | Closure that returns an array of swipe action options for a member | + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +let groupMembers = CometChatGroupMembers(group: group) + +groupMembers.set(options: { group, member in + var options = [CometChatGroupMemberOption]() - required init?(coder: NSCoder) { - super.init(coder: coder) - setupView() - } + // Add message option + let messageOption = CometChatGroupMemberOption( + id: "message", + title: "Message", + icon: UIImage(systemName: "message"), + backgroundColor: .systemBlue, + onClick: { member, group, section, option, controller in + let messages = CometChatMessages() + messages.set(user: member) + controller.navigationController?.pushViewController(messages, animated: true) + } + ) + options.append(messageOption) - private func setupView() { - addSubview(nameLabel) - addSubview(roleButton) - - NSLayoutConstraint.activate([ - nameLabel.leadingAnchor.constraint(equalTo: leadingAnchor), - nameLabel.centerYAnchor.constraint(equalTo: centerYAnchor), - - roleButton.leadingAnchor.constraint(equalTo: nameLabel.trailingAnchor, constant: 8), - roleButton.centerYAnchor.constraint(equalTo: centerYAnchor), - roleButton.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor) - ]) - } + // Add remove option + let removeOption = CometChatGroupMemberOption( + id: "remove", + title: "Remove", + icon: UIImage(systemName: "trash"), + backgroundColor: .systemRed, + onClick: { member, group, section, option, controller in + print("Remove member: \(member.name ?? "")") + } + ) + options.append(removeOption) - func configure(with groupMember: GroupMember) { - nameLabel.text = groupMember.name ?? "" - roleButton.setTitle("\(groupMember.scope)", for: .normal) - } -} + return options +}) ``` - +#### add(options:) + +Adds additional swipe actions to the existing default options. - +```swift lines +@discardableResult +public func add(options: ((_ group: Group, _ member: GroupMember?) -> [CometChatGroupMemberOption])?) -> Self +``` -*** +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((Group, GroupMember?) -> [CometChatGroupMemberOption])?` | Closure that returns additional swipe action options to append | -#### SetTrailView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can set a custom Tailview using `.setTailView()` to match the `TailView` view of your app. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.setTailView(tailView: { groupMember in - let customTailGroupView = CustomTailGroupView() - customTailGroupView.configure(with: groupMember!) - return customTailGroupView +groupMembers.add(options: { group, member in + var options = [CometChatGroupMemberOption]() + + // Add promote option + let promoteOption = CometChatGroupMemberOption( + id: "promote", + title: "Promote", + icon: UIImage(systemName: "arrow.up.circle"), + backgroundColor: .systemGreen, + onClick: { member, group, section, option, controller in + print("Promote member: \(member.name ?? "")") + } + ) + options.append(promoteOption) + + return options }) ``` - - - +### Data Manipulation Methods -**Example** +#### add(groupMember:) - - - +Adds a new group member to the list. -In this example, we will create a UIView file `Custom_Tail_GroupView` and pass it inside the `.setTailView()` method. +```swift lines +@discardableResult +public func add(groupMember: GroupMember) -> Self +``` -```swift Custom_Tail_GroupView +| Parameter | Type | Description | +|-----------|------|-------------| +| `groupMember` | `GroupMember` | The group member to add to the list | -import UIKit -import CometChatSDK +```swift lines import CometChatUIKitSwift +import CometChatSDK -class CustomTailGroupView: UIView { - - let tailLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 10, weight: .semibold) - label.textColor = UIColor(hex: "#6852D6") - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(tailLabel) - NSLayoutConstraint.activate([ - tailLabel.centerXAnchor.constraint(equalTo: centerXAnchor), - tailLabel.centerYAnchor.constraint(equalTo: centerYAnchor), - self.heightAnchor.constraint(equalToConstant: 22), - self.layer.cornerRadius = 11 - ]) - self.backgroundColor = UIColor(hex: "#EDEAFA") - } +let groupMembers = CometChatGroupMembers(group: group) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // Configure the view with a group member - func configure(with groupMember: GroupMember) { - tailLabel.text = "\(groupMember.name!.description )" - } -} +// Add a member programmatically +let newMember = GroupMember(uid: "user-123", groupMemberScope: .participant) +newMember.name = "John Doe" +groupMembers.add(groupMember: newMember) ``` -*** - -#### SubtitleView +#### update(groupMember:) -You can set your custom Subtitle view using the `.setSubtitleView()` method. But keep in mind, by using this you will override the default Subtitle view functionality. +Updates an existing group member in the list. - - -```swift -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.setSubtitleView(subtitleView: { groupMember in - let customSubtitleGroupMemberView = CustomSubtitleGroupMemberView() - customSubtitleGroupMemberView.configure(with: groupMember!) - return customSubtitleGroupMemberView -}) +```swift lines +@discardableResult +public func update(groupMember: GroupMember) -> Self ``` - +| Parameter | Type | Description | +|-----------|------|-------------| +| `groupMember` | `GroupMember` | The group member with updated information | - +```swift lines +import CometChatUIKitSwift +import CometChatSDK -* You can customize the subtitle view for each GroupMembers item to meet your requirements +let groupMembers = CometChatGroupMembers(group: group) -**Example** +// Update a member's information +if var existingMember = memberToUpdate { + existingMember.scope = .admin + groupMembers.update(groupMember: existingMember) +} +``` - - - +#### remove(groupMember:) -In this example, we will create a `Custom_Subtitle_GroupMember_View`a UIView file. +Removes a group member from the list. -```swift Custom_Subtitle_GroupMember_View +```swift lines +@discardableResult +public func remove(groupMember: GroupMember) -> Self +``` -import UIKit -import CometChatSDK +| Parameter | Type | Description | +|-----------|------|-------------| +| `groupMember` | `GroupMember` | The group member to remove from the list | + +```swift lines import CometChatUIKitSwift +import CometChatSDK -class CustomSubtitleGroupMemberView: UIView { - - let memberNameLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = .init(red: 0.42, green: 0.01, blue: 0.84, alpha: 1.00) - label.font = UIFont.systemFont(ofSize: 15, weight: .bold) - return label - }() - - let joinedAtLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = .systemBrown - label.font = UIFont.systemFont(ofSize: 10, weight: .medium) - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(memberNameLabel) - addSubview(joinedAtLabel) - - NSLayoutConstraint.activate([ - memberNameLabel.topAnchor.constraint(equalTo: topAnchor), - memberNameLabel.leadingAnchor.constraint(equalTo: leadingAnchor), - memberNameLabel.trailingAnchor.constraint(equalTo: trailingAnchor), - - joinedAtLabel.topAnchor.constraint(equalTo: memberNameLabel.bottomAnchor, constant: 2), - joinedAtLabel.leadingAnchor.constraint(equalTo: leadingAnchor), - joinedAtLabel.trailingAnchor.constraint(equalTo: trailingAnchor), - joinedAtLabel.bottomAnchor.constraint(equalTo: bottomAnchor) - ]) - } +let groupMembers = CometChatGroupMembers(group: group) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } +// Remove a member from the UI +groupMembers.remove(groupMember: memberToRemove) +``` - func configure(with groupMember: GroupMember) { - memberNameLabel.text = "Member: \(groupMember.name ?? "")" +#### insert(groupMember:at:) - let date = Date(timeIntervalSince1970: Double(groupMember.joinedAt)) - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - joinedAtLabel.text = "Joined at: \(dateFormatter.string(from: date))" - } -} +Inserts a group member at a specific index in the list. + +```swift lines +@discardableResult +public func insert(groupMember: GroupMember, at index: Int) -> Self ``` -*** +| Parameter | Type | Description | +|-----------|------|-------------| +| `groupMember` | `GroupMember` | The group member to insert | +| `index` | `Int` | The position at which to insert the member | -#### Options +```swift lines +import CometChatUIKitSwift +import CometChatSDK -Enhance your GroupsMembers component by setting Custom Options to incorporate additional functionalities when swiping +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.setOptions (options:{ group, groupMember in - //Perform Your Action -}) +// Insert a member at the top of the list +let newMember = GroupMember(uid: "user-456", groupMemberScope: .participant) +newMember.name = "Jane Smith" +groupMembers.insert(groupMember: newMember, at: 0) ``` - - - +#### clearList() -* You can customize the options for group members to meet your requirements +Removes all group members from the list. -**Example** +```swift lines +public func clearList() +``` - - - +```swift lines +import CometChatUIKitSwift -In this example, we've enhanced the interface of `CometChatGroupMembers` by introducing a tailored feature. By adding a custom option, such as "Delete" with a corresponding trash icon, users can now enjoy a more interactive and user-friendly experience. - - - -```swift -let customOption = CometChatGroupMemberOption(id: "custom_option_1", - title: "Delete", - icon: UIImage(systemName: "trash.square"), - backgroundColor: .red, - onClick: { groupMember, group, section, option, controller in - print("Custom option clicked!") -}) +let groupMembers = CometChatGroupMembers(group: group) -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.setOptions(options: { group, groupMember in - return [customOption] -}) +// Clear all members from the list +groupMembers.clearList() ``` - +#### size() - +Returns the number of group members currently in the list. -*** +```swift lines +public func size() -> Int +``` -#### Menus +```swift lines +import CometChatUIKitSwift -You can set the Custom Menus to add more options to the Group members component. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.set(menus: [UIBarButtonItem]) +// Get the count of members +let memberCount = groupMembers.size() +print("Total members: \(memberCount)") ``` - +--- - +## Selection Properties -* You can customize the menus for groups to meet your requirements +### onSelectedItemProceed -**Example** +Callback that fires when the user proceeds with selected members in selection mode. This is typically triggered when the user taps a "Done" or "Proceed" button after selecting members. - - - +| | | +|---|---| +| Type | `(([GroupMember]) -> Void)?` | +| Default | `nil` | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let groupMembers = CometChatGroupMembers(group: group) +groupMembers.selectionMode = .multiple -In this example, we'll craft a custom button tailored for `CometChatGroupMembers`, enhancing its interface with a personalized `menu` for a more user-friendly experience. - - - -```swift -let customMenuButton: UIBarButtonItem = { - let button = UIButton(type: .system) - button.setImage(UIImage(systemName: "person.badge.plus"), for: .normal) - button.setTitle("", for: .normal) - button.addTarget(self, action: #selector(handleCustomMenu), for: .touchUpInside) - let barButtonItem = UIBarButtonItem(customView: button) - return barButtonItem -}() - -let cometChatGroupMembers = CometChatGroupMembers(group: group) -cometChatGroupMembers.set(menus: [customMenuButton]) +groupMembers.set(onSelectedItemProceed: { [weak self] selectedMembers in + print("Proceeding with \(selectedMembers.count) selected members") + + for member in selectedMembers { + print("Selected: \(member.name ?? "")") + } + + // Perform action with selected members + self?.handleSelectedMembers(selectedMembers) +}) ``` - +--- - +## Custom Swipe Options -*** +Add custom actions when swiping on a member: -#### SetLoadingView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can set a custom loading view using .set(loadingView:). This method accepts a UIView to display while data is being fetched. +let groupMembers = CometChatGroupMembers(group: group) - - -```swift -let loadingIndicator = UIActivityIndicatorView(style: .medium) -loadingIndicator.startAnimating() -cometChatGroupMember.set(loadingView: loadingIndicator) +let deleteOption = CometChatGroupMemberOption( + id: "delete", + title: "Remove", + icon: UIImage(systemName: "trash"), + backgroundColor: .systemRed, + onClick: { member, group, section, option, controller in + print("Remove \(member.name ?? "")") + // Implement remove logic + } +) + +let messageOption = CometChatGroupMemberOption( + id: "message", + title: "Message", + icon: UIImage(systemName: "message"), + backgroundColor: .systemBlue, + onClick: { member, group, section, option, controller in + let messages = CometChatMessages() + messages.set(user: member) + controller.navigationController?.pushViewController(messages, animated: true) + } +) + +groupMembers.setOptions(options: { group, member in + return [messageOption, deleteOption] +}) ``` - + + CometChatGroupMembers showing custom swipe options with Remove and Message action buttons revealed on a member row + - +--- -*** +## Custom Menu Buttons -#### SetErrorView +Add buttons to the navigation bar: -You can customize the error view using .set(errorView:). This method accepts a UIView that appears when an error occurs. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let errorLabel = UILabel() -errorLabel.text = "Something went wrong!" -errorLabel.textColor = .red -cometChatGroupMember.set(errorView: errorLabel) +class GroupMembersViewController: UIViewController { + + var group: Group! + + override func viewDidLoad() { + super.viewDidLoad() + setupGroupMembers() + } + + private func setupGroupMembers() { + let groupMembers = CometChatGroupMembers(group: group) + + let addButton = UIBarButtonItem( + image: UIImage(systemName: "person.badge.plus"), + style: .plain, + target: self, + action: #selector(addMemberTapped) + ) + + groupMembers.set(menus: [addButton]) + + let navController = UINavigationController(rootViewController: groupMembers) + present(navController, animated: true) + } + + @objc func addMemberTapped() { + // Show add member screen + let addMembers = CometChatAddMembers(group: group) + navigationController?.pushViewController(addMembers, animated: true) + } +} ``` - + + CometChatGroupMembers showing custom navigation bar menu with an add member button in the top right corner + + +--- + +## Common Patterns - +### Admins and moderators only -*** +```swift lines +let adminBuilder = GroupMembersRequest.GroupMembersRequestBuilder(guid: group.guid) + .set(scopes: ["admin", "moderator"]) -#### SetEmptyView +let groupMembers = CometChatGroupMembers(group: group, groupMembersRequestBuilder: adminBuilder) +``` -You can customize the empty state view using .set(emptyView:). This method accepts a UIView that appears when no group members are available. +### Hide management options for participants - - -```swift -let emptyLabel = UILabel() -emptyLabel.text = "No groups found" -emptyLabel.textColor = .gray -emptyLabel.textAlignment = .center -cometChatGroupMember.set(emptyView: emptyLabel) +```swift lines +let groupMembers = CometChatGroupMembers(group: group) +groupMembers.hideKickMemberOption = true +groupMembers.hideBanMemberOption = true +groupMembers.hideScopeChangeOption = true ``` - +### Custom empty state + +```swift lines +let groupMembers = CometChatGroupMembers(group: group) + +groupMembers.set(emptyStateView: { + let label = UILabel() + label.text = "No members in this group" + label.textAlignment = .center + return label +}) +``` - +### Multi-select members -*** +```swift lines +let groupMembers = CometChatGroupMembers(group: group) +groupMembers.selectionMode = .multiple - +groupMembers.set(onSelection: { selectedMembers in + print("Selected \(selectedMembers.count) members") + // Kick selected members, change scope, etc. +}) +``` -Ensure to pass and present `CometChatGroupMembers`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. +--- - +## Related Components -*** +- [Groups](/ui-kit/ios/groups) - List all groups +- [Messages](/ui-kit/ios/messages) - Display messages in a group +- [Add Members](/ui-kit/ios/add-members) - Add new members to a group +- [Banned Members](/ui-kit/ios/banned-members) - View banned members +- [Transfer Ownership](/ui-kit/ios/transfer-ownership) - Transfer group ownership diff --git a/ui-kit/ios/groups.mdx b/ui-kit/ios/groups.mdx index d105be4db..63f51f1f3 100644 --- a/ui-kit/ios/groups.mdx +++ b/ui-kit/ios/groups.mdx @@ -1,613 +1,511 @@ --- title: "Groups" +description: "Display and manage a list of groups with search functionality" --- -## Overview - -`CometChatGroups` functions as a standalone [component](/ui-kit/ios/components-overview#components) designed to create a screen displaying a list of groups, with the added functionality of enabling users to search for specific groups. Acting as a container component, CometChatGroups encapsulates and formats the `CometChatListBase` without introducing any additional behavior of its own. +The `CometChatGroups` component displays a searchable list of all available groups. It shows group names, avatars, member counts, and group type indicators (public/private/password-protected). Users can browse, join, and interact with group conversations. - + CometChatGroups showing a searchable list of groups with avatars, names, member counts, and group type indicators -The `Groups` component is composed of the following BaseComponents: + +```json +{ + "component": "CometChatGroups", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays a searchable list of all available groups with avatars, names, member counts, and group type indicators.", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onItemClick", + "type": "(Group, IndexPath) -> Void" + }, + "props": { + "data": { + "groupsRequestBuilder": { + "type": "GroupsRequest.GroupsRequestBuilder?", + "default": "nil", + "note": "Custom request builder for filtering groups" + }, + "searchRequestBuilder": { + "type": "GroupsRequest.GroupsRequestBuilder?", + "default": "nil", + "note": "Custom request builder for search" + } + }, + "callbacks": { + "onItemClick": "(Group, IndexPath) -> Void", + "onItemLongClick": "(Group, IndexPath) -> Void", + "onBack": "() -> Void", + "onSelection": "([Group]) -> Void", + "onSelectedItemProceed": "([Group]) -> Void", + "onError": "(CometChatException) -> Void", + "onEmpty": "() -> Void", + "onLoad": "([Group]) -> Void" + }, + "visibility": { + "hideSearch": { "type": "Bool", "default": false }, + "hideNavigationBar": { "type": "Bool", "default": false }, + "hideBackButton": { "type": "Bool", "default": false }, + "hideGroupType": { "type": "Bool", "default": false }, + "hideSectionHeader": { "type": "Bool", "default": false }, + "hideErrorView": { "type": "Bool", "default": false }, + "hideLoadingState": { "type": "Bool", "default": false } + }, + "selection": { + "selectionMode": { "type": "SelectionMode", "default": ".none" }, + "selectionLimit": { "type": "Int", "default": 0 }, + "selectedCellCount": { "type": "Int", "default": 0 } + }, + "styling": { + "avatarStyle": { "type": "AvatarStyle", "default": "AvatarStyle()" }, + "statusIndicatorStyle": { "type": "StatusIndicatorStyle", "default": "StatusIndicatorStyle()" } + }, + "viewSlots": { + "listItemView": "(Group) -> UIView", + "leadingView": "(Group) -> UIView", + "titleView": "(Group?) -> UIView", + "subtitleView": "(Group?) -> UIView", + "trailingView": "(Group?) -> UIView", + "emptyStateView": "() -> UIView", + "errorStateView": "() -> UIView", + "loadingStateView": "() -> UIView" + } + }, + "events": [ + { + "name": "ccGroupCreated", + "payload": "Group", + "description": "Fires when a group is created" + }, + { + "name": "ccGroupDeleted", + "payload": "Group", + "description": "Fires when a group is deleted" + }, + { + "name": "ccGroupMemberJoined", + "payload": "{ user: User, group: Group }", + "description": "Fires when a user joins a group" + }, + { + "name": "ccGroupMemberLeft", + "payload": "{ user: User, group: Group }", + "description": "Fires when a user leaves a group" + } + ], + "sdkListeners": [ + "onGroupMemberJoined", + "onGroupMemberLeft", + "onGroupMemberKicked", + "onGroupMemberBanned", + "onGroupMemberUnbanned", + "onGroupMemberScopeChanged", + "onMemberAddedToGroup" + ], + "compositionExample": { + "description": "Groups list for browsing and joining group conversations", + "components": ["CometChatGroups", "CometChatMessages"], + "flow": "User taps on a group → onItemClick fires → Navigate to CometChatMessages with selected group" + }, + "types": { + "Group": { + "guid": "String", + "name": "String", + "icon": "String?", + "membersCount": "Int", + "groupType": "GroupType", + "scope": "MemberScope?" + }, + "GroupType": { + "public": "Anyone can join", + "private": "Invite only", + "password": "Password protected" + } + } +} +``` + -| Components | Description | -| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [CometChatListBase](/ui-kit/ios/list-base) | `CometChatListBase` serves as a container component equipped with a title (navigationBar), search functionality (search-bar), background settings, and a container for embedding a list view. | -| [CometChatListItem](/ui-kit/ios/list-item) | This component renders information extracted from a `Group` object onto a tile, featuring a title, subtitle, leading view, and trailing view. | +| Field | Value | +|-------|-------| +| Component | `CometChatGroups` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | -*** +--- -## Usage +## Where It Fits -### Integration +`CometChatGroups` displays all available groups for browsing and joining. It's typically used as a standalone screen or within a tab view controller. -The following code snippet illustrates how you can can launch **CometChatGroups**. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let groups = CometChatGroups() -let naviVC = UINavigationController(rootViewController: groups) -self.present(naviVC, animated: true) +class GroupsViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + setupGroups() + } + + private func setupGroups() { + let groupsController = CometChatGroups() + + // Handle group selection - open group chat + groupsController.set(onItemClick: { [weak self] group, indexPath in + self?.openGroupChat(group) + }) + + let navController = UINavigationController(rootViewController: groupsController) + present(navController, animated: true) + } + + private func openGroupChat(_ group: Group) { + let messagesVC = CometChatMessages() + messagesVC.set(group: group) + navigationController?.pushViewController(messagesVC, animated: true) + } +} ``` - - - - - - -If you are already using a navigation controller, you can use the `pushViewController` function instead of presenting the view controller. - - - -### Actions + + CometChatGroups showing integration with navigation controller and group selection handling + -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. +--- -1. ##### set(onItemClick:) +## Minimal Render -`set(OnItemClick:)` is triggered when you click on a ListItem of the groups component. This `set(OnItemClick:)` method proves beneficial when a user intends to customize the on-click behavior in CometChatGroups. +```swift lines +import CometChatUIKitSwift - - -```swift -cometChatGroups.set(onItemClick: { group, indexPath in - // Override on item click -}) +let groups = CometChatGroups() +let navController = UINavigationController(rootViewController: groups) +present(navController, animated: true) ``` - - - - -*** + + CometChatGroups showing minimal render with default configuration displaying group list + -2. ##### set(OnItemLongClick:) +--- -`set(OnItemLongClick:)` is triggered when you long press on a ListItem of the groups component. This `set(OnItemLongClick:)` method proves beneficial when a user intends to additional functionality on long press on list item in CometChatGroups. +## Filtering - - -```swift -cometChatGroups.set(onItemLongClick: { group, indexPath in - // Override on item click -}) -``` +Use `GroupsRequest.GroupsRequestBuilder` to filter which groups appear in the list. The builder pattern allows chaining multiple filter conditions. - +```swift lines +import CometChatUIKitSwift +import CometChatSDK - +// Create a custom request builder +let groupsRequestBuilder = GroupsRequest.GroupsRequestBuilder(limit: 30) + .set(joinedOnly: true) -*** +let groups = CometChatGroups(groupsRequestBuilder: groupsRequestBuilder) +``` -##### 3. set(onBack:) +### Filter Recipes -This `set(onBack:)` method becomes valuable when a user needs to override the action triggered upon pressing the back button in CometChatGroups. +| Recipe | Code | +|--------|------| +| Joined groups only | `.set(joinedOnly: true)` | +| Search by name | `.set(searchKeyword: "design")` | +| Filter by tags | `.set(tags: ["engineering", "marketing"])` | +| Include tag info | `.set(withTags: true)` | +| Limit results | `GroupsRequestBuilder(limit: 20)` | - - -```swift -cometChatGroups.set(onBack: { - // Override on back -}) -``` +--- - +## Actions and Events - +### Callback Props -*** +#### onItemClick -##### 4. set(onSelection:) +Fires when a user taps on a group in the list. Use this to open the group chat. -The `set(onSelection:)` only gets trigger when selection mode is set to multiple of single. And this gets trigger on every selection, and returns the list of selected groups. +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift +let groups = CometChatGroups() -cometChatGroups.set(onSelection: { groups in - //Handle action +groups.set(onItemClick: { [weak self] group, indexPath in + guard let self = self else { return } + + let messagesVC = CometChatMessages() + messagesVC.set(group: group) + self.navigationController?.pushViewController(messagesVC, animated: true) }) ``` - - - +#### onItemLongClick -*** +Fires when a user long-presses on a group. Use this to show additional options. -##### 5. set(onError:) +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatGroups. +let groups = CometChatGroups() - - -```swift -cometChatGroups.set(onError: { error in - // Override on error +groups.set(onItemLongClick: { [weak self] group, indexPath in + guard let self = self else { return } + + let alert = UIAlertController(title: group.name, message: nil, preferredStyle: .actionSheet) + + alert.addAction(UIAlertAction(title: "View Details", style: .default) { _ in + // View group details + }) + + alert.addAction(UIAlertAction(title: "Leave Group", style: .destructive) { _ in + // Leave group + }) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + self.present(alert, animated: true) }) ``` - - - +#### onBack -*** +Fires when the back button is pressed. -##### 6. set(onEmpty:) +```swift lines +import CometChatUIKitSwift -This `set(onEmpty:)` method is triggered when the groups list is empty in CometChatGroups. +let groups = CometChatGroups() - - -```swift -cometChatGroups.set(onEmpty: { - // Handle empty state +groups.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) }) ``` - - - +#### onSelection -*** +Fires when groups are selected in selection mode. -##### 7. setOnLoad +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This set(onLoad:) gets triggered when a group list is fully fetched and going to displayed on the screen, this return the list of groups to get displayed on the screen. +let groups = CometChatGroups() +groups.selectionMode = .multiple - - -```swift -cometChatGroups.set(onLoad: { groups in - // Handle loaded groups +groups.set(onSelection: { [weak self] selectedGroups in + print("Selected \(selectedGroups.count) groups") }) ``` - - - +#### onSelectedItemProceed -*** +Fires when the user confirms their selection by tapping the proceed/submit button. Use this to handle the final selection action. -### Filters - -**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK. +```swift lines +import CometChatUIKitSwift +import CometChatSDK -##### 1. GroupsRequestBuilder +let groups = CometChatGroups() +groups.selectionMode = .multiple +groups.selectionLimit = 5 -The [GroupsRequestBuilder](/sdk/ios/retrieve-groups) enables you to filter and customize the group list based on available parameters in GroupsRequestBuilder. This feature allows you to create more specific and targeted queries when fetching groups. The following are the parameters available in [GroupsRequestBuilder](/sdk/ios/retrieve-groups) +groups.onSelectedItemProceed = { [weak self] selectedGroups in + guard let self = self else { return } + + // Handle the selected groups + for group in selectedGroups { + print("Selected group: \(group.name ?? "")") + } + + // Proceed with the selection + self.processSelectedGroups(selectedGroups) +} +``` -| Methods | Type | Description | -| -------------------- | --------- | ------------------------------------------------------------------------------------------------------------------- | -| **setLimit** | Int | Configure the maximum number of groups to fetch in a single request, optimizing pagination for smoother navigation. | -| **setSearchKeyword** | String | Employed to retrieve groups that match the provided string, facilitating precise searches. | -| **joinedOnly** | boolean | Exclusively fetches joined groups. | -| **setTags** | \[String] | Utilized to fetch groups containing the specified tags. | -| **withTags** | boolean | Utilized to retrieve groups with specific tags. | +#### onError -**Example** +Fires when an error occurs while loading groups. -In the example below, we are applying a filter to the Group List based on only joined groups. +```swift lines +import CometChatUIKitSwift - - -```swift -// You can create GroupRequestBuilder as per your requirement -let groupsRequestBuilder = GroupsRequest.GroupsRequestBuilder(limit: 20).set(joinedOnly: true) +let groups = CometChatGroups() -let groups = CometChatGroups(groupsRequestBuilder: groupsRequestBuilder) -let naviVC = UINavigationController(rootViewController: groups) -self.present(naviVC, animated: true) +groups.set(onError: { error in + print("Error loading groups: \(error.errorDescription)") +}) ``` - - - +#### onEmpty -##### 2. SearchRequestBuilder +Fires when the group list is empty. -The SearchRequestBuilder uses [GroupsRequestBuilder](/sdk/ios/retrieve-groups) enables you to filter and customize the search list based on available parameters in GroupsRequestBuilder. This feature allows you to keep uniformity between the displayed Groups List and searched Group List. - -**Example** +```swift lines +import CometChatUIKitSwift - - -```swift -// You can create GroupRequestBuilder as per your requirement -let groupsRequestBuilder = GroupsRequest.GroupsRequestBuilder(limit: 2).set(searchKeyword: "") +let groups = CometChatGroups() -let groups = CometChatGroups(groupsRequestBuilder: groupsRequestBuilder) -let naviVC = UINavigationController(rootViewController: groups) -self.present(naviVC, animated: true) +groups.set(onEmpty: { + print("No groups found") +}) ``` - - - - -*** +#### onLoad -### Events +Fires when groups are successfully loaded. -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. - -The list of events emitted by the Groups component is as follows. +```swift lines +import CometChatUIKitSwift +import CometChatSDK -| Event | Description | -| ---------------------------- | -------------------------------------------------------------------------------------------------------- | -| **onGroupCreate** | This gets triggered when the logged in user creates a group. | -| **onGroupDelete** | This gets triggered when the logged in user deletes a group. | -| **onGroupMemberLeave** | This gets triggered when the logged in user leaves a group. | -| **onGroupMemberChangeScope** | This gets triggered when the logged in user changes the scope of another group member. | -| **onGroupMemberBan** | This gets triggered when the logged in user bans a group member from the group. | -| **onGroupMemberKick** | This gets triggered when the logged in user kicks another group member from the group. | -| **onGroupMemberUnban** | This gets triggered when the logged in user unbans a user banned from the group. | -| **onGroupMemberJoin** | This gets triggered when the logged in user joins a group. | -| **onGroupMemberAdd** | This gets triggered when the logged in user adds new members to the group. | -| **onOwnershipChange** | This gets triggered when the logged in user transfers the ownership of their group to some other member. | +let groups = CometChatGroups() -Adding `CometChatGroupsEvents` Listener's +groups.set(onLoad: { groups in + print("Loaded \(groups.count) groups") +}) +``` - - -```swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { +### Actions Reference + +| Method | Description | Example | +|--------|-------------|---------| +| `set(onItemClick:)` | Triggered when a group is tapped | Open group chat | +| `set(onItemLongClick:)` | Triggered on long press | Show options menu | +| `set(onBack:)` | Triggered when back button is pressed | Custom navigation | +| `set(onSelection:)` | Triggered in selection mode | Multi-select groups | +| `onSelectedItemProceed` | Triggered when selection is confirmed | Process selected groups | +| `set(onError:)` | Triggered when an error occurs | Show error alert | +| `set(onEmpty:)` | Triggered when list is empty | Show empty state | +| `set(onLoad:)` | Triggered when groups load | Analytics tracking | + +### Global UI Events + +| Event | Fires when | Payload | +|-------|------------|---------| +| `ccGroupCreated` | A group is created | `Group` | +| `ccGroupDeleted` | A group is deleted | `Group` | +| `ccGroupMemberJoined` | A user joins a group | `User, Group` | +| `ccGroupMemberLeft` | A user leaves a group | `User, Group` | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK - public override func viewDidLoad() { +class MyViewController: UIViewController, CometChatGroupEventListener { + + override func viewDidLoad() { super.viewDidLoad() - - // Subscribing for the listener to listen events from user module - CometChatGroupEvents.addListener("UNIQUE_ID", self as CometChatGroupEventListener) - } - -} - - // Listener events from groups module -extension ViewController: CometChatGroupEventListener { - - public func onGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) { - // Do Stuff - } - - public func onCreateGroupClick() { - // Do Stuff - } - - public func onGroupCreate(group: Group) { - // Do Stuff - } - - public func onGroupDelete(group: Group) { - // Do Stuff - } - - public func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) { - // Do Stuff + CometChatGroupEvents.addListener("my-listener", self) } - - public func onGroupMemberLeave(leftUser: User, leftGroup: Group) { - // Do Stuff - } - - public func onGroupMemberBan(bannedUser: User, bannedGroup: Group) { - // Do Stuff + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatGroupEvents.removeListener("my-listener") } - - public func onGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group) { - // Do Stuff + + func onGroupCreate(group: Group) { + print("Group created: \(group.name ?? "")") } - - public func onGroupMemberKick(kickedUser: User, kickedGroup: Group) { - // Do Stuff + + func onGroupDelete(group: Group) { + print("Group deleted: \(group.name ?? "")") } - - public func onGroupMemberChangeScope(updatedBy: User, updatedUser: User, scopeChangedTo: CometChat.MemberScope, scopeChangedFrom: CometChat.MemberScope, group: Group) { - // Do Stuff + + func onGroupMemberJoin(joinedUser: User, joinedGroup: Group) { + print("\(joinedUser.name ?? "") joined \(joinedGroup.name ?? "")") } - - public func onOwnershipChange(group: Group?, member: GroupMember?) { - // Do Stuff + + func onGroupMemberLeave(leftUser: User, leftGroup: Group) { + print("\(leftUser.name ?? "") left \(leftGroup.name ?? "")") } } ``` - - - - -```swift Emitting Group Events -///you need to pass the [Group] object of the group which is created -CometChatGroupEvents.emitOnGroupCreate(group: Group) - -///you need to pass the [Group] object of the group which is deleted -CometChatGroupEvents.emitOnGroupDelete(group: Group) - -///emit this when logged in user leaves the group. -CometChatGroupEvents.emitOnGroupMemberLeave(leftUser: User, leftGroup: Group) - -///emit this when group member's scope is changed by logged in user. -CometChatGroupEvents.emitOnGroupMemberChangeScope(updatedBy: User , updatedUser: User , scopeChangedTo: CometChat.MemberScope , scopeChangedFrom: CometChat.MemberScope, group: Group) - -///emit this when group member is banned from the group by logged in user. -CometChatGroupEvents.emitOnGroupMemberBan(bannedUser: User, bannedGroup: Group, bannedBy: User) - -///emit this when group member is kicked from the group by logged in user. -CometChatGroupEvents.emitOnGroupMemberKick(kickedUser: User, kickedGroup: Group, kickedBy: User) - -///emit this when a banned group member is unbanned from group by logged in user. -CometChatGroupEvents.emitOnGroupMemberUnban(unbannedUserUser: User, unbannedUserGroup: Group, unbannedBy: User) - -///emit this when logged in user has joined a group successfully. -CometChatGroupEvents.emitOnGroupMemberJoin(joinedUser: User, joinedGroup: Group) - -//emit this when members are added to a group by the logged in user. -CometChatGroupEvents.emitOnGroupMemberAdd(group: Group, members: [GroupMember], addedBy: User) - -///emit this when ownership is changed by logged in user. -CometChatGroupEvents.emitOnGroupMemberChangeScope(updatedBy: User , updatedUser: User , scopeChangedTo: CometChat.MemberScope , scopeChangedFrom: CometChat.MemberScope, group: Group) -``` - -Removing `CometChatGroupsEvents` Listener's - - - -```swift -public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events -CometChatGroupEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") -} -``` - - - - - -## Customization - -To fit your app's design requirements, you can customize the appearance of the groups component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. - -### Style - -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. - -##### 1. Groups Style - -Enhance your Groups Component by setting the GroupsStyle to customize its appearance. - -**Group level styling** - - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) - -CometChatGroups.style.titleColor = UIColor(hex: "#F76808") -CometChatGroups.style.titleFont = UIFont(name: "Times-New-Roman", size: 34) -CometChatGroups.avatarStyle = customAvatarStyle -``` - - - - - -**Instance level styling** - - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) - -let groupStyle = GroupsStyle() -groupStyle.titleColor = UIColor(hex: "#F76808") -groupStyle.titleFont = UIFont(name: "Times-New-Roman", size: 34) - -let customGroup = CometChatGroups() -customGroup.style = groupStyle -customGroup.avatarStyle = customAvatarStyle -``` - - - - - - - - - -| **Property** | **Description** | **Code** | -| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| **List Item Selected Image** | Check box image when a list item is selected. | `listItemSelectedImage` | -| **List Item Deselected Image** | Check box image when a list item is deselected. | `listItemDeSelectedImage` | -| **Search Icon Tint Color** | Tint color for the search icon, defaults to the secondary icon color from CometChatTheme. | `searchIconTintColor` | -| **Search Bar Style** | Style of the search bar, defaulting to the standard style. | `searchBarStyle` | -| **Search Tint Color** | Tint color for the search bar, defaults to the primary color from CometChatTheme. | `searchTintColor` | -| **Search Bar Tint Color** | Background color of the search bar, defaulting to clear. | `searchBarTintColor` | -| **Search Bar Placeholder Text Color** | Placeholder text color for the search bar, defaults to the tertiary text color from CometChatTheme. | `searchBarPlaceholderTextColor` | -| **Search Bar Placeholder Text Font** | Font used for the placeholder text in the search bar, defaults to regular body font. | `searchBarPlaceholderTextFont` | -| **Search Bar Text Color** | Color of the text entered in the search bar, defaults to the primary text color from CometChatTheme. | `searchBarTextColor` | -| **Search Bar Text Font** | Font used for the text in the search bar, defaults to regular body font. | `searchBarTextFont` | -| **Search Bar Background Color** | Background color of the search bar, defaults to a specific background color from CometChatTheme. | `searchBarBackgroundColor` | -| **Search Bar Cancel Icon Tint Color** | Tint color for the cancel icon in the search bar, defaults to the primary color from CometChatTheme. | `searchBarCancelIconTintColor` | -| **Search Bar Cross Icon Tint Color** | Tint color for the cross icon in the search bar, defaults to the secondary icon color from CometChatTheme. | `searchBarCrossIconTintColor` | -| **Background Color** | Background color of the overall view, defaults to a specific background color from CometChatTheme. | `backgroundColor` | -| **Border Width** | Width of the border around the view, defaults to 0 (no border). | `borderWidth` | -| **Border Color** | Color of the border around the view, defaults to clear. | `borderColor` | -| **Corner Radius** | Corner radius settings for the view, defaults to no corner radius. | `cornerRadius` | -| **Title Color** | Color for the title text, defaults to the primary text color from CometChatTheme. | `titleColor` | -| **Title Font** | Font used for the title text, defaults to nil (not set). | `titleFont` | -| **Large Title Color** | Color for the large title text, defaults to the primary text color from CometChatTheme. | `largeTitleColor` | -| **Large Title Font** | Font used for the large title text, defaults to nil (not set). | `largeTitleFont` | -| **Navigation Bar Tint Color** | Background color of the navigation bar, defaults to a specific background color from CometChatTheme. | `navigationBarTintColor` | -| **Navigation Bar Items Tint Color** | Tint color for items in the navigation bar, defaults to the highlight color from CometChatTheme. | `navigationBarItemsTintColor` | -| **Error Title Text Font** | Font used for the error title text, defaults to a bold heading 3 font from CometChatTypography. | `errorTitleTextFont` | -| **Error Title Text Color** | Color of the error title text, defaults to the primary text color from CometChatTheme. | `errorTitleTextColor` | -| **Error Subtitle Font** | Font used for the error subtitle text, defaults to regular body font. | `errorSubTitleFont` | -| **Error Subtitle Text Color** | Color of the error subtitle text, defaults to the secondary text color from CometChatTheme. | `errorSubTitleTextColor` | -| **Retry Button Text Color** | Color for the retry button text, defaults to button text color from CometChatTheme. | `retryButtonTextColor` | -| **Retry Button Text Font** | Font used for the retry button text, defaults to medium button font from CometChatTypography. | `retryButtonTextFont` | -| **Retry Button Background Color** | Background color for the retry button, defaults to the primary color from CometChatTheme. | `retryButtonBackgroundColor` | -| **Retry Button Border Color** | Border color for the retry button, defaults to clear. | `retryButtonBorderColor` | -| **Retry Button Border Width** | Width of the border around the retry button, defaults to 0 (no border). | `retryButtonBorderWidth` | -| **Retry Button Corner Radius** | Corner radius settings for the retry button, defaults to a specific corner radius from CometChatSpacing. | `retryButtonCornerRadius` | -| **Empty State Title Font** | Font used for the empty state title text, defaults to a bold heading 3 font from CometChatTypography. | `emptyTitleTextFont` | -| **Empty State Title Color** | Color of the empty state title text, defaults to the primary text color from CometChatTheme. | `emptyTitleTextColor` | -| **Empty State Subtitle Font** | Font used for the empty state subtitle text, defaults to regular body font. | `emptySubTitleFont` | -| **Empty State Subtitle Color** | Color of the empty state subtitle text, defaults to the secondary text color from CometChatTheme. | `emptySubTitleTextColor` | -| **Table View Separator** | Color of the table view separator, defaults to clear. | `tableViewSeparator` | -| **List Item Title Text Color** | Color of the title text in list items, defaults to the primary text color from CometChatTheme. | `listItemTitleTextColor` | -| **List Item Title Font** | Font used for the title text in list items, defaults to medium heading 4 font from CometChatTypography. | `listItemTitleFont` | -| **List Item Subtitle Text Color** | Color of the subtitle text in list items, defaults to the secondary text color from CometChatTheme. | `listItemSubTitleTextColor` | -| **List Item Subtitle Font** | Font used for the subtitle text in list items, defaults to regular body font. | `listItemSubTitleFont` | -| **List Item Background** | Background color for list items, defaults to clear. | `listItemBackground` | -| **List Item Selected Background** | Background color for list items if selected, defaults to clear. | `listItemSelectedBackground` | -| **List Item Border Width** | Width of the border around list items, defaults to 0 (no border). | `listItemBorderWidth` | -| **List Item Border Color** | Color of the border around list items, defaults to the light border color from CometChatTheme. | `listItemBorderColor` | -| **List Item Corner Radius** | Corner radius settings for list items, defaults to no corner radius. | `listItemCornerRadius` | -| **List Item Selection Image Tint** | Tint color for the selection image in list items, defaults to the highlight color from CometChatTheme. | `listItemSelectionImageTint` | -| **List Item Deselection Image Tint** | Tint color for the deselected image in list items. | `listItemDeSelectedImageTint` | -| **Password Group Image Tint Color** | Tint color for the password group image, defaults to the background color from CometChatTheme. | `passwordGroupImageTintColor` | -| **Password Group Image Background Color** | Background color for the password group image, defaults to the warning color from CometChatTheme. | `passwordGroupImageBackgroundColor` | -| **Private Group Image Tint Color** | Tint color for the private group image, defaults to the background color from CometChatTheme. | `privateGroupImageTintColor` | -| **Private Group Image Background Color** | Background color for the private group image, defaults to the success color from CometChatTheme. | `privateGroupImageBackgroundColor` | -| **Private Group Icon** | Image for a private group icon. | `privateGroupIcon` | -| **Protected Group Icon** | Image for a protected group icon. | `protectedGroupIcon` | - -*** - -### Functionality - -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. - -Below is a list of customizations along with corresponding code snippets - -| Method | Description | Code | -| ---------------------------- | ---------------------------------------------- | ------------------------------------------------- | -| set(groupsRequestBuilder:) | Sets the request builder for fetching groups. | `set(groupsRequestBuilder: requestBuilder)` | -| set(searchRequestBuilder:) | Sets the request builder for searching groups. | `set(searchRequestBuilder: searchRequestBuilder)` | -| set(searchKeyword:) | Sets the search keyword to filter groups. | `set(searchKeyword: "group_name")` | -| hideErrorView | Hides the error state view. | `hideErrorView = true` | -| hideNavigationBar | Hides or shows the navigation bar. | `hideNavigationBar = true` | -| hideSearch | Hides the search bar. | `hideSearch = true` | -| hideBackButton | Hides the back button. | `hideBackButton = true` | -| hideLoadingState | Hides the loading state indicator. | `hideLoadingState = true` | -| hideReceipts | Hides message read/delivery receipts. | `hideReceipts = true` | -| hideDeleteConversationOption | Hides the option to delete a conversation. | `hideDeleteConversationOption = true` | -| hideUserStatus | Hides the online/offline status of users. | `hideUserStatus = true` | -| hideGroupType | Hides the group type (private/public). | `hideGroupType = true` | - -*** - -### Advanced - -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. - -*** - -#### SetOptions - -You can define custom options for each group using .set(options:). This method allows you to return an array of CometChatGroupOption based on the group object. - - - -```swift -cometChatGroups.set(options: { group in - return [CometChatGroupOptions] -}) -``` - - +### SDK Events (Real-Time, Automatic) - +| SDK Listener | Internal behavior | +|--------------|-------------------| +| `onGroupMemberJoined` | Updates member count | +| `onGroupMemberLeft` | Updates member count | +| `onGroupMemberKicked` | Updates member count | +| `onGroupMemberBanned` | Updates member count | +| `onGroupMemberUnbanned` | Updates group info | +| `onGroupMemberScopeChanged` | Updates member scope | +| `onMemberAddedToGroup` | Updates member count | -*** - -#### AddOptions - -You can dynamically add options to groups using .add(options:). This method lets you return additional CometChatGroupOption elements. +--- - - -```swift -cometChatGroups.add(options: { group in - return [ArchiveOption()] -}) -``` +## Custom View Slots - +| Slot | Signature | Replaces | +|------|-----------|----------| +| `listItemView` | `(Group) -> UIView` | Entire group row | +| `leadingView` | `(Group) -> UIView` | Avatar / left section | +| `titleView` | `(Group?) -> UIView` | Name / title text | +| `subtitleView` | `(Group?) -> UIView` | Member count / subtitle | +| `trailingView` | `(Group?) -> UIView` | Right side content | +| `emptyStateView` | `() -> UIView` | Empty state display | +| `errorStateView` | `() -> UIView` | Error state display | +| `loadingStateView` | `() -> UIView` | Loading state display | - +### listItemView -*** +Replace the entire group row with a custom design. -#### SetListItemView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -With this function, you can assign a custom ListItem to the groups Component. +let groups = CometChatGroups() - - -```swift -let cometChatGroups = CometChatGroups() -cometChatGroups.set(listItemView: { group in - let view = GroupCellView() - return view +groups.set(listItemView: { group in + let customView = CustomGroupCell() + customView.configure(with: group) + return customView }) ``` - - - - -Demonstration - - + CometChatGroups with custom listItemView showing customized group row with avatar, title, member count, and join button -You can create a `CustomListItemView` as a custom `UIView`. Which we will inflate in `setListItemView()` +You can create a `CustomGroupCell` as a custom `UIView`: -```swift swift +```swift lines import UIKit import CometChatSDK -import CometChatUIKitSwift -class GroupCellView: UIView { - - // MARK: - Properties +class CustomGroupCell: UIView { private let avatarImageView: UIImageView = { let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false - imageView.contentMode = .scaleAspectFit - imageView.layer.cornerRadius = 20 // Circular avatar + imageView.contentMode = .scaleAspectFill + imageView.layer.cornerRadius = 20 imageView.clipsToBounds = true + imageView.backgroundColor = .systemGray5 return imageView }() private let titleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 16, weight: .bold) - label.textColor = .black - label.numberOfLines = 1 + label.font = .systemFont(ofSize: 16, weight: .semibold) + label.textColor = .label return label }() - private let subtitleLabel: UILabel = { + private let membersLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 14, weight: .regular) - label.textColor = .darkGray - label.numberOfLines = 1 + label.font = .systemFont(ofSize: 14) + label.textColor = .secondaryLabel return label }() @@ -615,17 +513,13 @@ class GroupCellView: UIView { let button = UIButton(type: .system) button.translatesAutoresizingMaskIntoConstraints = false button.setTitle("JOIN", for: .normal) - button.setTitleColor(.systemBlue, for: .normal) - button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold) + button.titleLabel?.font = .systemFont(ofSize: 12, weight: .bold) button.layer.cornerRadius = 12 button.layer.borderWidth = 1 button.layer.borderColor = UIColor.systemBlue.cgColor - button.clipsToBounds = true return button }() - // MARK: - Initializers - override init(frame: CGRect) { super.init(frame: frame) setupView() @@ -636,40 +530,26 @@ class GroupCellView: UIView { setupView() } - // MARK: - Setup - private func setupView() { - // Add subviews addSubview(avatarImageView) addSubview(titleLabel) - addSubview(subtitleLabel) + addSubview(membersLabel) addSubview(joinButton) - // Constraints for avatarImageView NSLayoutConstraint.activate([ avatarImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), avatarImageView.centerYAnchor.constraint(equalTo: centerYAnchor), avatarImageView.widthAnchor.constraint(equalToConstant: 40), - avatarImageView.heightAnchor.constraint(equalToConstant: 40) - ]) - - // Constraints for titleLabel - NSLayoutConstraint.activate([ + avatarImageView.heightAnchor.constraint(equalToConstant: 40), + titleLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12), - titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8), - titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: joinButton.leadingAnchor, constant: -8) - ]) - - // Constraints for subtitleLabel - NSLayoutConstraint.activate([ - subtitleLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12), - subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4), - subtitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: joinButton.leadingAnchor, constant: -8), - subtitleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8) - ]) - - // Constraints for joinButton - NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12), + titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: joinButton.leadingAnchor, constant: -8), + + membersLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12), + membersLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4), + membersLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12), + joinButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), joinButton.centerYAnchor.constraint(equalTo: centerYAnchor), joinButton.widthAnchor.constraint(equalToConstant: 60), @@ -677,49 +557,52 @@ class GroupCellView: UIView { ]) } - // MARK: - Configuration - - func configure(avatar: UIImage?, title: String, subtitle: String, isJoined: Bool) { - avatarImageView.image = avatar - titleLabel.text = title - subtitleLabel.text = subtitle + func configure(with group: Group) { + titleLabel.text = group.name + membersLabel.text = "\(group.membersCount) members" + + if let iconURL = group.icon, let url = URL(string: iconURL) { + URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in + if let data = data, let image = UIImage(data: data) { + DispatchQueue.main.async { + self?.avatarImageView.image = image + } + } + }.resume() + } + + let isJoined = group.hasJoined joinButton.setTitle(isJoined ? "JOINED" : "JOIN", for: .normal) - joinButton.setTitleColor(isJoined ? .gray : .systemBlue, for: .normal) - joinButton.layer.borderColor = isJoined ? UIColor.gray.cgColor : UIColor.systemBlue.cgColor + joinButton.setTitleColor(isJoined ? .systemGray : .systemBlue, for: .normal) + joinButton.layer.borderColor = isJoined ? UIColor.systemGray.cgColor : UIColor.systemBlue.cgColor } } ``` -*** +### leadingView -#### SetLeadingView +Customize the leading view (avatar area) of a group cell. + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can modify the leading view of a group cell using .set(leadingView:). +let groups = CometChatGroups() - - -```swift -cometChatGroups.set(leadingView: { group in +groups.set(leadingView: { group in let view = CustomLeadingView() - return view -}) + return view +}) ``` - - - - -Demonstration - - + CometChatGroups with custom leadingView showing customized avatar area with icon and join button -You can create a `CustomLeadingView` as a custom `UIView`. Which we will inflate in `setLeadingView()` +You can create a `CustomLeadingView` as a custom `UIView`: - - -```swift +```swift lines import UIKit class CustomLeadingView: UIView { @@ -758,46 +641,38 @@ class CustomLeadingView: UIView { addSubview(joinButton) iconImageView.translatesAutoresizingMaskIntoConstraints = false - joinButton.translatesAutoresizingMask + joinButton.translatesAutoresizingMaskIntoConstraints = false } } ``` - +### titleView - +Customize the title view of a group cell. -*** - -#### SetTitleView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can customize the title view of a group cell using .set(titleView:). +let groups = CometChatGroups() - - -```swift -cometChatGroups.set(titleView: { group in +groups.set(titleView: { group in let view = CustomTitleView() return view -}) +}) ``` - - - - -Demonstration - - + CometChatGroups with custom titleView showing group name with public badge indicator -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +You can create a `CustomTitleView` as a custom `UIView`: + +```swift lines +import UIKit - - -```swift - class CustomTitleView: UIView { +class CustomTitleView: UIView { private let titleLabel: UILabel = { let label = UILabel() @@ -865,41 +740,73 @@ You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate i } ``` - +### subtitleView - +Customize the subtitle area below the group name. -*** +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +let groups = CometChatGroups() + +groups.set(subtitleView: { group in + let view = CustomSubtitleView(membersCount: group.membersCount) + return view +}) +``` -#### SetTrailView + + CometChatGroups with custom subtitleView showing member count and group description text + -You can modify the trailing view of a group cell using .set(trailView:). +You can create a `CustomSubtitleView` as a custom `UIView`: + +```swift lines +import UIKit - - -```swift -cometChatGroups.set(trailView: { group in - let view = CustomTrailView() - return view -}) +class CustomSubtitleView: UILabel { + + init(membersCount: Int) { + super.init(frame: .zero) + self.text = "\(membersCount) members • Group description" + self.textColor = UIColor.gray + self.font = UIFont.systemFont(ofSize: 14) + self.numberOfLines = 1 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} ``` - +### trailingView - +Customize the trailing view (right side) of a group cell. -Demonstration +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +let groups = CometChatGroups() + +groups.set(trailView: { group in + let view = CustomTrailView() + return view +}) +``` - + CometChatGroups with custom trailingView showing joined status badge on the right side -You can create a `CustomTrailView` as a custom `UIView`. Which we will inflate in `setTrailView()` +You can create a `CustomTrailView` as a custom `UIView`: - - -```swift - import UIKit +```swift lines +import UIKit class CustomTrailView: UIView { @@ -935,123 +842,524 @@ class CustomTrailView: UIView { ]) } } +``` + +### loadingStateView + +Customize the loading state view displayed while data is being fetched. + +```swift lines +import UIKit +import CometChatUIKitSwift + +let groups = CometChatGroups() - +let loadingIndicator = UIActivityIndicatorView(style: .medium) +loadingIndicator.startAnimating() +groups.set(loadingView: loadingIndicator) ``` - +### errorStateView - +Customize the error state view displayed when an error occurs. -*** +```swift lines +import UIKit +import CometChatUIKitSwift -#### SetSubTitleView +let groups = CometChatGroups() -You can customize the subtitle view for each group item to meet your requirements +let errorLabel = UILabel() +errorLabel.text = "Something went wrong!" +errorLabel.textColor = .red +groups.set(errorView: errorLabel) +``` - - -```swift -cometChatGroup.set(subtitleView: { group in - let view = CustomSubtitleView() - return view -}) +### emptyStateView + +Customize the empty state view displayed when no groups are available. + +```swift lines +import UIKit +import CometChatUIKitSwift + +let groups = CometChatGroups() + +let emptyLabel = UILabel() +emptyLabel.text = "No groups found" +emptyLabel.textColor = .gray +emptyLabel.textAlignment = .center +groups.set(emptyView: emptyLabel) ``` - +--- - +## Options -**Example** +### set(options:) -Demonstration +Define custom swipe options for each group. This method allows you to return an array of `CometChatGroupOption` based on the group object. These options appear when the user swipes on a group cell. - - - +```swift lines +import CometChatUIKitSwift +import CometChatSDK -You can seamlessly integrate this `CustomSubtitleView` UIView file into the `.set(subtitleView:)` method within CometChatGroups. +let groups = CometChatGroups() - - -```swift -import UIKit +groups.set(options: { group in + // Create a custom delete option + let deleteOption = CometChatGroupOption( + id: "delete", + title: "Delete", + icon: UIImage(systemName: "trash"), + backgroundColor: .systemRed, + onClick: { group, section, option, controller in + // Handle delete action + print("Delete group: \(group.name ?? "")") + } + ) + + // Create a custom mute option + let muteOption = CometChatGroupOption( + id: "mute", + title: "Mute", + icon: UIImage(systemName: "bell.slash"), + backgroundColor: .systemOrange, + onClick: { group, section, option, controller in + // Handle mute action + print("Mute group: \(group.name ?? "")") + } + ) + + return [deleteOption, muteOption] +}) +``` -class CustomSubtitleView: UILabel { +### add(options:) + +Dynamically add additional swipe options to groups while preserving the default options. This method lets you return additional `CometChatGroupOption` elements that will be appended to the existing options. + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let groups = CometChatGroups() + +groups.add(options: { group in + // Add a custom archive option + let archiveOption = CometChatGroupOption( + id: "archive", + title: "Archive", + icon: UIImage(systemName: "archivebox"), + backgroundColor: .systemBlue, + onClick: { group, section, option, controller in + // Handle archive action + print("Archive group: \(group.name ?? "")") + } + ) - init(membersCount: Int) { - super.init(frame: .zero) - self.text = "\(membersCount) members • \("group_description")" - self.textColor = UIColor.gray - self.font = UIFont.systemFont(ofSize: 14) - self.numberOfLines = 1 + return [archiveOption] +}) +``` + +--- + +## Data Manipulation Methods + +### showJoiningGroupAlert(for:) + +Displays an alert dialog when a user attempts to join a password-protected group. This method shows a prompt for the user to enter the group password. + +```swift lines +public func showJoiningGroupAlert(for group: Group) +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `group` | `Group` | The password-protected group to join | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let groups = CometChatGroups() + +// Show joining alert for a password-protected group +groups.set(onItemClick: { [weak self] group, indexPath in + if group.groupType == .password && !group.hasJoined { + self?.groups.showJoiningGroupAlert(for: group) + } else { + // Navigate to group chat } +}) +``` + +### hideJoiningGroupAlert(completion:) + +Dismisses the joining group alert dialog programmatically. Use this when you need to close the alert without user interaction. + +```swift lines +public func hideJoiningGroupAlert(completion: (() -> Void)? = nil) +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `completion` | `(() -> Void)?` | Optional closure called after the alert is dismissed | + +```swift lines +import CometChatUIKitSwift + +let groups = CometChatGroups() + +// Hide the joining alert with a completion handler +groups.hideJoiningGroupAlert { + print("Alert dismissed") +} +``` + +--- + +## Styling + +### Style Hierarchy + +1. Global styles (`CometChatGroups.style`) apply to all instances +2. Instance styles override global for specific instances + +### Global Level Styling + +```swift lines +import UIKit +import CometChatUIKitSwift + +// Apply global styles that affect all CometChatGroups instances +CometChatGroups.style.backgroundColor = UIColor.systemBackground +CometChatGroups.style.titleColor = UIColor.label +CometChatGroups.style.titleFont = UIFont.systemFont(ofSize: 34, weight: .bold) +CometChatGroups.style.listItemTitleTextColor = UIColor.label +CometChatGroups.style.listItemSubTitleTextColor = UIColor.secondaryLabel + +// Custom avatar style +let avatarStyle = AvatarStyle() +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) +CometChatGroups.avatarStyle = avatarStyle +``` + +### Instance Level Styling + +```swift lines +import UIKit +import CometChatUIKitSwift + +// Create a custom style for a specific instance +var customStyle = GroupsStyle() +customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +customStyle.titleColor = UIColor.darkGray +customStyle.listItemBackground = UIColor.white + +let groups = CometChatGroups() +groups.style = customStyle +``` + +### Key Style Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `backgroundColor` | `UIColor` | `CometChatTheme.backgroundColor01` | Background color | +| `titleColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Navigation title color | +| `titleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Navigation title font | +| `listItemTitleTextColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Group name color | +| `listItemTitleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Group name font | +| `listItemSubTitleTextColor` | `UIColor` | `CometChatTheme.textColorSecondary` | Member count color | +| `listItemSubTitleFont` | `UIFont` | `CometChatTypography.Body.regular` | Member count font | +| `listItemBackground` | `UIColor` | `.clear` | List item background | +| `privateGroupBadgeColor` | `UIColor` | `CometChatTheme.iconColorSecondary` | Private group badge color | +| `passwordGroupBadgeColor` | `UIColor` | `CometChatTheme.iconColorSecondary` | Password group badge color | + +### Customization Matrix + +| What to change | Where | Property/API | Example | +|----------------|-------|--------------|---------| +| Background color | Style | `backgroundColor` | `UIColor.systemBackground` | +| Title appearance | Style | `titleColor`, `titleFont` | Custom colors and fonts | +| List item look | Style | `listItemBackground` | `UIColor.white` | +| Avatar appearance | Style | `avatarStyle` | `AvatarStyle()` with custom radius | +| Group type badges | Style | `privateGroupBadgeColor` | Custom badge colors | +| Hide search | Property | `hideSearch` | `groups.hideSearch = true` | +| Hide group type | Property | `hideGroupType` | `groups.hideGroupType = true` | +| Custom row | View Slot | `set(listItemView:)` | See Custom View Slots | + +--- + +## Props + +All props are optional. Sorted alphabetically. + +### avatarStyle + +Customizes the appearance of avatars in group list items. + +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | + +```swift lines +import CometChatUIKitSwift + +let groups = CometChatGroups() + +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor.systemBlue +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) +avatarStyle.borderWidth = 1 +avatarStyle.borderColor = UIColor.systemGray4 + +groups.set(avatarStyle: avatarStyle) +``` + +### groupsRequestBuilder + +Custom request builder for filtering groups. + +| | | +|---|---| +| Type | `GroupsRequest.GroupsRequestBuilder?` | +| Default | `nil` | + +### hideBackButton + +Hides the back button in the navigation bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideErrorView + +Hides the error state view. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideGroupType + +Hides the public/private/password group type icons. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideLoadingState + +Hides the loading state indicator. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideNavigationBar + +Hides the entire navigation bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideSearch + +Hides the search bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideSectionHeader + +Hides the alphabetical section headers. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### searchRequestBuilder + +Custom request builder for search functionality. + +| | | +|---|---| +| Type | `GroupsRequest.GroupsRequestBuilder?` | +| Default | `nil` | + +### selectedCellCount + +Returns the count of currently selected groups when in selection mode. + +| | | +|---|---| +| Type | `Int` | +| Default | `0` | + +```swift lines +import CometChatUIKitSwift + +let groups = CometChatGroups() +groups.selectionMode = .multiple + +// Get the count of selected groups +let selectedCount = groups.selectedCellCount +print("Selected \(selectedCount) groups") +``` + +### selectionLimit + +Sets the maximum number of groups that can be selected in selection mode. When the limit is reached, further selections are disabled. + +| | | +|---|---| +| Type | `Int` | +| Default | `0` (unlimited) | + +```swift lines +import CometChatUIKitSwift + +let groups = CometChatGroups() +groups.selectionMode = .multiple + +// Limit selection to 5 groups +groups.selectionLimit = 5 + +// Handle selection confirmation +groups.onSelectedItemProceed = { selectedGroups in + print("Selected \(selectedGroups.count) groups") - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + // Process the selected groups + for group in selectedGroups { + print("Group: \(group.name ?? "")") } } ``` - +### selectionMode + +Sets the selection mode for multi-select functionality. + +| | | +|---|---| +| Type | `SelectionMode` | +| Default | `.none` | - +### statusIndicatorStyle -*** +Customizes the appearance of group type status indicators. -#### SetLoadingView +| | | +|---|---| +| Type | `StatusIndicatorStyle` | +| Default | `StatusIndicatorStyle()` | -You can set a custom loading view using .set(loadingView:). This method accepts a UIView to display while data is being fetched. +```swift lines +import CometChatUIKitSwift + +let groups = CometChatGroups() + +let statusIndicatorStyle = StatusIndicatorStyle() +statusIndicatorStyle.backgroundColor = UIColor.systemGreen +statusIndicatorStyle.borderWidth = 2 +statusIndicatorStyle.borderColor = UIColor.white - - -```swift -let loadingIndicator = UIActivityIndicatorView(style: .medium) -loadingIndicator.startAnimating() -cometChatGroups.set(loadingView: loadingIndicator) +groups.set(statusIndicatorStyle: statusIndicatorStyle) ``` - +--- + +## Events + +| Event | Payload | Fires when | +|-------|---------|------------| +| `ccGroupCreated` | `Group` | A group is created | +| `ccGroupDeleted` | `Group` | A group is deleted | +| `ccGroupMemberJoined` | `User, Group` | A user joins a group | +| `ccGroupMemberLeft` | `User, Group` | A user leaves a group | - +--- -*** +## Common Patterns -#### SetErrorView +### Public groups only -You can customize the error view using .set(errorView:). This method accepts a UIView that appears when an error occurs. +```swift lines +let publicBuilder = GroupsRequest.GroupsRequestBuilder(limit: 30) + .set(groupType: .public) - - -```swift -let errorLabel = UILabel() -errorLabel.text = "Something went wrong!" -errorLabel.textColor = .red -cometChatGroups.set(errorView: errorLabel) +let groups = CometChatGroups() +groups.set(groupsRequestBuilder: publicBuilder) ``` - +### Joined groups only - +```swift lines +let joinedBuilder = GroupsRequest.GroupsRequestBuilder(limit: 30) + .set(joinedOnly: true) -*** +let groups = CometChatGroups() +groups.set(groupsRequestBuilder: joinedBuilder) +``` -#### SetEmptyView +### Custom empty state with CTA -You can customize the empty state view using .set(emptyView:). This method accepts a UIView that appears when no groups are available. +```swift lines +let groups = CometChatGroups() - - -```swift -let emptyLabel = UILabel() -emptyLabel.text = "No groups found" -emptyLabel.textColor = .gray -emptyLabel.textAlignment = .center -cometChatGroups.set(emptyView: emptyLabel) +groups.set(emptyStateView: { + let emptyView = UIView() + + let label = UILabel() + label.text = "No groups found" + label.textAlignment = .center + + let button = UIButton(type: .system) + button.setTitle("Create a group", for: .normal) + + // Add subviews and constraints... + return emptyView +}) ``` - +### Hide all chrome — minimal list + +```swift lines +let groups = CometChatGroups() +groups.hideSearch = true +groups.hideGroupType = true +groups.hideSectionHeader = true +``` + +### Multi-select groups + +```swift lines +let groups = CometChatGroups() +groups.selectionMode = .multiple + +groups.set(onSelection: { selectedGroups in + print("Selected \(selectedGroups.count) groups") +}) +``` + +--- - +## Related Components -*** +- [Messages](/ui-kit/ios/messages) - Display messages in a group +- [Conversations](/ui-kit/ios/conversations) - List all conversations +- [Users](/ui-kit/ios/users) - List all users +- [Group Members](/ui-kit/ios/group-members) - Manage group members +- [Groups With Messages](/ui-kit/ios/groups-with-messages) - Combined groups and messages view diff --git a/ui-kit/ios/guide-ai-agent.mdx b/ui-kit/ios/guide-ai-agent.mdx index 01fc4ad08..a5c2193fb 100644 --- a/ui-kit/ios/guide-ai-agent.mdx +++ b/ui-kit/ios/guide-ai-agent.mdx @@ -1,27 +1,10 @@ --- title: "AI Agent Integration" sidebarTitle: "AI Agent Integration" +description: "Add AI-powered chat assistants to your iOS app" --- -Enable intelligent conversational AI capabilities in your iOS app using CometChat UIKit v5 with AI Agent integration: - -- **AI Assistant Chat History** -- **Chat History Management** -- **Contextual Responses** -- **Agent Detection** -- **Seamless Handoffs** - -Transform your chat experience with AI-powered assistance that provides intelligent responses and offers seamless integration with your existing chat infrastructure. - -## Overview - -Users can interact with AI agents through a dedicated chat interface that: - -- Provides intelligent responses based on conversation context. -- Maintains chat history for continuity. -- Seamlessly integrates with your existing user chat system. - -The AI Agent chat interface provides a familiar messaging experience enhanced with AI capabilities, accessible through your main chat flow or as a standalone feature. +Integrate AI agents into your iOS app to provide intelligent conversational experiences with chat history, contextual responses, and seamless handoffs. @@ -29,166 +12,520 @@ The AI Agent chat interface provides a familiar messaging experience enhanced wi ## Prerequisites -- **CometChat UIKit for iOS** installed via CocoaPods or Swift Package Manager -- CometChat initialized with `App ID`, `Region`, and `Auth Key` -- Message chat enabled in your CometChat app -- Navigation set up between message and user/group screens -- Internet permissions +Before implementing AI agents, ensure you have: -## Components +- Completed [Getting Started](/ui-kit/ios/getting-started) setup +- CometChat UIKit v5+ installed +- AI features enabled in your [CometChat Dashboard](https://app.cometchat.com) +- User logged in with `CometChatUIKit.login()` -| Component/Class | Role | -|------------------------------ |------------------------------------------------------| -| `CometChatMessageHeader` | Manages message interactions and state | -| `CometChatMessageList` | Displays a list of messages | -| `CometChatMessageComposer` | Composes and sends new messages | -| `CometChatAIAssistantChatHistory` | Displays previous AI conversation history | +## Overview ---- +The AI Agent integration provides: -## Integration Steps +- **Intelligent Responses** - Context-aware AI conversations +- **Chat History** - Browse and resume previous AI sessions +- **Streaming Responses** - Real-time message streaming +- **Custom Styling** - Match your app's design +- **Suggested Messages** - Quick-start prompts for users -### Step 1 - Screen Setup +## Basic Implementation -Create a screen for AI Assistant chat using `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer`. +Create a simple AI chat screen: - - -```swift +```swift lines import UIKit -import CometChatUIKit +import CometChatUIKitSwift +import CometChatSDK + +class AIAgentChatViewController: UIViewController { + + private var user: User? + private var messageHeader: CometChatMessageHeader! + private var messageList: CometChatMessageList! + private var messageComposer: CometChatMessageComposer! + + convenience init(user: User) { + self.init() + self.user = user + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + setupUI() + } + + private func setupUI() { + guard let user = user else { return } + + // Message Header + messageHeader = CometChatMessageHeader() + messageHeader.set(user: user) + messageHeader.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(messageHeader) + + // Message List + messageList = CometChatMessageList() + messageList.set(user: user) + messageList.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(messageList) + + // Message Composer + messageComposer = CometChatMessageComposer() + messageComposer.set(user: user) + messageComposer.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(messageComposer) + + setupConstraints() + } + + private func setupConstraints() { + NSLayoutConstraint.activate([ + messageHeader.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + messageHeader.leadingAnchor.constraint(equalTo: view.leadingAnchor), + messageHeader.trailingAnchor.constraint(equalTo: view.trailingAnchor), + messageHeader.heightAnchor.constraint(equalToConstant: 60), + + messageList.topAnchor.constraint(equalTo: messageHeader.bottomAnchor), + messageList.leadingAnchor.constraint(equalTo: view.leadingAnchor), + messageList.trailingAnchor.constraint(equalTo: view.trailingAnchor), + messageList.bottomAnchor.constraint(equalTo: messageComposer.topAnchor), + + messageComposer.leadingAnchor.constraint(equalTo: view.leadingAnchor), + messageComposer.trailingAnchor.constraint(equalTo: view.trailingAnchor), + messageComposer.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) + ]) + } +} +``` -class AIAssistantChatViewController: UIViewController { +## Production Implementation - var user: User? - var group: Group? - var parentMessage: BaseMessage? - var isHistory: Bool = false +Complete AI agent chat with history, navigation, and error handling: +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ProductionAIAgentViewController: UIViewController { + + // MARK: - Properties + private var user: User? + private var group: Group? + private var parentMessage: BaseMessage? + private var isHistoryMode: Bool = false + + private var messageHeader: CometChatMessageHeader! + private var messageList: CometChatMessageList! + private var messageComposer: CometChatMessageComposer! + + // MARK: - Initialization + convenience init(user: User, parentMessage: BaseMessage? = nil, isHistory: Bool = false) { + self.init() + self.user = user + self.parentMessage = parentMessage + self.isHistoryMode = isHistory + } + + convenience init(group: Group, parentMessage: BaseMessage? = nil, isHistory: Bool = false) { + self.init() + self.group = group + self.parentMessage = parentMessage + self.isHistoryMode = isHistory + } + + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() - setupUI() + view.backgroundColor = .systemBackground + setupMessageHeader() + setupMessageList() + setupMessageComposer() + setupConstraints() } - - func setupUI() { - let messageHeader = CometChatMessageHeader() - messageHeader.user = user - messageHeader.group = group - messageHeader.onBack = { [weak self] in - self?.navigationController?.popViewController(animated: true) + + // MARK: - Setup + private func setupMessageHeader() { + messageHeader = CometChatMessageHeader() + messageHeader.translatesAutoresizingMaskIntoConstraints = false + + if let user = user { + messageHeader.set(user: user) + } else if let group = group { + messageHeader.set(group: group) } - messageHeader.chatHistoryButtonClick = { [weak self] in + + // Back button handler + messageHeader.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) + }) + + // Chat history button handler + messageHeader.onAiChatHistoryClicked = { [weak self] user in self?.openChatHistory() } + view.addSubview(messageHeader) - - let messageList = CometChatMessageList() - messageList.user = user - messageList.group = group + } + + private func setupMessageList() { + messageList = CometChatMessageList() + messageList.translatesAutoresizingMaskIntoConstraints = false messageList.hideThreadView = true + + if let user = user { + messageList.set(user: user) + } else if let group = group { + messageList.set(group: group) + } + + // If resuming from history, set parent message + if let parentMessage = parentMessage { + messageList.set(parentMessage: parentMessage) + } + view.addSubview(messageList) - - let composer = CometChatMessageComposer() - composer.user = user - composer.group = group - view.addSubview(composer) } - - func openChatHistory() { - let chatHistoryVC = CometChatAIAssistantChatHistory() - chatHistoryVC.user = user - chatHistoryVC.group = group - chatHistoryVC.onNewChatButtonClicked = { - self.startNewChat() + + private func setupMessageComposer() { + messageComposer = CometChatMessageComposer() + messageComposer.translatesAutoresizingMaskIntoConstraints = false + + if let user = user { + messageComposer.set(user: user) + } else if let group = group { + messageComposer.set(group: group) + } + + // If resuming from history, set parent message + if let parentMessage = parentMessage { + messageComposer.set(parentMessage: parentMessage) + } + + view.addSubview(messageComposer) + } + + private func setupConstraints() { + NSLayoutConstraint.activate([ + messageHeader.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + messageHeader.leadingAnchor.constraint(equalTo: view.leadingAnchor), + messageHeader.trailingAnchor.constraint(equalTo: view.trailingAnchor), + messageHeader.heightAnchor.constraint(equalToConstant: 60), + + messageList.topAnchor.constraint(equalTo: messageHeader.bottomAnchor), + messageList.leadingAnchor.constraint(equalTo: view.leadingAnchor), + messageList.trailingAnchor.constraint(equalTo: view.trailingAnchor), + messageList.bottomAnchor.constraint(equalTo: messageComposer.topAnchor), + + messageComposer.leadingAnchor.constraint(equalTo: view.leadingAnchor), + messageComposer.trailingAnchor.constraint(equalTo: view.trailingAnchor), + messageComposer.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) + ]) + } + + // MARK: - Chat History + private func openChatHistory() { + let chatHistoryVC = CometChatAIAssistanceChatHistory() + + if let user = user { + chatHistoryVC.set(user: user) + } else if let group = group { + chatHistoryVC.set(group: group) + } + + // Handle new chat button + chatHistoryVC.onNewChatButtonClicked = { [weak self] user in + self?.startNewChat() } + + // Handle message selection to resume conversation chatHistoryVC.onMessageClicked = { [weak self] message in - guard let self = self else { return } - self.parentMessage = message - self.isHistory = true - self.navigationController?.pushViewController( - AIAssistantChatViewController(), - animated: true - ) + self?.resumeConversation(from: message) } - chatHistoryVC.onClose = { - self.navigationController?.popViewController(animated: true) + + // Handle close + chatHistoryVC.onClose = { [weak self] in + self?.navigationController?.popViewController(animated: true) } + navigationController?.pushViewController(chatHistoryVC, animated: true) } + + private func startNewChat() { + let newChatVC: ProductionAIAgentViewController + + if let user = user { + newChatVC = ProductionAIAgentViewController(user: user) + } else if let group = group { + newChatVC = ProductionAIAgentViewController(group: group) + } else { + return + } + + navigationController?.pushViewController(newChatVC, animated: true) + } + + private func resumeConversation(from message: BaseMessage) { + let resumeVC: ProductionAIAgentViewController + + if let user = user { + resumeVC = ProductionAIAgentViewController(user: user, parentMessage: message, isHistory: true) + } else if let group = group { + resumeVC = ProductionAIAgentViewController(group: group, parentMessage: message, isHistory: true) + } else { + return + } + + navigationController?.pushViewController(resumeVC, animated: true) + } +} +``` + +## Launching AI Agent Chat + +Start an AI agent conversation from your app: - func startNewChat() { - navigationController?.pushViewController( - AIAssistantChatViewController(), - animated: true - ) +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatListViewController: UIViewController { + + func openAIAgentChat(agentUID: String) { + // Fetch the AI agent user + CometChat.getUser(UID: agentUID) { [weak self] user in + DispatchQueue.main.async { + // Check if user is an AI agent (role contains "agentic") + if user.role?.lowercased().contains("agentic") == true { + let aiChatVC = ProductionAIAgentViewController(user: user) + self?.navigationController?.pushViewController(aiChatVC, animated: true) + } else { + // Regular user chat + let messages = CometChatMessages() + messages.set(user: user) + self?.navigationController?.pushViewController(messages, animated: true) + } + } + } onError: { error in + print("Error fetching user: \(error?.errorDescription ?? "")") + } + } + + func detectAndOpenChat(for user: User) { + // Detect if user is an AI agent + let isAIAgent = user.role?.lowercased().contains("agentic") == true + + if isAIAgent { + let aiChatVC = ProductionAIAgentViewController(user: user) + navigationController?.pushViewController(aiChatVC, animated: true) + } else { + let messages = CometChatMessages() + messages.set(user: user) + navigationController?.pushViewController(messages, animated: true) + } } } ``` - +## Styling + +Customize the AI chat bubble appearance: + +```swift lines +import UIKit +import CometChatUIKitSwift + +class AIAgentStylingExample { + + func applyGlobalStyles() { + // Configure AI bubble style + var aiBubbleStyle = AIAssistantBubbleStyle() + aiBubbleStyle.backgroundColor = .clear + aiBubbleStyle.borderWidth = 1 + aiBubbleStyle.borderColor = .systemBlue + aiBubbleStyle.textColor = .label + aiBubbleStyle.textFont = UIFont.systemFont(ofSize: 14) + aiBubbleStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 12) + + // Apply globally + CometChatAIAssistantBubble.style = aiBubbleStyle + } + + func applyInstanceStyles() -> ProductionAIAgentViewController { + let aiChatVC = ProductionAIAgentViewController(user: User()) + + // Custom message list style + let messageListStyle = MessageListStyle() + messageListStyle.backgroundColor = UIColor.systemBackground + + // Custom composer style + let composerStyle = MessageComposerStyle() + composerStyle.backgroundColor = UIColor.secondarySystemBackground + composerStyle.borderColor = UIColor.separator + composerStyle.borderWidth = 1 + + return aiChatVC + } +} +``` - +### Style Properties +| Property | Description | +|----------|-------------| +| `backgroundColor` | Bubble background color | +| `borderWidth` | Bubble border width | +| `borderColor` | Bubble border color | +| `textColor` | Message text color | +| `textFont` | Message text font | +| `cornerRadius` | Bubble corner radius | -### Step 2 - Chat History Screen +## Customization Options -Create a screen for AI Assistant chat history using `CometChatAIAssistantChatHistory`. +### Empty State View -Features Implemented:: -- Browse their previous AI chat sessions. -- Resume a previous conversation (onMessageClicked). -- Start a new chat session (onNewChatButtonClicked). -- Close the chat history view (onClose). +Customize the view shown when there are no messages: -### Step 3 - Custom Styles +```swift lines +let emptyView = UIView() +let label = UILabel() +label.text = "Start a conversation with AI" +label.textAlignment = .center +label.textColor = .secondaryLabel +emptyView.addSubview(label) -Define custom styles for AI chat bubbles and the composer using `CometChatAiAssistantBubbleStyle`. +messageList.set(emptyStateView: emptyView) +``` +### Streaming Speed - - -```swift -import UIKit -import CometChatUIKit +Adjust how fast AI responses stream: -let aiBubbleStyle = AiAssistantBubbleStyle() -aiBubbleStyle.backgroundColor = .clear -aiBubbleStyle.border = Border(width: 1, color: .systemBlue) -aiBubbleStyle.textColor = UIColor(named: "TextPrimary") -aiBubbleStyle.textStyle = UIFont(name: "TimesNewRoman", size: 14) -CometChatAiAssistantBubble.style = aiBubbleStyle +```swift lines +// Configure streaming speed (characters per second) +messageList.set(streamingSpeed: 50) ``` - - +### Suggested Messages ---- +Provide quick-start prompts for users: -## Implementation Flow Summary +```swift lines +let suggestions = [ + "What can you help me with?", + "Tell me about your capabilities", + "How do I get started?" +] -| Step | Action | -|:-----|:-------------------------------------------------------------------------------| -| 1 | User selects AI agent from chat list | -| 2 | `AIAssistantChatViewController` launches | -| 3 | Parse User data and detect agent chat (Role must be `@agentic`) | -| 4 | Initialize UI with AI-specific styling | -| 5 | Configure chat history and navigation | -| 6 | Launch chat with AI agent | +messageComposer.set(suggestedMessages: suggestions) +``` ---- +### AI Assistant Tools -## Customization Options +Configure custom tools for the AI agent: -- **Custom AI Assistant Empty Chat View:** Customize using `emptyStateView`. -- **Streaming Speed:** Adjust AI response streaming speed with `streamingSpeed`. -- **AI Assistant Suggested Messages:** Set quick prompts using `suggestedMessages`. -- **AI Assistant Tools:** Set AI agent tools using `setAiAssistantTools` callback. +```swift lines +messageComposer.set(aiAssistantTools: { message in + // Return custom tools based on context + return [ + AITool(name: "search", description: "Search knowledge base"), + AITool(name: "calculate", description: "Perform calculations") + ] +}) +``` ---- +## Chat History Component + +The `CometChatAIAssistanceChatHistory` component displays previous AI conversations: -## Feature Matrix +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatHistoryViewController: UIViewController { + + private var user: User? + + convenience init(user: User) { + self.init() + self.user = user + } + + override func viewDidLoad() { + super.viewDidLoad() + setupChatHistory() + } + + private func setupChatHistory() { + guard let user = user else { return } + + let chatHistory = CometChatAIAssistanceChatHistory() + chatHistory.set(user: user) + + // New chat button + chatHistory.onNewChatButtonClicked = { [weak self] user in + let newChat = ProductionAIAgentViewController(user: user) + self?.navigationController?.pushViewController(newChat, animated: true) + } + + // Resume conversation + chatHistory.onMessageClicked = { [weak self] message in + let resumeChat = ProductionAIAgentViewController( + user: user, + parentMessage: message, + isHistory: true + ) + self?.navigationController?.pushViewController(resumeChat, animated: true) + } + + // Close handler + chatHistory.onClose = { [weak self] in + self?.dismiss(animated: true) + } + + addChild(chatHistory) + view.addSubview(chatHistory.view) + chatHistory.view.frame = view.bounds + chatHistory.didMove(toParent: self) + } +} +``` -| Feature | Implementation | UI Component | -|:-----------------------|:-------------------------------------------- |:---------------------- | -| AI Chat | `AIAssistantChatViewController` | Full chat screen | -| Chat History | `CometChatAIAssistantChatHistory` | Chat history screen | +## Implementation Flow + +| Step | Action | +|------|--------| +| 1 | User selects AI agent from chat list | +| 2 | Detect agent by checking user role for "agentic" | +| 3 | Launch `ProductionAIAgentViewController` | +| 4 | Configure header, message list, and composer | +| 5 | User sends message, AI responds with streaming | +| 6 | Access chat history via header button | + +## Components Reference + +| Component | Purpose | +|-----------|---------| +| `CometChatMessageHeader` | Navigation and chat history access | +| `CometChatMessageList` | Display messages with AI responses | +| `CometChatMessageComposer` | Send messages to AI agent | +| `CometChatAIAssistanceChatHistory` | Browse previous AI conversations | +| `CometChatAIAssistantBubble` | AI message bubble styling | + +## Related Guides + + + + Overview of all AI-powered features + + + Browse and resume AI conversations + + + Display and customize chat messages + + diff --git a/ui-kit/ios/guide-block-unblock-user.mdx b/ui-kit/ios/guide-block-unblock-user.mdx index 7920f5ed8..1f684f018 100644 --- a/ui-kit/ios/guide-block-unblock-user.mdx +++ b/ui-kit/ios/guide-block-unblock-user.mdx @@ -1,178 +1,705 @@ --- -title: "Implementing Block/Unblock User in iOS with CometChat UIKit" +title: "Block/Unblock User" sidebarTitle: "Block/Unblock User" +description: "Implement user blocking and profile management in your iOS app" --- -Build a comprehensive user profile screen in your iOS app using CometChat’s UIKit for iOS, complete with avatar display, messaging, audio/video calls, and block/unblock actions. - -## Overview - -The `UserDetailsViewController` provides a detailed view of a CometChat user’s profile and key interaction options, including: - -- Displaying the user’s avatar, name, and online status. -- Initiating one-on-one chats. -- Starting audio or video calls. -- Blocking or unblocking users. -- Deleting the conversation with the user. +Build a user profile screen with avatar display, messaging, audio/video calls, and block/unblock functionality using CometChat UIKit. ## Prerequisites -- A UIKit-based iOS project. -- CometChat UIKit for iOS v5 installed via CocoaPods or Swift Package Manager. -- Valid CometChat **App ID**, **Region**, and **Auth Key**. -- User authenticated with `CometChat.login()` before presenting the details screen. +Before implementing this feature, ensure you have: + +- Completed [Getting Started](/ui-kit/ios/getting-started) setup +- CometChat UIKit v5+ installed +- User logged in with `CometChatUIKit.login()` +- Navigation controller configured -## Components +## Overview -| Component | Role | -|:----------------------------------|:--------------------------------------------------------------| -| `CometChatAvatar` | Displays user’s profile picture with customizable styling. | -| `CometChatMessagesViewController`| Opens the 1-on-1 chat interface when “Message” is tapped. | -| `CometChatCallButtons` | Initiates audio/video calls (`CometChat.startCall()`). | -| `CometChatUIKit.blockUser()` | Blocks the selected user and updates UI accordingly. | -| `CometChatUIKit.unblockUser()` | Unblocks a user if previously blocked. | +The user details screen provides: -## Integration Steps +- **Profile Display** - Avatar, name, and online status +- **Messaging** - Start one-on-one chats +- **Calling** - Audio and video call buttons +- **Block/Unblock** - Manage user relationships +- **Delete Conversation** - Remove chat history -### 1. Presenting the User Details Screen +## Basic Implementation -Initialize and push `UserDetailsViewController` with the selected user’s data. +Create a simple user details screen: -```swift +```swift lines import UIKit +import CometChatUIKitSwift import CometChatSDK -func showUserDetails(for user: User) { - let detailsVC = UserDetailsViewController(user: user) - navigationController?.pushViewController(detailsVC, animated: true) +class UserDetailsViewController: UIViewController { + + private var user: User? + + convenience init(user: User) { + self.init() + self.user = user + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + setupUI() + } + + private func setupUI() { + guard let user = user else { return } + + // Avatar + let avatar = CometChatAvatar() + avatar.set(user: user) + avatar.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(avatar) + + // Name label + let nameLabel = UILabel() + nameLabel.text = user.name + nameLabel.font = .systemFont(ofSize: 24, weight: .bold) + nameLabel.textAlignment = .center + nameLabel.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(nameLabel) + + // Status label + let statusLabel = UILabel() + statusLabel.text = user.status == .online ? "Online" : "Offline" + statusLabel.textColor = user.status == .online ? .systemGreen : .secondaryLabel + statusLabel.font = .systemFont(ofSize: 14) + statusLabel.textAlignment = .center + statusLabel.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(statusLabel) + + // Message button + let messageButton = UIButton(type: .system) + messageButton.setTitle("Message", for: .normal) + messageButton.setImage(UIImage(systemName: "message.fill"), for: .normal) + messageButton.addTarget(self, action: #selector(openChat), for: .touchUpInside) + messageButton.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(messageButton) + + // Block button + let blockButton = UIButton(type: .system) + blockButton.setTitle("Block User", for: .normal) + blockButton.setTitleColor(.systemRed, for: .normal) + blockButton.addTarget(self, action: #selector(blockUser), for: .touchUpInside) + blockButton.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(blockButton) + + NSLayoutConstraint.activate([ + avatar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40), + avatar.centerXAnchor.constraint(equalTo: view.centerXAnchor), + avatar.widthAnchor.constraint(equalToConstant: 100), + avatar.heightAnchor.constraint(equalToConstant: 100), + + nameLabel.topAnchor.constraint(equalTo: avatar.bottomAnchor, constant: 16), + nameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + + statusLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 8), + statusLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + + messageButton.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 32), + messageButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + + blockButton.topAnchor.constraint(equalTo: messageButton.bottomAnchor, constant: 24), + blockButton.centerXAnchor.constraint(equalTo: view.centerXAnchor) + ]) + } + + @objc private func openChat() { + guard let user = user else { return } + let messages = CometChatMessages() + messages.set(user: user) + navigationController?.pushViewController(messages, animated: true) + } + + @objc private func blockUser() { + guard let user = user else { return } + CometChat.blockUsers([user.uid ?? ""]) { [weak self] _ in + DispatchQueue.main.async { + self?.showAlert(title: "Blocked", message: "\(user.name ?? "User") has been blocked") + } + } onError: { error in + print("Block error: \(error?.errorDescription ?? "")") + } + } + + private func showAlert(title: String, message: String) { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } } ``` -**File reference:** -[`UserDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/UserDetailsViewController.swift) +## Production Implementation + +Complete user details screen with all features and event handling: + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK +#if canImport(CometChatCallsSDK) +import CometChatCallsSDK +#endif + +class ProductionUserDetailsViewController: UIViewController { + + // MARK: - Properties + private var user: User? + private var isBlocked: Bool = false + private let listenerID = "user-details-listener" + + // MARK: - UI Components + private let scrollView = UIScrollView() + private let contentView = UIView() + private let avatar = CometChatAvatar() + private let nameLabel = UILabel() + private let statusLabel = UILabel() + private let buttonStackView = UIStackView() + private let messageButton = UIButton(type: .system) + private let audioCallButton = UIButton(type: .system) + private let videoCallButton = UIButton(type: .system) + private let blockButton = UIButton(type: .system) + private let deleteButton = UIButton(type: .system) + + // MARK: - Initialization + convenience init(user: User) { + self.init() + self.user = user + } + + // MARK: - Lifecycle + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + setupUI() + configureWithUser() + checkBlockStatus() + addEventListeners() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + setupNavigationBar() + } + + deinit { + removeEventListeners() + } + + // MARK: - Setup + private func setupNavigationBar() { + title = "User Details" + navigationController?.navigationBar.prefersLargeTitles = false + } + + private func setupUI() { + // Scroll View + scrollView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(scrollView) + + contentView.translatesAutoresizingMaskIntoConstraints = false + scrollView.addSubview(contentView) + + // Avatar + avatar.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(avatar) + + // Name Label + nameLabel.font = .systemFont(ofSize: 24, weight: .bold) + nameLabel.textAlignment = .center + nameLabel.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(nameLabel) + + // Status Label + statusLabel.font = .systemFont(ofSize: 14) + statusLabel.textAlignment = .center + statusLabel.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(statusLabel) + + // Button Stack + buttonStackView.axis = .horizontal + buttonStackView.spacing = 24 + buttonStackView.distribution = .equalSpacing + buttonStackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(buttonStackView) + + // Message Button + configureButton(messageButton, title: "Message", icon: "message.fill", action: #selector(openChat)) + buttonStackView.addArrangedSubview(messageButton) + + // Call Buttons (conditional) + #if canImport(CometChatCallsSDK) + configureButton(audioCallButton, title: "Audio", icon: "phone.fill", action: #selector(startAudioCall)) + configureButton(videoCallButton, title: "Video", icon: "video.fill", action: #selector(startVideoCall)) + buttonStackView.addArrangedSubview(audioCallButton) + buttonStackView.addArrangedSubview(videoCallButton) + #endif + + // Block Button + blockButton.setTitle("Block User", for: .normal) + blockButton.setTitleColor(.systemRed, for: .normal) + blockButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium) + blockButton.addTarget(self, action: #selector(toggleBlock), for: .touchUpInside) + blockButton.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(blockButton) + + // Delete Button + deleteButton.setTitle("Delete Conversation", for: .normal) + deleteButton.setTitleColor(.systemRed, for: .normal) + deleteButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium) + deleteButton.addTarget(self, action: #selector(deleteConversation), for: .touchUpInside) + deleteButton.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(deleteButton) + + setupConstraints() + } + + private func configureButton(_ button: UIButton, title: String, icon: String, action: Selector) { + button.setTitle(title, for: .normal) + button.setImage(UIImage(systemName: icon), for: .normal) + button.titleLabel?.font = .systemFont(ofSize: 12) + button.tintColor = .systemBlue + button.configuration = .plain() + button.configuration?.imagePlacement = .top + button.configuration?.imagePadding = 8 + button.addTarget(self, action: action, for: .touchUpInside) + } + + private func setupConstraints() { + NSLayoutConstraint.activate([ + scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + + contentView.topAnchor.constraint(equalTo: scrollView.topAnchor), + contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), + contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), + contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), + + avatar.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 40), + avatar.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + avatar.widthAnchor.constraint(equalToConstant: 100), + avatar.heightAnchor.constraint(equalToConstant: 100), + + nameLabel.topAnchor.constraint(equalTo: avatar.bottomAnchor, constant: 16), + nameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20), + nameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20), + + statusLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 8), + statusLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + + buttonStackView.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 32), + buttonStackView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + + blockButton.topAnchor.constraint(equalTo: buttonStackView.bottomAnchor, constant: 48), + blockButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + + deleteButton.topAnchor.constraint(equalTo: blockButton.bottomAnchor, constant: 16), + deleteButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + deleteButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -40) + ]) + } -Ensures the details screen loads with the correct user context. + // MARK: - Configuration + private func configureWithUser() { + guard let user = user else { return } + + avatar.set(user: user) + nameLabel.text = user.name + updateStatusLabel(user: user) + } + + private func updateStatusLabel(user: User) { + if isBlocked { + statusLabel.text = "Blocked" + statusLabel.textColor = .systemRed + } else { + statusLabel.text = user.status == .online ? "Online" : "Offline" + statusLabel.textColor = user.status == .online ? .systemGreen : .secondaryLabel + } + } + + private func checkBlockStatus() { + guard let uid = user?.uid else { return } + + let request = BlockedUserRequest.BlockedUserRequestBuilder() + .set(limit: 100) + .build() + + request.fetchNext { [weak self] blockedUsers in + let isBlocked = blockedUsers?.contains { $0.uid == uid } ?? false + DispatchQueue.main.async { + self?.isBlocked = isBlocked + self?.updateBlockButton() + self?.updateStatusLabel(user: self?.user ?? User()) + } + } onError: { error in + print("Error checking block status: \(error?.errorDescription ?? "")") + } + } + + private func updateBlockButton() { + let title = isBlocked ? "Unblock User" : "Block User" + blockButton.setTitle(title, for: .normal) + } + + // MARK: - Actions + @objc private func openChat() { + guard let user = user else { return } + + if isBlocked { + showAlert(title: "User Blocked", message: "Unblock this user to send messages") + return + } + + let messages = CometChatMessages() + messages.set(user: user) + navigationController?.pushViewController(messages, animated: true) + } + + #if canImport(CometChatCallsSDK) + @objc private func startAudioCall() { + guard let user = user else { return } + + if isBlocked { + showAlert(title: "User Blocked", message: "Unblock this user to make calls") + return + } + + let call = Call(receiverId: user.uid ?? "", callType: .audio, receiverType: .user) + CometChat.initiateCall(call: call) { call in + print("Audio call initiated: \(call?.sessionID ?? "")") + } onError: { [weak self] error in + self?.showAlert(title: "Call Failed", message: error?.errorDescription ?? "Unable to start call") + } + } + + @objc private func startVideoCall() { + guard let user = user else { return } + + if isBlocked { + showAlert(title: "User Blocked", message: "Unblock this user to make calls") + return + } + + let call = Call(receiverId: user.uid ?? "", callType: .video, receiverType: .user) + CometChat.initiateCall(call: call) { call in + print("Video call initiated: \(call?.sessionID ?? "")") + } onError: { [weak self] error in + self?.showAlert(title: "Call Failed", message: error?.errorDescription ?? "Unable to start call") + } + } + #endif + + @objc private func toggleBlock() { + if isBlocked { + unblockUser() + } else { + showBlockConfirmation() + } + } + + private func showBlockConfirmation() { + let alert = UIAlertController( + title: "Block User", + message: "Are you sure you want to block \(user?.name ?? "this user")? They won't be able to send you messages or call you.", + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + alert.addAction(UIAlertAction(title: "Block", style: .destructive) { [weak self] _ in + self?.blockUser() + }) + + present(alert, animated: true) + } + + private func blockUser() { + guard let uid = user?.uid else { return } + + CometChat.blockUsers([uid]) { [weak self] blockedUsers in + DispatchQueue.main.async { + self?.isBlocked = true + self?.updateBlockButton() + self?.updateStatusLabel(user: self?.user ?? User()) + + // Emit event for other components + if let user = self?.user { + CometChatUserEvents.ccUserBlocked(user: user) + } + } + } onError: { [weak self] error in + self?.showAlert(title: "Error", message: error?.errorDescription ?? "Failed to block user") + } + } + + private func unblockUser() { + guard let uid = user?.uid else { return } + + CometChat.unblockUsers([uid]) { [weak self] unblockedUsers in + DispatchQueue.main.async { + self?.isBlocked = false + self?.updateBlockButton() + self?.updateStatusLabel(user: self?.user ?? User()) + + // Emit event for other components + if let user = self?.user { + CometChatUserEvents.ccUserUnblocked(user: user) + } + } + } onError: { [weak self] error in + self?.showAlert(title: "Error", message: error?.errorDescription ?? "Failed to unblock user") + } + } + + @objc private func deleteConversation() { + let alert = UIAlertController( + title: "Delete Conversation", + message: "Are you sure you want to delete this conversation? This action cannot be undone.", + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { [weak self] _ in + self?.performDeleteConversation() + }) + + present(alert, animated: true) + } + + private func performDeleteConversation() { + guard let uid = user?.uid else { return } + + CometChat.deleteConversation(conversationWith: uid, conversationType: .user) { [weak self] _ in + DispatchQueue.main.async { + self?.showAlert(title: "Deleted", message: "Conversation has been deleted") + } + } onError: { [weak self] error in + self?.showAlert(title: "Error", message: error?.errorDescription ?? "Failed to delete conversation") + } + } + + private func showAlert(title: String, message: String) { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } -### 2. Configuring the UI + // MARK: - Event Listeners + private func addEventListeners() { + CometChat.addUserListener(listenerID, self) + CometChatUserEvents.addListener(listenerID, self) + } + + private func removeEventListeners() { + CometChat.removeUserListener(listenerID) + CometChatUserEvents.removeListener(listenerID) + } +} -Arrange avatar, labels, and action buttons on the view. +// MARK: - CometChatUserDelegate +extension ProductionUserDetailsViewController: CometChatUserDelegate { + + func onUserOnline(user: User) { + guard user.uid == self.user?.uid else { return } + DispatchQueue.main.async { + self.user = user + self.updateStatusLabel(user: user) + } + } + + func onUserOffline(user: User) { + guard user.uid == self.user?.uid else { return } + DispatchQueue.main.async { + self.user = user + self.updateStatusLabel(user: user) + } + } +} -```swift -override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - setupLayout() - setupNavigationBar() - if let user = user { - updateUserStatus(user: user) +// MARK: - CometChatUserEventListener +extension ProductionUserDetailsViewController: CometChatUserEventListener { + + func ccUserBlocked(user: User) { + guard user.uid == self.user?.uid else { return } + DispatchQueue.main.async { + self.isBlocked = true + self.updateBlockButton() + self.updateStatusLabel(user: user) + } + } + + func ccUserUnblocked(user: User) { + guard user.uid == self.user?.uid else { return } + DispatchQueue.main.async { + self.isBlocked = false + self.updateBlockButton() + self.updateStatusLabel(user: user) + } } } ``` -**File reference:** -[`UserDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/UserDetailsViewController.swift) - -Applies theme-based styling and updates status label on appearance. +## Launching User Details -### 3. Enabling Call Buttons +Open the user details screen from your app: -Add audio and video call buttons if calls SDK is available. +```swift lines +import UIKit +import CometChatSDK -```swift -#if canImport(CometChatCallsSDK) -buttonContainerStackView.addArrangedSubview(audioCallButton) -buttonContainerStackView.addArrangedSubview(videoCallButton) -#endif +class UsersListViewController: UIViewController { + + func showUserDetails(for user: User) { + let detailsVC = ProductionUserDetailsViewController(user: user) + navigationController?.pushViewController(detailsVC, animated: true) + } + + // From a users list + func openFromUsersList() { + let users = CometChatUsers() + users.set(onItemClick: { [weak self] user, _ in + self?.showUserDetails(for: user) + }) + navigationController?.pushViewController(users, animated: true) + } + + // From a conversation + func openFromConversation(_ conversation: Conversation) { + if let user = conversation.conversationWith as? User { + showUserDetails(for: user) + } + } +} ``` -**File reference:** -[`UserDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/UserDetailsViewController.swift) +## Block/Unblock API Reference + +### Block Users -Conditionally shows call options based on SDK availability. +```swift lines +// Block single user +CometChat.blockUsers(["user-uid"]) { blockedUsers in + print("Blocked \(blockedUsers?.count ?? 0) users") +} onError: { error in + print("Error: \(error?.errorDescription ?? "")") +} -### 4. Block/Unblock and Delete Actions +// Block multiple users +CometChat.blockUsers(["user1", "user2", "user3"]) { blockedUsers in + print("Blocked users: \(blockedUsers?.map { $0.uid ?? "" } ?? [])") +} onError: { error in + print("Error: \(error?.errorDescription ?? "")") +} +``` -Provide block/unblock and delete conversation functionality. +### Unblock Users -```swift -@objc func showBlockAlert() { - // Toggle block/unblock logic with CometChat.blockUsers / unblockUsers +```swift lines +// Unblock single user +CometChat.unblockUsers(["user-uid"]) { unblockedUsers in + print("Unblocked \(unblockedUsers?.count ?? 0) users") +} onError: { error in + print("Error: \(error?.errorDescription ?? "")") } -@objc func showDeleteAlert() { - // Confirm and call CometChat.deleteConversation() +// Unblock multiple users +CometChat.unblockUsers(["user1", "user2"]) { unblockedUsers in + print("Unblocked users: \(unblockedUsers?.map { $0.uid ?? "" } ?? [])") +} onError: { error in + print("Error: \(error?.errorDescription ?? "")") } ``` -**File reference:** -[`UserDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/UserDetailsViewController.swift) +### Fetch Blocked Users -Manages user relationships and conversation lifecycle. +```swift lines +let request = BlockedUserRequest.BlockedUserRequestBuilder() + .set(limit: 50) + .set(direction: .blockedByMe) // or .hasBlockedMe, .both + .build() -### 5. Listening for User Events +request.fetchNext { blockedUsers in + for user in blockedUsers ?? [] { + print("Blocked: \(user.name ?? "")") + } +} onError: { error in + print("Error: \(error?.errorDescription ?? "")") +} +``` -Update UI in response to status, block, and unblock events. +## Styling -```swift -func connect() { - CometChat.addUserListener(listenerID, self) - CometChatUserEvents.addListener(listenerID, self) -} +Customize the avatar appearance: -func disconnect() { - CometChat.removeUserListener(listenerID) - CometChatUserEvents.removeListener(listenerID) -} +```swift lines +let avatarStyle = AvatarStyle() +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 50) +avatarStyle.borderWidth = 2 +avatarStyle.borderColor = .systemBlue +avatarStyle.backgroundColor = .systemGray5 -extension UserDetailsViewController: CometChatUserEventListener, CometChatUserDelegate { - func onUserOnline(user: User) { updateUserStatus(user: user) } - func onUserOffline(user: User) { updateUserStatus(user: user) } - func ccUserBlocked(user: User) { statusLabel.isHidden = true } - func ccUserUnblocked(user: User) { statusLabel.isHidden = false; updateUserStatus(user: user) } -} +avatar.set(style: avatarStyle) ``` -**File reference:** -[`UserDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/UserDetailsViewController.swift) +## Components Reference -Keeps profile status and block state in sync with real-time events. +| Component | Purpose | +|-----------|---------| +| `CometChatAvatar` | Display user profile picture | +| `CometChatMessages` | Open chat interface | +| `CometChat.blockUsers()` | Block users | +| `CometChat.unblockUsers()` | Unblock users | +| `CometChat.deleteConversation()` | Delete chat history | +| `CometChat.initiateCall()` | Start audio/video calls | -## Customization Options +## Edge Cases -- **Avatar Styling:** Use `CometChatAvatarStyle` to adjust shape and border. -- **Button Assets:** Replace default icons with custom images. -- **Localization:** Override button titles and alerts with localized strings. -- **Theming:** Leverage `CometChatTheme` and `CometChatTypography` for fonts and colors. +- **Self-blocking**: Hide block controls when viewing your own profile +- **Already blocked**: Check block status before showing chat/call options +- **Call SDK unavailable**: Conditionally show call buttons with `#if canImport(CometChatCallsSDK)` +- **Missing user data**: Show placeholder UI for incomplete profiles -## Filtering & Edge Cases +## Error Handling -- Hide block/unblock controls for the logged-in user. -- Disable call buttons if calling is disabled in settings. -- Handle missing or partially loaded user data with fallback UI. +| Error | Solution | +|-------|----------| +| Block failed | Show retry option, check network | +| Unblock failed | Verify user was previously blocked | +| Call initiation failed | Check permissions and call SDK setup | +| Delete conversation failed | Verify conversation exists | -## Error Handling +## Related Guides + + + + Display and manage user list + + + Handle user and block events + + + View and manage conversations + + + +--- -- **Fetch Failures:** Show error label or dismiss the view. -- **Block/Unblock Errors:** Present retry alert on API failure. -- **Call Failures:** Alert user on call initiation error or permission denial. - -## Feature Matrix - -| Feature | Component / Method | -|:-------------------------|:---------------------------------------------| -| Display user details | `CometChatAvatar`, `UILabel` | -| Open chat | `CometChatMessagesViewController(user:)` | -| Audio/video call | `CometChat.startCall()` via Call Buttons | -| Block user | `CometChatUIKit.blockUser(uid:)` | -| Unblock user | `CometChatUIKit.unblockUser(uid:)` | -| Delete conversation | `CometChat.deleteConversation()` | - - - - Try the complete sample app for User Details: - [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) + + + Complete implementation example - - Explore CometChat UIKit iOS repository: - [GitHub → UIKit v5](https://github.com/cometchat/cometchat-uikit-ios/tree/v5) + + CometChat UIKit iOS repository - \ No newline at end of file + diff --git a/ui-kit/ios/guide-call-log-details.mdx b/ui-kit/ios/guide-call-log-details.mdx index 89cd141c0..b0ce1dc4f 100644 --- a/ui-kit/ios/guide-call-log-details.mdx +++ b/ui-kit/ios/guide-call-log-details.mdx @@ -1,145 +1,255 @@ --- -title: "CometChat UIKit iOS — Call Log Details" +title: "Call Log Details" sidebarTitle: "Call Log Details" +description: "Display call history, participants, and recordings in your iOS app" --- -Learn how to integrate and customize CometChat’s call log components to display call history, participant details, and call recordings in your iOS UIKit chat app. +Learn how to integrate and customize CometChat's call log components to display call history, participant details, and call recordings in your iOS app. ## Overview -The `CallLogDetailsVC` module provides a tabbed interface to view details of past calls: +The `CallLogDetailsVC` module provides a tabbed interface for viewing details of past calls: -- **History:** Chronological join/leave events. -- **Participants:** Users who joined the call. -- **Recordings:** Links to cloud-hosted call recordings. +- **History** — Chronological join/leave events with timestamps +- **Participants** — Users who joined the call +- **Recordings** — Links to cloud-hosted call recordings -This ensures transparency and auditability for both users and admins. +This ensures transparency and auditability for both users and administrators. ## Prerequisites -- A UIKit-based iOS project. -- **CometChatSDK**, **CometChatCallsSDK**, and **CometChatUIKitSwift** integrated. -- Active internet connection. -- A valid, logged-in CometChat user. +Before implementing call log details, ensure you have: + +- Completed [Getting Started](/ui-kit/ios/getting-started) setup +- CometChat UIKit v5+ installed +- CometChatCallsSDK integrated +- User logged in with `CometChatUIKit.login()` +- Active internet connection ## Components -| Component | Role | -|-----------------------------|----------------------------------------------------------------------------------------| -| `CallLogDetailsVC` | Main container with segmented control and page view. | -| `CallLogParticipantsVC` | Displays a list of users who participated in the call. | -| `CallLogHistoryVC` | Shows join/leave history entries with timestamps and statuses. | -| `CallLogRecordingsVC` | Lists call recordings with playback actions. | -| `CallLogDetailsHeaderView` | Header view showing call metadata (title, status, duration). | -| `CallLogUserCell` | UITableViewCell for participants, history, and recordings entries. | -| `CallLogDetailsModel` | Data model formatting participants, history, and recordings data. | -| `CallLogViewModel` | Fetches and distributes call log data to the UI components. | +| Component | Description | +|-----------|-------------| +| `CallLogDetailsVC` | Main container with segmented control and page view | +| `CallLogParticipantsVC` | Displays a list of users who participated in the call | +| `CallLogHistoryVC` | Shows join/leave history entries with timestamps and statuses | +| `CallLogRecordingsVC` | Lists call recordings with playback actions | +| `CallLogDetailsHeaderView` | Header view showing call metadata (title, status, duration) | +| `CallLogUserCell` | UITableViewCell for participants, history, and recordings entries | +| `CallLogDetailsModel` | Data model formatting participants, history, and recordings data | +| `CallLogViewModel` | Fetches and distributes call log data to the UI components | ## Integration Steps -### 1. Present Call Log Details Screen - -Show the call log interface for a selected call. - -```swift -let detailsVC = CallLogDetailsVC(call: call) -navigationController?.pushViewController(detailsVC, animated: true) +### Step 1: Present Call Log Details Screen + +Show the call log interface for a selected call: + +```swift lines +import UIKit +import CometChatSDK +import CometChatCallsSDK + +class CallLogsViewController: UIViewController { + + func showCallDetails(for call: CallLog) { + // Initialize the call log details view controller + let detailsVC = CallLogDetailsVC(call: call) + + // Push onto navigation stack + navigationController?.pushViewController(detailsVC, animated: true) + } +} ``` -**File reference:** -[`CallLogDetailsVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/CallLogDetailsVC.swift) +This bundles history, participants, and recordings into a single UI flow. -Bundles history, participants, and recordings into a single UI flow. +**File reference:** [`CallLogDetailsVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/CallLogDetailsVC.swift) -### 2. Display Participants List +### Step 2: Display Participants List -Populate the participants tab with the call’s members. +Populate the participants tab with the call's members: -```swift -participantsTableView.reloadData() +```swift lines +import UIKit +import CometChatSDK + +class CallLogParticipantsVC: UIViewController { + + var participants: [Participant] = [] + @IBOutlet weak var participantsTableView: UITableView! + + func loadParticipants() { + // Fetch participants from call log data + // ... + + // Reload table view to display participants + participantsTableView.reloadData() + } +} ``` -**File reference:** -[`CallLogParticipantsVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20Participants/CallLogParticipantsVC.swift) +This provides an audit trail of who was present in the call. + +**File reference:** [`CallLogParticipantsVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20Participants/CallLogParticipantsVC.swift) -Audits who was present in the call. +### Step 3: Show Call History -### 3. Show Call History +Render join/leave activities in chronological order: -Render join/leave activities in chronological order. +```swift lines +import UIKit -```swift -history.append(CallHistoryEntry(...)) -tableView.reloadData() +class CallLogHistoryVC: UIViewController { + + var history: [CallHistoryEntry] = [] + @IBOutlet weak var tableView: UITableView! + + func addHistoryEntry(user: String, action: String, timestamp: Date) { + // Create and append new history entry + let entry = CallHistoryEntry(user: user, action: action, timestamp: timestamp) + history.append(entry) + + // Refresh the table view + tableView.reloadData() + } +} ``` -**File references:** -- [`CallHistoyTVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20History%20/CallHistoyTVC.swift) +This tracks user join/leave times for transparency. + +**File references:** +- [`CallHistoyTVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20History%20/CallHistoyTVC.swift) - [`CallLogHistoryVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20History%20/CallLogHistoryVC.swift) -Tracks user join/leave times for transparency. +### Step 4: List and Play Recordings -### 4. List and Play Recordings +Provide playback links for any recorded calls: -Provide playback links for any recorded calls. +```swift lines +import UIKit -```swift -UIApplication.shared.open(url) +class CallLogRecordingsVC: UIViewController { + + func playRecording(url: URL) { + // Open recording URL in default browser/player + UIApplication.shared.open(url) + } +} ``` -**File references:** -- [`CallLogRecordingsVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20Recording%20/CallLogRecordingsVC.swift) -- [`CallRecordingTVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20Recording%20/CallRecordingTVC.swift) +This enables administrators and users to review call content (if recording is enabled). -Enables admins and users to review call content (if recording enabled). +**File references:** +- [`CallLogRecordingsVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20Recording%20/CallLogRecordingsVC.swift) +- [`CallRecordingTVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details/Call%20Recording%20/CallRecordingTVC.swift) ## Customization Options -- **Styling:** Customize colors, fonts, and spacing via `CometChatTheme`, `CometChatTypography`, and `CometChatSpacing` in `CallLogUserCell` and `CallLogDetailsHeaderView`. -- **Filters:** Use `CallLogViewModel` to filter by call type (incoming, outgoing, missed). -- **Empty States:** Implement an `EmptyStateView` in `CallLogHistoryVC` for no-history scenarios. +### Styling -## Filtering & Edge Cases +Customize colors, fonts, and spacing using CometChat's theming system: -- **No Call Logs:** Show a custom empty state instead of a blank table. -- **Pagination:** Add lazy loading in `scrollViewDidScroll` of `CallLogHistoryVC` to fetch more entries. -- **Blocked Users:** In `CallLogParticipantsVC`, disable profile navigation if the user is blocked. +```swift lines +import CometChatUIKitSwift -## Error Handling +// Apply custom theme to call log components +let theme = CometChatTheme() +theme.palette.primary = UIColor.systemBlue + +// Apply typography +let typography = CometChatTypography() +typography.heading = UIFont.systemFont(ofSize: 18, weight: .bold) -- **Network/API Errors:** Display `UIAlertController` on fetch failures; expose error via `CallLogViewModel` delegate. -- **Retry Mechanism:** Add pull-to-refresh or a retry button in `CallLogDetailsVC`. -- **Recording Unavailable:** Gracefully disable playback links if URL is missing. +// Apply spacing +let spacing = CometChatSpacing() +spacing.padding = 16 +``` -## Optional Notes +### Filters -- **Group Calls vs 1:1 Calls:** Customize `CallLogParticipantsVC` display based on call type and participant roles. -- **Metadata Display:** Use `CallLogDetailsHeaderView` to show titles, call duration, and status icons. +Use `CallLogViewModel` to filter by call type: -## Feature Matrix +```swift lines +// Filter by call type +viewModel.filterByType(.incoming) // Show only incoming calls +viewModel.filterByType(.outgoing) // Show only outgoing calls +viewModel.filterByType(.missed) // Show only missed calls +``` + +### Empty States + +Implement an `EmptyStateView` in `CallLogHistoryVC` for no-history scenarios: -| Feature | Component / Method | File(s) | -|:-----------------------------|:----------------------------------|:--------------------------------------------------------------------------------------------------| -| Show call log details screen | `CallLogDetailsVC(call:)` | `CallLogDetailsVC.swift` | -| Display participants | `CallLogParticipantsVC` | `CallLogParticipantsVC.swift` | -| Display history entries | `CallLogHistoryVC` | `CallHistoyTVC.swift`, `CallLogHistoryVC.swift` | -| List recordings | `CallLogRecordingsVC` | `CallLogRecordingsVC.swift`, `CallRecordingTVC.swift` | -| Header metadata | `CallLogDetailsHeaderView` | `CallLogDetailsHeaderView.swift` | -| Data handling | `CallLogDetailsModel` | `CallLogDetailsModel.swift` | -| Data fetching & distribution | `CallLogViewModel` | `CallLogViewModel.swift` | +```swift lines +func showEmptyState() { + let emptyView = UILabel() + emptyView.text = "No call history available" + emptyView.textAlignment = .center + emptyView.textColor = .secondaryLabel + tableView.backgroundView = emptyView +} +``` + +## Edge Cases - +| Scenario | Handling | +|----------|----------| +| No call logs | Show a custom empty state instead of a blank table | +| Large history | Add lazy loading in `scrollViewDidScroll` to fetch more entries | +| Blocked users | Disable profile navigation in `CallLogParticipantsVC` if the user is blocked | +| Missing recording URL | Gracefully disable playback links | - -Explore a full sample implementation: -[GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) +## Error Handling - +| Error Type | Solution | +|------------|----------| +| Network/API errors | Display `UIAlertController` on fetch failures; expose error via `CallLogViewModel` delegate | +| Retry mechanism | Add pull-to-refresh or a retry button in `CallLogDetailsVC` | +| Recording unavailable | Gracefully disable playback links if URL is missing | - -Review the call log components in the UIKit library: -[GitHub → Call Log Components](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp/View%20Controllers/CometChat%20Components/Call%20Log%20Details) +## Additional Notes - +- **Group Calls vs 1:1 Calls** — Customize `CallLogParticipantsVC` display based on call type and participant roles +- **Metadata Display** — Use `CallLogDetailsHeaderView` to show titles, call duration, and status icons + +## Feature Matrix - \ No newline at end of file +| Feature | Component / Method | File(s) | +|---------|-------------------|---------| +| Show call log details screen | `CallLogDetailsVC(call:)` | `CallLogDetailsVC.swift` | +| Display participants | `CallLogParticipantsVC` | `CallLogParticipantsVC.swift` | +| Display history entries | `CallLogHistoryVC` | `CallHistoyTVC.swift`, `CallLogHistoryVC.swift` | +| List recordings | `CallLogRecordingsVC` | `CallLogRecordingsVC.swift`, `CallRecordingTVC.swift` | +| Header metadata | `CallLogDetailsHeaderView` | `CallLogDetailsHeaderView.swift` | +| Data handling | `CallLogDetailsModel` | `CallLogDetailsModel.swift` | +| Data fetching & distribution | `CallLogViewModel` | `CallLogViewModel.swift` | + +## Related Components + +- [Call Logs](/ui-kit/ios/call-logs) - Display call log list +- [Call Features](/ui-kit/ios/call-features) - Overview of calling capabilities +- [Ongoing Call](/ui-kit/ios/ongoing-call) - Active call interface + + + + Explore a full sample implementation + + + Review the call log components in the UIKit library + + + +## Related Guides + + + + Display call history list + + + Overview of calling capabilities + + + Handle call events + + diff --git a/ui-kit/ios/guide-group-chat.mdx b/ui-kit/ios/guide-group-chat.mdx index dd71cfe6d..a9bfc3287 100644 --- a/ui-kit/ios/guide-group-chat.mdx +++ b/ui-kit/ios/guide-group-chat.mdx @@ -1,6 +1,7 @@ --- title: "Group Details" sidebarTitle: "Group Details" +description: "Display and manage group information in your iOS app" --- Provide a detailed view for CometChat groups in your iOS app, enabling users to see group info, join/leave, manage members, and respond to real-time group events. @@ -9,113 +10,230 @@ Provide a detailed view for CometChat groups in your iOS app, enabling users to `GroupDetailsViewController` displays comprehensive group information and actions: -- **Group Info:** Name, icon, description, and member count. -- **Actions:** Join/Leave/Delete group. -- **Member Management:** View members, add members, view banned members. -- **Real-Time Updates:** Reflects joins, leaves, bans, and ownership changes. +- **Group Info** — Name, icon, description, and member count +- **Actions** — Join, leave, or delete group +- **Member Management** — View members, add members, view banned members +- **Real-Time Updates** — Reflects joins, leaves, bans, and ownership changes ## Prerequisites -- A UIKit-based iOS project. -- CometChat UIKit for iOS v5 installed via CocoaPods or Swift Package Manager. -- Valid CometChat **App ID**, **Region**, and **Auth Key**. -- User logged in with `CometChat.login()`. -- Navigation stack (`UINavigationController`) configured. +Before implementing group details, ensure you have: + +- Completed [Getting Started](/ui-kit/ios/getting-started) setup +- CometChat UIKit v5+ installed via CocoaPods or Swift Package Manager +- Valid CometChat App ID, Region, and Auth Key +- User logged in with `CometChatUIKit.login()` +- Navigation controller (`UINavigationController`) configured ## Components -| Component | Role | -|:------------------------------|:----------------------------------------------------------------| -| `CometChatGroup` | Renders group avatar, name, and metadata. | -| `GroupActionView` | Custom view for action buttons (view/add/banned members). | -| `CometChatMessagesViewController` | Opens group chat interface when “Chat” is tapped. | -| `CometChat.joinGroup()` | Joins public or password-protected groups. | -| `CometChat.leaveGroup()` | Leaves the current group. | -| `CometChat.deleteGroup()` | Deletes and exits the group (owners only). | -| `CometChatGroupMembers` | Lists current group members. | -| `CometChatGroupDelegate` | Receives real-time group events. | +| Component | Description | +|-----------|-------------| +| `CometChatGroup` | Renders group avatar, name, and metadata | +| `GroupActionView` | Custom view for action buttons (view/add/banned members) | +| `CometChatMessagesViewController` | Opens group chat interface when "Chat" is tapped | +| `CometChat.joinGroup()` | Joins public or password-protected groups | +| `CometChat.leaveGroup()` | Leaves the current group | +| `CometChat.deleteGroup()` | Deletes and exits the group (owners only) | +| `CometChatGroupMembers` | Lists current group members | +| `CometChatGroupDelegate` | Receives real-time group events | ## Integration Steps -### 1. Presenting the Group Details Screen +### Step 1: Present the Group Details Screen -Push `GroupDetailsViewController` for a selected group. +Push `GroupDetailsViewController` for a selected group: -```swift +```swift lines import UIKit import CometChatSDK -func showGroupDetails(for group: Group) { - let detailsVC = GroupDetailsViewController() - detailsVC.group = group - navigationController?.pushViewController(detailsVC, animated: true) +class GroupListViewController: UIViewController { + + func showGroupDetails(for group: Group) { + // Initialize the group details view controller + let detailsVC = GroupDetailsViewController() + detailsVC.group = group + + // Push onto navigation stack + navigationController?.pushViewController(detailsVC, animated: true) + } } ``` -**File reference:** -[`HomeScreenViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/HomeScreenViewController.swift) +This initializes and presents the details UI with the correct group context. -Initializes and presents the details UI with the correct group context. +**File reference:** [`HomeScreenViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/HomeScreenViewController.swift) -### 2. Setting Up the UI +### Step 2: Set Up the UI -Configure scroll view, header, and action views. +Configure scroll view, header, and action views: -```swift -override public func viewDidLoad() { - super.viewDidLoad() - connect() - view.backgroundColor = CometChatTheme.backgroundColor01 - setupScrollView() - setupLayout() - addButtonActions() +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class GroupDetailsViewController: UIViewController { + + var group: Group? + + override public func viewDidLoad() { + super.viewDidLoad() + + // Connect to group event listeners + connect() + + // Apply theme + view.backgroundColor = CometChatTheme.backgroundColor01 + + // Set up UI components + setupScrollView() + setupLayout() + addButtonActions() + } + + private func setupScrollView() { + // Configure scroll view for content + } + + private func setupLayout() { + // Arrange header, info, and action views + } } ``` -**File reference:** -[`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) +This lays out the UI components and registers for group events. + +**File reference:** [`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) -Lays out the UI components and registers for group events. +### Step 3: Enable Group Action Buttons -### 3. Enabling Group Action Buttons +Wire up view/add/banned members actions: -Wire up view/add/banned members actions. +```swift lines +// Action views for member management +private let viewMembersView = GroupActionView() +private let addMembersView = GroupActionView() +private let bannedMembersView = GroupActionView() -```swift public func addButtonActions() { - viewMembersView.onActionButtonTapped = { self.viewMembers() } - addMembersView.onActionButtonTapped = { self.addMembers() } - bannedMembersView.onActionButtonTapped = { self.banMembers() } + // View current group members + viewMembersView.onActionButtonTapped = { [weak self] in + self?.viewMembers() + } + + // Add new members to the group + addMembersView.onActionButtonTapped = { [weak self] in + self?.addMembers() + } + + // View banned members + bannedMembersView.onActionButtonTapped = { [weak self] in + self?.banMembers() + } } -``` -**File reference:** -[`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) +private func viewMembers() { + guard let group = group else { return } + let membersVC = CometChatGroupMembers() + membersVC.set(group: group) + navigationController?.pushViewController(membersVC, animated: true) +} -Enables user interaction for member management. +private func addMembers() { + // Present add members interface +} + +private func banMembers() { + // Present banned members list +} +``` -### 4. Handling Leave and Delete Actions +This enables user interaction for member management. + +**File reference:** [`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) + +### Step 4: Handle Leave and Delete Actions + +Provide ownership-aware leave/delete flows: + +```swift lines +@objc func showLeaveGroupAlert() { + guard let group = group else { return } + + let alert = UIAlertController( + title: "Leave Group", + message: "Are you sure you want to leave this group?", + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + alert.addAction(UIAlertAction(title: "Leave", style: .destructive) { [weak self] _ in + self?.leaveGroup() + }) + + present(alert, animated: true) +} -Provide ownership-aware leave/delete flows. +@objc func showDeleteGroupAlert() { + guard let group = group else { return } + + let alert = UIAlertController( + title: "Delete Group", + message: "Are you sure you want to delete this group? This action cannot be undone.", + preferredStyle: .alert + ) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { [weak self] _ in + self?.deleteGroup() + }) + + present(alert, animated: true) +} -```swift -@objc func showLeaveGroupAlert() { /* ownership transfer or leave logic */ } +private func leaveGroup() { + guard let guid = group?.guid else { return } + + CometChat.leaveGroup(GUID: guid) { [weak self] _ in + DispatchQueue.main.async { + self?.navigationController?.popToRootViewController(animated: true) + } + } onError: { error in + print("Leave group error: \(error?.errorDescription ?? "")") + } +} -@objc func showDeleteGroupAlert() { /* deleteGroup and pop to Home */ } +private func deleteGroup() { + guard let guid = group?.guid else { return } + + CometChat.deleteGroup(GUID: guid) { [weak self] _ in + DispatchQueue.main.async { + self?.navigationController?.popToRootViewController(animated: true) + } + } onError: { error in + print("Delete group error: \(error?.errorDescription ?? "")") + } +} ``` -**File reference:** -[`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) +This manages group exit, with transfer prompt for owners. -Manages group exit, with transfer prompt for owners. +**File reference:** [`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) -### 5. Listening for Group Events +### Step 5: Listen for Group Events -Update UI on member joins, leaves, bans, and ownership changes. +Update UI on member joins, leaves, bans, and ownership changes: + +```swift lines +private let listenerId = "group-details-listener" -```swift func connect() { + // Add SDK group listener CometChat.addGroupListener(listenerId, self) + + // Add UIKit group events listener CometChatGroupEvents.addListener(listenerId, self) } @@ -124,57 +242,153 @@ func disconnect() { CometChatGroupEvents.removeListener(listenerId) } -extension GroupDetailsViewController: CometChatGroupDelegate, CometChatGroupEventListener { - func onGroupMemberJoined(_ action: ActionMessage, user: User, group: Group) { updateGroupInfo(group) } - func onGroupMemberLeft(_ action: ActionMessage, user: User, group: Group) { /* hide UI if self-left */ } - // other event methods... +deinit { + disconnect() } ``` -**File reference:** -[`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift#L200-L245) +```swift lines +// MARK: - CometChatGroupDelegate +extension GroupDetailsViewController: CometChatGroupDelegate { + + func onGroupMemberJoined(action: ActionMessage, joinedUser: User, joinedGroup: Group) { + updateGroupInfo(joinedGroup) + } + + func onGroupMemberLeft(action: ActionMessage, leftUser: User, leftGroup: Group) { + // Hide UI if current user left + if leftUser.uid == CometChat.getLoggedInUser()?.uid { + navigationController?.popViewController(animated: true) + } else { + updateGroupInfo(leftGroup) + } + } + + func onGroupMemberKicked(action: ActionMessage, kickedUser: User, kickedBy: User, kickedFrom: Group) { + updateGroupInfo(kickedFrom) + } + + func onGroupMemberBanned(action: ActionMessage, bannedUser: User, bannedBy: User, bannedFrom: Group) { + updateGroupInfo(bannedFrom) + } + + func onGroupMemberUnbanned(action: ActionMessage, unbannedUser: User, unbannedBy: User, unbannedFrom: Group) { + updateGroupInfo(unbannedFrom) + } + + func onGroupMemberScopeChanged(action: ActionMessage, scopeChangeduser: User, scopeChangedBy: User, scopeChangedTo: String, scopeChangedFrom: String, group: Group) { + updateGroupInfo(group) + } + + func onMemberAddedToGroup(action: ActionMessage, addedBy: User, addedUser: User, addedTo: Group) { + updateGroupInfo(addedTo) + } +} -Keeps the group details in sync with back-end events. +// MARK: - CometChatGroupEventListener +extension GroupDetailsViewController: CometChatGroupEventListener { + + func ccOwnershipChanged(group: Group, newOwner: GroupMember) { + updateGroupInfo(group) + } +} + +private func updateGroupInfo(_ group: Group) { + self.group = group + // Refresh UI with updated group data +} +``` + +This keeps the group details in sync with back-end events. + +**File reference:** [`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift#L200-L245) ## Customization Options -- **Header Styling:** Use `CometChatTheme` to customize fonts, colors, and borders. -- **Button Labels:** Localize or rebrand action texts. -- **Avatar Placeholder:** Provide fallback initials or default images. +### Header Styling + +Use `CometChatTheme` to customize fonts, colors, and borders: + +```swift lines +// Apply custom theme +CometChatTheme.palette.primary = UIColor.systemBlue +CometChatTheme.typography.heading = UIFont.systemFont(ofSize: 20, weight: .bold) +``` + +### Button Labels + +Localize or rebrand action texts: + +```swift lines +viewMembersView.setTitle("View Members", for: .normal) +addMembersView.setTitle("Add Members", for: .normal) +bannedMembersView.setTitle("Banned Members", for: .normal) +``` -## Filtering & Edge Cases +### Avatar Placeholder -- **Private/Protected Groups:** Prompt for a password before joining. -- **Already a Member:** Hide or disable Join button. -- **Empty Group:** Show an empty state when no members. -- **Owner Restrictions:** Disable Delete for non-owners. +Provide fallback initials or default images: + +```swift lines +avatarView.set(name: group.name) +avatarView.set(image: UIImage(named: "default_group_avatar")) +``` + +## Edge Cases + +| Scenario | Handling | +|----------|----------| +| Private/Protected groups | Prompt for a password before joining | +| Already a member | Hide or disable Join button | +| Empty group | Show an empty state when no members | +| Owner restrictions | Disable Delete for non-owners | ## Error Handling -- **Join Failures:** Show alert on network or permission errors. -- **Leave/Delete Errors:** Display retry prompt on API failure. -- **Event Errors:** Log and notify user if group events fail. +| Error Type | Solution | +|------------|----------| +| Join failures | Show alert on network or permission errors | +| Leave/Delete errors | Display retry prompt on API failure | +| Event errors | Log and notify user if group events fail | ## Feature Matrix -| Feature | Component / Method | File(s) | -|:-----------------------|:------------------------------|:--------------------------------------------------------------------------------| -| Show group details | `GroupDetailsViewController` | `GroupDetailsViewController.swift` | -| View group members | `viewMembersView` action | `GroupDetailsViewController.swift` | -| Add members | `addMembersView` action | `GroupDetailsViewController.swift` | -| Ban members | `bannedMembersView` action | `GroupDetailsViewController.swift` | -| Join group | `CometChat.joinGroup()` | `GroupDetailsViewController.swift` | -| Leave group | `showLeaveGroupAlert()` | `GroupDetailsViewController.swift` | -| Delete group | `showDeleteGroupAlert()` | `GroupDetailsViewController.swift` | -| Real-time updates | `CometChatGroupDelegate` | `GroupDetailsViewController.swift` | - - - - Explore the complete Group Details flow: - [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) +| Feature | Component / Method | File(s) | +|---------|-------------------|---------| +| Show group details | `GroupDetailsViewController` | `GroupDetailsViewController.swift` | +| View group members | `viewMembersView` action | `GroupDetailsViewController.swift` | +| Add members | `addMembersView` action | `GroupDetailsViewController.swift` | +| Ban members | `bannedMembersView` action | `GroupDetailsViewController.swift` | +| Join group | `CometChat.joinGroup()` | `GroupDetailsViewController.swift` | +| Leave group | `showLeaveGroupAlert()` | `GroupDetailsViewController.swift` | +| Delete group | `showDeleteGroupAlert()` | `GroupDetailsViewController.swift` | +| Real-time updates | `CometChatGroupDelegate` | `GroupDetailsViewController.swift` | + +## Related Components + +- [Groups](/ui-kit/ios/groups) - Display group list +- [Group Members](/ui-kit/ios/group-members) - Display group member list +- [Events](/ui-kit/ios/events) - Listen for chat events + + + + Explore the complete Group Details flow + + + Browse the Group Details implementation + + + +## Related Guides + + + + Display and manage group list + + + View and manage group membership - - Browse the Group Details implementation: - [GitHub → GroupDetailsViewController.swift](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) + + Handle group and membership events - \ No newline at end of file + diff --git a/ui-kit/ios/guide-group-ownership.mdx b/ui-kit/ios/guide-group-ownership.mdx index 1ee408e80..12e88eb40 100644 --- a/ui-kit/ios/guide-group-ownership.mdx +++ b/ui-kit/ios/guide-group-ownership.mdx @@ -1,185 +1,410 @@ --- title: "Transfer Group Ownership" sidebarTitle: "Transfer Group Ownership" +description: "Enable group owners to transfer ownership to another member" --- -Enable the current group owner to delegate ownership to another member using CometChat’s UIKit for iOS. +Enable the current group owner to delegate ownership to another member using CometChat's UIKit for iOS. ## Overview -The **Transfer Group Ownership** feature provides a modal interface where the group owner can: +The Transfer Group Ownership feature provides a modal interface where the group owner can: -- See a list of current group members (excluding themselves). -- Select exactly one member to become the new owner. -- Trigger the ownership transfer API call. -- Automatically exit the group after successful transfer. +- See a list of current group members (excluding themselves) +- Select exactly one member to become the new owner +- Trigger the ownership transfer API call +- Automatically exit the group after successful transfer ## Prerequisites -- A UIKit-based iOS project. -- CometChat UIKit for iOS v5 installed via CocoaPods or Swift Package Manager. -- CometChat SDKs (`CometChatSDK`, `CometChatUIKitSwift`) integrated. -- Logged-in user with `CometChat.login()`. -- `UINavigationController` or modal presentation flow set up. -- Group context (GUID) available when invoking the transfer screen. +Before implementing ownership transfer, ensure you have: + +- Completed [Getting Started](/ui-kit/ios/getting-started) setup +- CometChat UIKit v5+ installed via CocoaPods or Swift Package Manager +- CometChatSDK and CometChatUIKitSwift integrated +- User logged in with `CometChatUIKit.login()` +- `UINavigationController` or modal presentation flow set up +- Group context (GUID) available when invoking the transfer screen ## Components -| Component | Responsibility | -|:------------------------------------|:--------------------------------------------------------------------| -| `TransferOwnership` | Subclass of `CometChatGroupMembers` enabling single selection mode. | -| `viewModel.groupMembers` | Data source array of `GroupMember` objects. | -| `onSelectedItemProceed` | Closure invoked when user confirms selection. | -| `CometChat.transferGroupOwnership` | API call to delegate group ownership. | -| `spinnerView` | `UIActivityIndicatorView` showing loading state. | -| `leaveGroupCallback` | Callback to perform group exit after transfer. | +| Component | Description | +|-----------|-------------| +| `TransferOwnership` | Subclass of `CometChatGroupMembers` enabling single selection mode | +| `viewModel.groupMembers` | Data source array of `GroupMember` objects | +| `onSelectedItemProceed` | Closure invoked when user confirms selection | +| `CometChat.transferGroupOwnership` | API call to delegate group ownership | +| `spinnerView` | `UIActivityIndicatorView` showing loading state | +| `leaveGroupCallback` | Callback to perform group exit after transfer | ## Integration Steps -### 1. Present Transfer Ownership Screen - -Show the ownership transfer UI modally. - -```swift -func showTransferOwnership(for group: Group) { - let transferVC = TransferOwnership() - transferVC.set(group: group) - let nav = UINavigationController(rootViewController: transferVC) - present(nav, animated: true) +### Step 1: Present Transfer Ownership Screen + +Show the ownership transfer UI modally: + +```swift lines +import UIKit +import CometChatSDK +import CometChatUIKitSwift + +class GroupDetailsViewController: UIViewController { + + var group: Group? + + func showTransferOwnership(for group: Group) { + // Initialize transfer ownership view controller + let transferVC = TransferOwnership() + transferVC.set(group: group) + + // Set callback for after transfer completes + transferVC.leaveGroupCallback = { [weak self] in + self?.leaveGroup() + } + + // Present modally with navigation + let nav = UINavigationController(rootViewController: transferVC) + present(nav, animated: true) + } + + private func leaveGroup() { + // Handle leaving group after ownership transfer + navigationController?.popToRootViewController(animated: true) + } } ``` -**File reference:** -[`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) - -### 2. Configure Single Selection Mode - -Restrict selection to one member and capture selection. - -```swift -override func viewDidLoad() { - selectionMode = .single - super.viewDidLoad() - title = "OWNERSHIP_TRANSFER".localize() - onSelectedItemProceed = { [weak self] users in - if let newOwner = users.first { - self?.transferOwnership(to: newOwner) +**File reference:** [`GroupDetailsViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/DetailsPage/GroupDetailsViewController.swift) + +### Step 2: Configure Single Selection Mode + +Restrict selection to one member and capture selection: + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class TransferOwnership: CometChatGroupMembers { + + var leaveGroupCallback: (() -> Void)? + + private let spinnerView: UIActivityIndicatorView = { + let spinner = UIActivityIndicatorView(style: .medium) + spinner.hidesWhenStopped = true + return spinner + }() + + override func viewDidLoad() { + // Enable single selection mode + selectionMode = .single + + super.viewDidLoad() + + // Set navigation title + title = "OWNERSHIP_TRANSFER".localize() + + // Handle member selection + onSelectedItemProceed = { [weak self] users in + if let newOwner = users.first as? GroupMember { + self?.transferOwnership(to: newOwner) + } + } } - } } ``` -**File reference:** -[`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L1-L30) +**File reference:** [`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L1-L30) -### 3. Load & Filter Member List +### Step 3: Load and Filter Member List -Exclude the current owner from the selectable list. +Exclude the current owner from the selectable list: -```swift +```swift lines override func reloadData() { - super.reloadData() - viewModel.reload = { [weak self] in - guard let self = self else { return } - let currentUID = CometChat.getLoggedInUser()?.uid - self.viewModel.groupMembers.removeAll { $0.uid == currentUID } - DispatchQueue.main.async { - self.removeLoadingView() - self.removeErrorView() - self.reload() - if self.viewModel.groupMembers.isEmpty { self.showEmptyView() } + super.reloadData() + + viewModel.reload = { [weak self] in + guard let self = self else { return } + + // Get current user's UID + let currentUID = CometChat.getLoggedInUser()?.uid + + // Remove current owner from the list + self.viewModel.groupMembers.removeAll { $0.uid == currentUID } + + DispatchQueue.main.async { + // Update UI state + self.removeLoadingView() + self.removeErrorView() + self.reload() + + // Show empty state if no eligible members + if self.viewModel.groupMembers.isEmpty { + self.showEmptyView() + } + } } - } } ``` -**File reference:** -[`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L31-L60) +**File reference:** [`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L31-L60) -### 4. Perform Ownership Transfer +### Step 4: Perform Ownership Transfer -Call the API, emit event, and exit the group. +Call the API, emit event, and exit the group: -```swift +```swift lines func transferOwnership(to member: GroupMember) { - addSpinnerView() - let uid = member.uid ?? "" - let guid = viewModel.group.guid - - CometChat.transferGroupOwnership(UID: uid, GUID: guid) { [weak self] _ in - DispatchQueue.main.async { - // Update local state - self?.viewModel.group.owner = uid - CometChatGroupEvents.ccOwnershipChanged(group: self!.viewModel.group, newOwner: member) - self?.leaveGroupCallback?() - self?.removeSpinnerView() - self?.dismiss(animated: true) + // Show loading indicator + addSpinnerView() + + let uid = member.uid ?? "" + let guid = viewModel.group.guid + + CometChat.transferGroupOwnership(UID: uid, GUID: guid) { [weak self] successMessage in + DispatchQueue.main.async { + guard let self = self else { return } + + // Update local group state + self.viewModel.group.owner = uid + + // Emit ownership changed event for other components + CometChatGroupEvents.ccOwnershipChanged( + group: self.viewModel.group, + newOwner: member + ) + + // Execute leave group callback + self.leaveGroupCallback?() + + // Hide loading and dismiss + self.removeSpinnerView() + self.dismiss(animated: true) + } + } onError: { [weak self] error in + DispatchQueue.main.async { + self?.removeSpinnerView() + + // Show error alert + let alert = UIAlertController( + title: "Transfer Failed", + message: error?.errorDescription ?? "Unable to transfer ownership", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + self?.present(alert, animated: true) + } } - } onError: { [weak self] error in - DispatchQueue.main.async { - self?.removeSpinnerView() - // TODO: Show error alert - } - } } ``` -**File reference:** -[`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L61-L100) +**File reference:** [`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L61-L100) -### 5. Manage Loading State +### Step 5: Manage Loading State -Provide visual feedback during network calls. +Provide visual feedback during network calls: -```swift +```swift lines func addSpinnerView() { - spinnerView.startAnimating() - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: spinnerView) + // Start spinner animation + spinnerView.startAnimating() + + // Replace right bar button with spinner + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: spinnerView) } func removeSpinnerView() { - spinnerView.stopAnimating() - navigationItem.rightBarButtonItem = nil + // Stop spinner animation + spinnerView.stopAnimating() + + // Remove spinner from navigation bar + navigationItem.rightBarButtonItem = nil } ``` -**File reference:** -[`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L101-L130) +**File reference:** [`TransferOwnership.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift#L101-L130) + +## Complete Implementation + +Here's the complete `TransferOwnership` class: + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class TransferOwnership: CometChatGroupMembers { + + // MARK: - Properties + var leaveGroupCallback: (() -> Void)? + + private let spinnerView: UIActivityIndicatorView = { + let spinner = UIActivityIndicatorView(style: .medium) + spinner.hidesWhenStopped = true + return spinner + }() + + // MARK: - Lifecycle + override func viewDidLoad() { + selectionMode = .single + super.viewDidLoad() + + title = "Transfer Ownership" + + onSelectedItemProceed = { [weak self] users in + if let newOwner = users.first as? GroupMember { + self?.transferOwnership(to: newOwner) + } + } + } + + // MARK: - Data Loading + override func reloadData() { + super.reloadData() + + viewModel.reload = { [weak self] in + guard let self = self else { return } + + let currentUID = CometChat.getLoggedInUser()?.uid + self.viewModel.groupMembers.removeAll { $0.uid == currentUID } + + DispatchQueue.main.async { + self.removeLoadingView() + self.removeErrorView() + self.reload() + + if self.viewModel.groupMembers.isEmpty { + self.showEmptyView() + } + } + } + } + + // MARK: - Transfer Ownership + func transferOwnership(to member: GroupMember) { + addSpinnerView() + + let uid = member.uid ?? "" + let guid = viewModel.group.guid + + CometChat.transferGroupOwnership(UID: uid, GUID: guid) { [weak self] _ in + DispatchQueue.main.async { + guard let self = self else { return } + + self.viewModel.group.owner = uid + CometChatGroupEvents.ccOwnershipChanged( + group: self.viewModel.group, + newOwner: member + ) + + self.leaveGroupCallback?() + self.removeSpinnerView() + self.dismiss(animated: true) + } + } onError: { [weak self] error in + DispatchQueue.main.async { + self?.removeSpinnerView() + self?.showError(error) + } + } + } + + // MARK: - Loading State + func addSpinnerView() { + spinnerView.startAnimating() + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: spinnerView) + } + + func removeSpinnerView() { + spinnerView.stopAnimating() + navigationItem.rightBarButtonItem = nil + } + + // MARK: - Error Handling + private func showError(_ error: CometChatException?) { + let alert = UIAlertController( + title: "Transfer Failed", + message: error?.errorDescription ?? "Unable to transfer ownership", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + present(alert, animated: true) + } +} +``` ## Customization Options -- **Title Text:** Replace localization key with custom string. -- **Spinner Style:** Adjust `spinnerView.style` and color using `CometChatTheme`. -- **Error Handling:** Customize error alerts in the `onError` closure. +### Title Text + +Replace localization key with custom string: + +```swift lines +title = "Select New Owner" +``` + +### Spinner Style + +Adjust `spinnerView.style` and color using `CometChatTheme`: -## Filtering & Edge Cases +```swift lines +spinnerView.style = .large +spinnerView.color = CometChatTheme.palette.primary +``` + +### Error Handling + +Customize error alerts in the `onError` closure: + +```swift lines +let alert = UIAlertController( + title: "Oops!", + message: "Could not transfer ownership. Please try again.", + preferredStyle: .alert +) +alert.addAction(UIAlertAction(title: "Retry", style: .default) { [weak self] _ in + self?.transferOwnership(to: member) +}) +alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) +present(alert, animated: true) +``` + +## Edge Cases -- **Empty Member List:** Show an informative empty state when no eligible members exist. -- **Network Failures:** Disable proceed button until connection restores. -- **Blocked Members:** Exclude or disable blocked users from selection. +| Scenario | Handling | +|----------|----------| +| Empty member list | Show an informative empty state when no eligible members exist | +| Network failures | Disable proceed button until connection restores | +| Blocked members | Exclude or disable blocked users from selection | ## Error Handling -- **Transfer Failures:** Present `UIAlertController` with retry option. -- **Unexpected States:** Ensure `removeSpinnerView()` always executes in `defer`. +| Error Type | Solution | +|------------|----------| +| Transfer failures | Present `UIAlertController` with retry option | +| Unexpected states | Ensure `removeSpinnerView()` always executes in `defer` | ## Feature Matrix -| Feature | Method / Component | File(s) | -|:-------------------------------|:---------------------------------------|:------------------------------------------------------------------------------------------| -| Launch transfer flow | `showTransferOwnership(for:)` | `GroupDetailsViewController.swift` | -| Single-member selection | `selectionMode = .single` | `TransferOwnership.swift` | -| Filter out current owner | `reloadData()` override | `TransferOwnership.swift` | -| Execute API transfer | `CometChat.transferGroupOwnership()` | `TransferOwnership.swift` | -| Show/hide loading indicator | `addSpinnerView()`, `removeSpinnerView()` | `TransferOwnership.swift` | - - - - Explore the transfer ownership feature in context: - [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) +| Feature | Method / Component | File(s) | +|---------|-------------------|---------| +| Launch transfer flow | `showTransferOwnership(for:)` | `GroupDetailsViewController.swift` | +| Single-member selection | `selectionMode = .single` | `TransferOwnership.swift` | +| Filter out current owner | `reloadData()` override | `TransferOwnership.swift` | +| Execute API transfer | `CometChat.transferGroupOwnership()` | `TransferOwnership.swift` | +| Show/hide loading indicator | `addSpinnerView()`, `removeSpinnerView()` | `TransferOwnership.swift` | + +## Related Guides + + + + Display and manage groups + + + View and manage group membership - - Review the implementation: - [TransferOwnership.swift](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/Transfer%20ownership%20/TransferOwnership.swift) + + Complete group management guide - \ No newline at end of file + diff --git a/ui-kit/ios/guide-message-privately.mdx b/ui-kit/ios/guide-message-privately.mdx index 8d065a0d3..0a06146e2 100644 --- a/ui-kit/ios/guide-message-privately.mdx +++ b/ui-kit/ios/guide-message-privately.mdx @@ -1,120 +1,210 @@ --- title: "Message Privately" sidebarTitle: "Message Privately" +description: "Start private one-on-one chats from group conversations" --- -Enable users to start a private one-on-one chat with a group member directly from a group chat screen using CometChat’s UIKit for iOS. +Enable users to start a private one-on-one chat with a group member directly from a group chat screen using CometChat's UIKit for iOS. ## Overview -The **Message Privately** feature allows users to long-press a message in a group chat and select **Message Privately** to transition into a private conversation with the original sender. This streamlines side discussions and follow-ups without manual user searches. +The Message Privately feature allows users to long-press a message in a group chat and select **Message Privately** to transition into a private conversation with the original sender. This streamlines side discussions and follow-ups without requiring manual user searches. ## Prerequisites -- UIKit-based iOS project. -- CometChat UIKit for iOS v5 installed via CocoaPods or Swift Package Manager. -- Valid CometChat **App ID**, **Region**, and **Auth Key**. -- Functional group chat via `CometChatMessageList`. -- A one-on-one chat screen (`CometChatMessages` or custom) and navigation flow configured. +Before implementing this feature, ensure you have: + +1. Completed [Getting Started](/ui-kit/ios/getting-started) setup +2. CometChat UIKit v5+ installed +3. User logged in with `CometChatUIKit.login()` ## Components -| Component | Role | -|:-----------------------------------|:-------------------------------------------------------------------------------------------------| -| `CometChatMessageList` | Displays group messages; handles long-press to show options. | -| `CometChatMessageOption` | Defines the **Message Privately** option in the context menu. | -| `MessageDataSource` | Supplies the `messagePrivatelyOption` in the options array. | -| `CometChatMessageListViewModel` | Manages UI state, including `hideMessagePrivatelyOption`. | -| `CometChatMessages` | Entry point for rendering or pushing the private chat interface. | -| `CometChatUIKit.getUser(uid:)` | Retrieves the `User` object for the selected message sender. | -| `CometChatUIKit.getConversationWith(user:)` | Creates or fetches the 1-on-1 conversation instance. | -| `UIViewController` (Navigation) | Pushes or presents the private chat screen (`CometChatMessages`). | +| Component | Description | +|-----------|-------------| +| `CometChatMessageList` | Displays group messages and handles long-press to show options | +| `CometChatMessageOption` | Defines the **Message Privately** option in the context menu | +| `MessageDataSource` | Supplies the `messagePrivatelyOption` in the options array | +| `CometChatMessageListViewModel` | Manages UI state, including `hideMessagePrivatelyOption` | +| `CometChatMessages` | Entry point for rendering or pushing the private chat interface | +| `CometChat.getUser(UID:onSuccess:onError:)` | Retrieves the `User` object for the selected message sender | +| `CometChatUIEvents.openChat(user:group:)` | Opens the chat interface for a user or group | +| `UIViewController` (Navigation) | Pushes or presents the private chat screen (`CometChatMessages`) | ## Integration Steps -### 1. Control Option Visibility via ViewModel +### Step 1: Control Option Visibility via ViewModel + +Dynamically show or hide **Message Privately** based on app context: -Dynamically show or hide **Message Privately** based on app context. +```swift lines +import CometChatUIKitSwift -```swift +// Control visibility of the Message Privately option public var hideMessagePrivatelyOption: Bool = false { didSet { + // Sync with view model viewModel.hideMessagePrivatelyOption = hideMessagePrivatelyOption } } ``` -**File reference:** -[`CometChatMessageList.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) +This ensures the option only appears when appropriate (e.g., based on user permissions). + +**File reference:** [`CometChatMessageList.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) + +### Step 2: Handle Private Chat Navigation -Ensures the option only appears when appropriate (e.g., user permissions). +Retrieve the sender and initiate a private 1-on-1 chat: -### 2. Handle Private Chat Navigation +```swift lines +import UIKit +import CometChatSDK +import CometChatUIKitSwift -Retrieve the sender and initiate a private 1-on-1 chat. +func startPrivateChat(with selectedMessage: BaseMessage) { + // Get the sender from the selected message + if let user = selectedMessage.sender { + // Open the private chat using CometChatUIEvents + DispatchQueue.main.async { + CometChatUIEvents.openChat(user: user, group: nil) + } + } +} -```swift -if let uid = selectedMessage.sender?.uid { - CometChatUIKit.getUser(uid: uid) { user in - CometChatUIKit.getConversationWith(user: user) { conversation in - let messagesVC = CometChatMessages(conversation: conversation) - navigationController?.pushViewController(messagesVC, animated: true) +// Alternative: Manual navigation with user fetch +func startPrivateChatManual(with selectedMessage: BaseMessage) { + guard let uid = selectedMessage.sender?.uid else { return } + + // Fetch the user object + CometChat.getUser(UID: uid) { [weak self] user in + guard let user = user else { return } + + DispatchQueue.main.async { + // Navigate to the private chat screen + let messagesVC = CometChatMessages() + messagesVC.set(user: user) + self?.navigationController?.pushViewController(messagesVC, animated: true) } + } onError: { error in + print("Error fetching user: \(error?.errorDescription ?? "")") } } ``` -**File reference:** -[`CometChatMessageList.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) +This automates the transition from group context to private conversation. -Automates transition from group context to private conversation. +**File reference:** [`CometChatMessageList.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) ## Implementation Flow -1. Long-press a group message in `CometChatMessageList`. -2. Options menu appears with **Message Privately**. -3. User taps **Message Privately**. -4. App fetches `User` via `CometChatUIKit.getUser(uid:)`. -5. Retrieves or creates conversation via `CometChatUIKit.getConversationWith(user:)`. -6. Pushes `CometChatMessages` onto the navigation stack. +| Step | Action | +|------|--------| +| 1 | Long-press a group message in `CometChatMessageList` | +| 2 | Options menu appears with **Message Privately** | +| 3 | User taps **Message Privately** | +| 4 | App gets `User` from `message.sender` | +| 5 | Opens chat via `CometChatUIEvents.openChat(user:group:)` | +| 6 | Pushes `CometChatMessages` onto the navigation stack | ## Customization Options -- **Styling:** Override `CometChatMessageOption` UI (icons, fonts, colors). -- **Availability:** Control via `viewModel.hideMessagePrivatelyOption`. -- **Extend Options:** Add additional actions in `MessageDataSource.getMessageOptions(for:)`. +### Styling + +Override `CometChatMessageOption` UI elements: + +```swift lines +// Customize the message option appearance +let privateOption = CometChatMessageOption( + id: "message-privately", + title: "Message Privately", + icon: UIImage(systemName: "person.fill"), + backgroundColor: .systemBlue +) +``` + +### Availability + +Control visibility via the view model: + +```swift lines +// Hide the option for specific scenarios +viewModel.hideMessagePrivatelyOption = true +``` + +### Extend Options + +Add additional actions in `MessageDataSource.getMessageOptions(for:)`: + +```swift lines +func getMessageOptions(for message: BaseMessage) -> [CometChatMessageOption] { + var options = [CometChatMessageOption]() + + // Add message privately option + if !hideMessagePrivatelyOption { + options.append(messagePrivatelyOption) + } + + // Add custom options + options.append(customOption) + + return options +} +``` + +## Edge Cases -## Filtering & Edge Cases +| Scenario | Handling | +|----------|----------| +| Blocked users | Hide option if the sender is in block list | +| Existing conversations | Reuse existing thread via `getConversationWith` | +| Unavailable users | Skip option or show disabled state if user data is missing | -- **Blocked Users:** Hide option if the sender is in block list. -- **Existing Conversations:** Reuse existing thread via `getConversationWith`. -- **Unavailable Users:** Skip option or show disabled state if user data missing. +## Error Handling -## Error Handling & Blocked-User Handling +| Error Type | Solution | +|------------|----------| +| Block state | Catch errors from `CometChat.getUser` and alert user | +| Network failures | Present retry or toast on navigation errors | +| Invalid data | Disable option if `sender.uid` is nil | -- **Block State:** Catch errors from `getUser`/`getConversationWith` and alert user. -- **Network Failures:** Present retry or toast on navigation errors. -- **Invalid Data:** Disable option if `sender.uid` is nil. +## Additional Notes -## Optional Context-Specific Notes +- This feature is only available in **group chat** screens (`CometChatMessageList`) +- The option is hidden automatically in direct/private chat views -- Only available in **group chat** screens (`CometChatMessageList`). -- Hidden automatically in direct/private chat views. +## Feature Matrix -## Summary / Feature Matrix +| Feature | Component / Method | File(s) | +|---------|-------------------|---------| +| Show options menu | `getMessageOptions(for:)` | [`MessageDataSource.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Framework/MessagesDataSource.swift) | +| Toggle Message Privately | `viewModel.hideMessagePrivatelyOption` | [`CometChatMessageList.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift), [`MessageListViewModel.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) | -| Feature | Component / Method | File(s) | -|:----------------------------|:------------------------------------------|:--------------------------------------------------------------------------------------------| -| Show options menu | `getMessageOptions(for:)` | [`MessageDataSource.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Framework/MessagesDataSource.swift) | -| Toggle **Message Privately**| `viewModel.hideMessagePrivatelyOption` | [`CometChatMessageList.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift),
[`MessageListViewModel.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) | - - - - Explore this feature in the CometChat SampleApp: - [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) +## Related Components + +- [Message List](/ui-kit/ios/message-list) - Display messages in conversations +- [Users](/ui-kit/ios/users) - Display user list +- [Conversations](/ui-kit/ios/conversations) - Display conversation list + + + + Explore this feature in the CometChat SampleApp + + + Browse the message list component + + + +## Related Guides + + + + Display and manage users + + + View and manage conversations - - Browse the message list component: - [GitHub → CometChatMessageList.swift](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Message%20List/CometChatMessageList.swift) + + View group membership - \ No newline at end of file + diff --git a/ui-kit/ios/guide-new-chat.mdx b/ui-kit/ios/guide-new-chat.mdx index 83716e6d4..78f4abf90 100644 --- a/ui-kit/ios/guide-new-chat.mdx +++ b/ui-kit/ios/guide-new-chat.mdx @@ -1,202 +1,322 @@ --- title: "Create Conversation" sidebarTitle: "Create Conversation" +description: "Enable users to start new 1:1 or group chats" --- -Enable users to start new 1:1 or group chats in your iOS app using CometChat’s UIKit for iOS by integrating the **CreateConversationVC** screen. +Enable users to start new 1:1 or group chats in your iOS app using CometChat's UIKit for iOS by integrating the `CreateConversationVC` screen. ## Overview -The `CreateConversation` enables users to: +The `CreateConversation` component enables users to: -- Browse CometChat users and groups via native list components. -- Search within users and groups. -- Toggle between “Users” and “Groups” tabs using a segmented control. -- Swipe between lists with a `UIPageViewController`. -- Navigate to `MessagesVC` upon selecting a user or group. +- Browse CometChat users and groups via native list components +- Search within users and groups +- Toggle between "Users" and "Groups" tabs using a segmented control +- Swipe between lists with a `UIPageViewController` +- Navigate to `MessagesVC` upon selecting a user or group ## Prerequisites -- A UIKit-based iOS project. -- CometChat UIKit for iOS v5 installed via CocoaPods or Swift Package Manager. -- User authenticated with `CometChat.login()` before presenting this screen. -- A `UINavigationController` embedded in your flow. -- `MessagesVC` implemented to handle chat screens. +Before implementing this feature, ensure you have: + +- Completed [Getting Started](/ui-kit/ios/getting-started) setup +- CometChat UIKit v5+ installed via CocoaPods or Swift Package Manager +- User authenticated with `CometChatUIKit.login()` before presenting this screen +- A `UINavigationController` embedded in your flow +- `MessagesVC` implemented to handle chat screens ## Components -| Component | Role | -|:------------------------|:------------------------------------------------------------| -| `UISegmentedControl` | Switches between “Users” and “Groups” tabs. | -| `UIPageViewController` | Enables swipe navigation between list views. | -| `CometChatUsers` | Displays the list of CometChat users. | -| `CometChatGroups` | Displays the list of CometChat groups. | -| `MessagesVC` | Chat interface, launched upon item selection. | -| `searchController` | Provides search for both users and groups. | -| `CometChatTheme` | Applies theming (colors, fonts) for UI consistency. | -| `CometChatTypography` | Defines text styles for segment labels. | +| Component | Description | +|-----------|-------------| +| `UISegmentedControl` | Switches between "Users" and "Groups" tabs | +| `UIPageViewController` | Enables swipe navigation between list views | +| `CometChatUsers` | Displays the list of CometChat users | +| `CometChatGroups` | Displays the list of CometChat groups | +| `MessagesVC` | Chat interface, launched upon item selection | +| `searchController` | Provides search for both users and groups | +| `CometChatTheme` | Applies theming (colors, fonts) for UI consistency | +| `CometChatTypography` | Defines text styles for segment labels | ## Integration Steps -### 1. Presenting the Create Conversation Screen +### Step 1: Present the Create Conversation Screen -Push `CreateConversations` to allow starting a chat. +Push `CreateConversations` to allow starting a chat: -```swift +```swift lines import UIKit import CometChatSDK -func showCreateConversation() { - let createVC = CreateConversationVC() - navigationController?.pushViewController(createVC, animated: true) +class HomeViewController: UIViewController { + + func showCreateConversation() { + // Initialize the create conversation view controller + let createVC = CreateConversationVC() + + // Push onto navigation stack + navigationController?.pushViewController(createVC, animated: true) + } } ``` -**File reference:** -[`HomeScreenViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/HomeScreenViewController.swift) +This provides the entry point to the create-conversation flow. -Provides entry point to the create-conversation flow. +**File reference:** [`HomeScreenViewController.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/HomeScreenViewController.swift) -### 2. Setting Up the User Interface +### Step 2: Set Up the User Interface -Build the segmented control and page view controller. +Build the segmented control and page view controller: -```swift -override public func viewDidLoad() { - super.viewDidLoad() - buildUI() // sets up segmentedControl, pageViewController, and searchController - setupPageViewController() - segmentedControl.addTarget(self, action: #selector(segmentChanged(_:)), for: .valueChanged) - navigationItem.searchController = usersViewController.searchController +```swift lines +import UIKit +import CometChatUIKitSwift + +class CreateConversationVC: UIViewController { + + private var segmentedControl: UISegmentedControl! + private var pageViewController: UIPageViewController! + private var usersViewController: CometChatUsers! + private var groupsViewController: CometChatGroups! + + override public func viewDidLoad() { + super.viewDidLoad() + + // Set up segmented control, page view controller, and search + buildUI() + setupPageViewController() + + // Add target for segment changes + segmentedControl.addTarget( + self, + action: #selector(segmentChanged(_:)), + for: .valueChanged + ) + + // Set initial search controller + navigationItem.searchController = usersViewController.searchController + } + + private func buildUI() { + // Configure segmented control and page view + } + + private func setupPageViewController() { + // Initialize page view controller with users and groups + } } ``` -**File reference:** -[`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) +This initializes the UI elements and search integration. -Initializes the UI elements and search integration. +**File reference:** [`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) -### 3. Configuring Segmented Control Navigation +### Step 3: Configure Segmented Control Navigation -Toggle between user and group lists when the segment changes. +Toggle between user and group lists when the segment changes: -```swift +```swift lines @objc public func segmentChanged(_ sender: UISegmentedControl) { let index = sender.selectedSegmentIndex + + // Determine navigation direction let direction: UIPageViewController.NavigationDirection = index == 0 ? .reverse : .forward + + // Update search controller based on selected tab navigationItem.searchController = (index == 0) ? usersViewController.searchController : groupsViewController.searchController - pageViewController.setViewControllers([pages[index]], direction: direction, animated: true) + + // Navigate to the selected page + pageViewController.setViewControllers( + [pages[index]], + direction: direction, + animated: true + ) } ``` -**File reference:** -[`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) +This keeps the proper search bar and view in sync with the selected tab. -Keeps the proper search bar and view in sync with the selected tab. +**File reference:** [`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) -### 4. Handling Item Selection +### Step 4: Handle Item Selection -Navigate to `MessagesVC` when a user or group is tapped. +Navigate to `MessagesVC` when a user or group is tapped: -```swift -// User tap +```swift lines +// Users list with tap handler public lazy var usersViewController: CometChatUsers = { let vc = CometChatUsers() + + // Handle user selection vc.set(onItemClick: { [weak self] user, _ in let chatVC = MessagesVC() chatVC.user = user self?.navigationController?.pushViewController(chatVC, animated: true) }) + + // Keep navigation bar visible during search vc.searchController.hidesNavigationBarDuringPresentation = false + return vc }() -// Group tap +// Groups list with tap handler public lazy var groupsViewController: CometChatGroups = { let vc = CometChatGroups() + + // Handle group selection vc.set(onItemClick: { [weak self] group, _ in let chatVC = MessagesVC() chatVC.group = group self?.navigationController?.pushViewController(chatVC, animated: true) }) + + // Keep navigation bar visible during search vc.searchController.hidesNavigationBarDuringPresentation = false + return vc }() ``` -**File reference:** -[`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) +This routes the user to the appropriate chat screen. -Routes the user to the appropriate chat screen. +**File reference:** [`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) -### 5. Managing Page View Transitions +### Step 5: Manage Page View Transitions -Implement data source and delegate for smooth swiping. +Implement data source and delegate for smooth swiping: -```swift +```swift lines +// MARK: - UIPageViewControllerDataSource extension CreateConversationVC: UIPageViewControllerDataSource { - public func pageViewController(_ pvc: UIPageViewController, viewControllerBefore vc: UIViewController) -> UIViewController? { + + public func pageViewController( + _ pvc: UIPageViewController, + viewControllerBefore vc: UIViewController + ) -> UIViewController? { guard let idx = pages.firstIndex(of: vc), idx > 0 else { return nil } return pages[idx - 1] } - public func pageViewController(_ pvc: UIPageViewController, viewControllerAfter vc: UIViewController) -> UIViewController? { + + public func pageViewController( + _ pvc: UIPageViewController, + viewControllerAfter vc: UIViewController + ) -> UIViewController? { guard let idx = pages.firstIndex(of: vc), idx < pages.count - 1 else { return nil } return pages[idx + 1] } } +// MARK: - UIPageViewControllerDelegate extension CreateConversationVC: UIPageViewControllerDelegate { - public func pageViewController(_ pvc: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - if completed, let current = pvc.viewControllers?.first, let idx = pages.firstIndex(of: current) { + + public func pageViewController( + _ pvc: UIPageViewController, + didFinishAnimating finished: Bool, + previousViewControllers: [UIViewController], + transitionCompleted completed: Bool + ) { + // Sync segmented control with current page + if completed, + let current = pvc.viewControllers?.first, + let idx = pages.firstIndex(of: current) { segmentedControl.selectedSegmentIndex = idx } } } ``` -**File reference:** -[`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) +This synchronizes the segmented control with page swipes. -Synchronizes the segmented control with page swipes. +**File reference:** [`CreateConversations.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversations.swift) ## Customization Options -- **Segment Styling:** Use `CometChatTheme` to customize tint and font. -- **Labels:** Localize or rebrand “USERS” / “GROUPS” labels. -- **Search:** Adjust `searchController.placeholder` and styling. +### Segment Styling + +Use `CometChatTheme` to customize tint and font: + +```swift lines +segmentedControl.selectedSegmentTintColor = CometChatTheme.palette.primary +segmentedControl.setTitleTextAttributes([ + .font: CometChatTypography.body, + .foregroundColor: UIColor.white +], for: .selected) +``` + +### Labels + +Localize or rebrand "USERS" / "GROUPS" labels: + +```swift lines +segmentedControl.setTitle("Contacts", forSegmentAt: 0) +segmentedControl.setTitle("Teams", forSegmentAt: 1) +``` -## Filtering & Edge Cases +### Search -- **Live Search:** Built-in in `CometChatUsers` and `CometChatGroups`. -- **Empty States:** Components display default “no results” views. -- **Segment Disabled:** Hide tabs if only one list is relevant. +Adjust `searchController.placeholder` and styling: + +```swift lines +usersViewController.searchController.searchBar.placeholder = "Search contacts..." +groupsViewController.searchController.searchBar.placeholder = "Search teams..." +``` + +## Edge Cases + +| Scenario | Handling | +|----------|----------| +| Live search | Built-in in `CometChatUsers` and `CometChatGroups` | +| Empty states | Components display default "no results" views | +| Segment disabled | Hide tabs if only one list is relevant | ## Error Handling -- **Load Errors:** Use `setErrorView()` on list components. -- **Navigation Failures:** Present an alert if push fails. -- **Blocked Users:** Intercept in `onItemClick` to prevent navigation. +| Error Type | Solution | +|------------|----------| +| Load errors | Use `setErrorView()` on list components | +| Navigation failures | Present an alert if push fails | +| Blocked users | Intercept in `onItemClick` to prevent navigation | ## Feature Matrix -| Feature | Implementation | -|:------------------------------|:-----------------------------------------------| -| Show create screen | `showCreateConversation()` | -| Tabbed lists | `UISegmentedControl` + `UIPageViewController` | -| Display users | `CometChatUsers()` | -| Display groups | `CometChatGroups()` | -| Search functionality | `searchController` | -| Navigate to chat | `MessagesVC(user:)` / `MessagesVC(group:)` | - - - - Explore the complete create-conversation flow: - [GitHub → SampleApp](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) +| Feature | Implementation | +|---------|----------------| +| Show create screen | `showCreateConversation()` | +| Tabbed lists | `UISegmentedControl` + `UIPageViewController` | +| Display users | `CometChatUsers()` | +| Display groups | `CometChatGroups()` | +| Search functionality | `searchController` | +| Navigate to chat | `MessagesVC(user:)` / `MessagesVC(group:)` | + +## Related Components + +- [Users](/ui-kit/ios/users) - Display user list +- [Groups](/ui-kit/ios/groups) - Display group list +- [Conversations](/ui-kit/ios/conversations) - Display conversation list + +## Related Guides + + + + Display and select users + + + Display and select groups + + + View recent conversations + + + + + + Explore the complete create-conversation flow - - Browse the source for `CreateConversationVC`: - [GitHub → CreateConversationVC.swift](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/CreateConversationVC.swift) + + Browse the source for CreateConversationVC - \ No newline at end of file + diff --git a/ui-kit/ios/guide-overview.mdx b/ui-kit/ios/guide-overview.mdx index 291ee9746..3b8cc90aa 100644 --- a/ui-kit/ios/guide-overview.mdx +++ b/ui-kit/ios/guide-overview.mdx @@ -1,23 +1,59 @@ --- title: "Overview" sidebarTitle: "Overview" +description: "Index of feature guides for iOS UI Kit" --- -> This page indexes focused, task‑oriented feature guides for the iOS UI Kit. Each guide shows how to implement a specific capability end‑to‑end using UIKit components. + +This page indexes focused, task-oriented feature guides for the iOS UI Kit. Each guide shows how to implement a specific capability end-to-end using UIKit components. + +## Prerequisites + +Before implementing any guide, ensure you have: + +1. Completed [Getting Started](/ui-kit/ios/getting-started) setup +2. CometChat UIKit v5+ installed +3. User logged in with `CometChatUIKit.login()` ## When to Use These Guides -Use these after completing [Getting Started](/ui-kit/ios/getting-started) and wiring your base conversations / messages flows. Apply them to layer feature depth without rebuilding standard patterns. +Use these guides after completing [Getting Started](/ui-kit/ios/getting-started) and wiring your base conversations/messages flows. Apply them to layer feature depth without rebuilding standard patterns. ## Guide Directory | Guide | Description | -|:------|:------------| +|-------|-------------| +| [AI Agent Integration](/ui-kit/ios/guide-ai-agent) | Add AI-powered chat assistants with chat history, contextual responses, and seamless handoffs. | | [Block / Unblock User](/ui-kit/ios/guide-block-unblock-user) | Add profile-level moderation so users can block or unblock others; hides interaction affordances and protects chat flow. | -| [Call Log Details](/ui-kit/ios/guide-call-log-details) | Provide a detailed post‑call screen with metadata, participants, history, and recordings for auditing & support. | +| [Call Log Details](/ui-kit/ios/guide-call-log-details) | Provide a detailed post-call screen with metadata, participants, history, and recordings for auditing and support. | | [Group Management](/ui-kit/ios/guide-group-chat) | Implement create/join, membership listing, role changes, bans, and structured group moderation actions. | | [Group Ownership Transfer](/ui-kit/ios/guide-group-ownership) | Allow admins to hand over group ownership securely to another member. | -| [Message Privately](/ui-kit/ios/guide-message-privately) | Launch a direct 1:1 conversation from a user profile or list; optionally seed with an initial message. | -| [New Chat](/ui-kit/ios/guide-new-chat) | Offer a unified entry to discover users & groups and jump into new conversations quickly. | +| [Message Privately](/ui-kit/ios/guide-message-privately) | Launch a direct 1:1 conversation from a group chat; streamlines side discussions without manual user searches. | +| [New Chat](/ui-kit/ios/guide-new-chat) | Offer a unified entry to discover users and groups and jump into new conversations quickly. | | [Threaded Messages](/ui-kit/ios/guide-threaded-messages) | Add threaded reply views so users can branch focused discussions off individual messages. | +## Related Resources + +- [Getting Started](/ui-kit/ios/getting-started) - Initial setup and configuration +- [Components Overview](/ui-kit/ios/components-overview) - All available UI components +- [Core Features](/ui-kit/ios/core-features) - Messaging, reactions, threads, and more + Need another guide? Request one via the [Developer Community](http://community.cometchat.com/) or Support. + +--- + +## Related Guides + + + + Build AI-powered chat experiences + + + Create and manage group conversations + + + Start new conversations with users or groups + + + Implement threaded message replies + + diff --git a/ui-kit/ios/guide-threaded-messages.mdx b/ui-kit/ios/guide-threaded-messages.mdx index a1cee6d7e..c8412948d 100644 --- a/ui-kit/ios/guide-threaded-messages.mdx +++ b/ui-kit/ios/guide-threaded-messages.mdx @@ -1,153 +1,240 @@ --- title: "Threaded Messages" sidebarTitle: "Threaded Messages" +description: "Add threaded reply views to your iOS chat app" --- -Enhance your iOS chat app with threaded messaging by integrating CometChat’s **UIKit for iOS**, allowing users to reply to specific messages within a focused thread view. +Enhance your iOS chat app with threaded messaging by integrating CometChat's UIKit for iOS, allowing users to reply to specific messages within a focused thread view. ## Overview -Threaded messages allow users to reply to specific messages within a conversation, creating a sub-conversation for improved clarity and context. With CometChat’s UIKit for iOS, you can: +Threaded messages allow users to reply to specific messages within a conversation, creating a sub-conversation for improved clarity and context. With CometChat's UIKit for iOS, you can: -- Display a dedicated thread view. -- View and send replies to a selected message. -- Maintain context between the main conversation and the thread. +- Display a dedicated thread view +- View and send replies to a selected message +- Maintain context between the main conversation and the thread ## Prerequisites -- A working UIKit-based iOS project. -- CometChat UIKit for iOS v4+ installed via Swift Package Manager or CocoaPods. -- Valid CometChat **App ID**, **Region**, and **Auth Key**. -- A navigation controller configured in your project. +Before implementing this feature, ensure you have: + +1. Completed [Getting Started](/ui-kit/ios/getting-started) setup +2. CometChat UIKit v5+ installed +3. User logged in with `CometChatUIKit.login()` ## Components -| Component | Role | -|:----------------------------------|:-----------------------------------------------------------| -| `CometChatMessageList` | Displays messages and provides `onThreadRepliesClick` handler. | -| `CometChatThreadedMessageHeader` | Shows the parent message context at the top of the thread. | -| `CometChatMessageComposer` | Composes messages with an optional `parentMessageId`. | -| `ThreadedMessagesVC` | View controller that hosts the threaded conversation. | +| Component | Description | +|-----------|-------------| +| `CometChatMessageList` | Displays messages and provides `onThreadRepliesClick` handler | +| `CometChatThreadedMessageHeader` | Shows the parent message context at the top of the thread | +| `CometChatMessageComposer` | Composes messages with an optional `parentMessageId` | +| `ThreadedMessagesVC` | View controller that hosts the threaded conversation | ## Integration Steps -### Show the "Reply in Thread" Option - -Navigate to the thread when a message’s thread icon is tapped. - -```swift -messageListView.set(onThreadRepliesClick: { [weak self] message, _ in - guard let self = self else { return } - let threadVC = ThreadedMessagesVC() - threadVC.parentMessage = message - self.navigationController?.pushViewController(threadVC, animated: true) -}) +### Step 1: Show the "Reply in Thread" Option + +Navigate to the thread when a message's thread icon is tapped: + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class MessagesViewController: UIViewController { + + var messageListView: CometChatMessageList! + + func setupThreadReplies() { + // Handle thread replies click + messageListView.set(onThreadRepliesClick: { [weak self] message, _ in + guard let self = self else { return } + + // Create and configure thread view controller + let threadVC = ThreadedMessagesVC() + threadVC.parentMessage = message + + // Navigate to thread screen + self.navigationController?.pushViewController(threadVC, animated: true) + }) + } +} ``` -**File reference:** -[`ThreadedMessagesVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/ThreadedMessagesVC.swift) - -Captures user intent and opens a focused thread screen. - -### Navigate to the Thread Screen - -Show a dedicated UI for thread replies. - -In `ThreadedMessagesVC.swift`: - -```swift -view.addSubview(parentMessageView) -view.addSubview(messageListView) -view.addSubview(composerView) +This captures user intent and opens a focused thread screen. + +**File reference:** [`ThreadedMessagesVC.swift`](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/SampleApp/View%20Controllers/CometChat%20Components/ThreadedMessagesVC.swift) + +### Step 2: Navigate to the Thread Screen + +Show a dedicated UI for thread replies. In `ThreadedMessagesVC.swift`: + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ThreadedMessagesVC: UIViewController { + + var parentMessage: BaseMessage? + var user: User? + var group: Group? + + private var parentMessageContainerView: CometChatThreadedMessageHeader! + private var messageListView: CometChatMessageList! + private var composerView: CometChatMessageComposer! + + override func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + private func setupUI() { + // Add UI components to view hierarchy + view.addSubview(parentMessageView) + view.addSubview(messageListView) + view.addSubview(composerView) + } +} ``` -Header: +Header configuration: -```swift +```swift lines +// Create the threaded message header let parentMessageContainerView = CometChatThreadedMessageHeader() ``` -Message List: +Message list configuration: -```swift +```swift lines +// Configure message list with user and parent message messageListView.set(user: user, parentMessage: parentMessage) ``` -Provides a focused UI for thread interactions. +This provides a focused UI for thread interactions. -### Send a Threaded Message +### Step 3: Send a Threaded Message -Ensure new replies are attached to the correct parent message. +Ensure new replies are attached to the correct parent message: -```swift +```swift lines +// Set the parent message ID for threaded replies composerView.set(parentMessageId: parentMessage?.id ?? 0) ``` Set the conversation context: -```swift +```swift lines +// Configure composer for user conversation composerView.set(user: user) + +// Or configure for group conversation composerView.set(group: group) ``` -### Fetch & Display Thread Replies - -Only messages that are part of the thread are displayed. +### Step 4: Fetch and Display Thread Replies -Handled internally by: +Only messages that are part of the thread are displayed. This is handled internally by: -```swift +```swift lines +// Configure message list to fetch thread replies messageListView.set(user: user, parentMessage: parentMessage) ``` -Ensures `CometChatMessageList` fetches replies using the `parentMessageId`. +This ensures `CometChatMessageList` fetches replies using the `parentMessageId`. ## Customization Options -- **Header Styling:** Customize `CometChatThreadedMessageHeader` (fonts, colors, etc.). -- **Composer:** Modify placeholder text, input styles, and icons. -- **Navigation:** Add a custom `navigationItem.leftBarButtonItem` for back navigation. +### Header Styling -## Filtering / Edge Cases +Customize `CometChatThreadedMessageHeader` appearance: -- **Parent Message Deleted:** Display a fallback UI or disable the composer. -- **No Replies:** Show an empty state (e.g., “No replies yet”). -- **Offline Mode:** Disable the composer and queue thread operations. - -## Error Handling & Edge Cases - -- **Fetch Failures:** Show an error UI or retry mechanism when loading thread messages. -- **Send Failures:** Handle send errors via delegate callbacks or show an alert with retry. -- **Loading States:** Display a `UIActivityIndicatorView` during fetch/send operations. -- **Blocked Users:** Remove the composer and display a blocked status label. - -## Summary / Feature Matrix - -| Feature | Implementation | -|:----------------------------|:------------------------------------------------------| -| Show thread option | `CometChatMessageList.onThreadRepliesClick` | -| Thread view screen | `ThreadedMessagesVC.swift` | -| Display threaded messages | `CometChatMessageList.set(parentMessage:)` | -| Send threaded message | `CometChatMessageComposer.set(parentMessageId:)` | -| Thread header | `CometChatThreadedMessageHeader` | -| Handle blocked user | Remove composer & show a blocked user label | - - - - - -Explore a complete sample application demonstrating threaded messaging. +```swift lines +// Customize fonts, colors, and layout +let headerStyle = ThreadedMessageHeaderStyle() +headerStyle.titleFont = UIFont.systemFont(ofSize: 16, weight: .semibold) +headerStyle.titleColor = .label +parentMessageContainerView.set(style: headerStyle) +``` -[View on GitHub](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/SampleApp) +### Composer - +Modify placeholder text, input styles, and icons: - +```swift lines +// Customize composer appearance +composerView.set(placeholderText: "Reply in thread...") +``` -Browse the CometChat UIKit for iOS source code. +### Navigation -[View on GitHub](https://github.com/cometchat/cometchat-uikit-ios/tree/v5) +Add a custom back button for navigation: - +```swift lines +// Add custom back button +navigationItem.leftBarButtonItem = UIBarButtonItem( + image: UIImage(systemName: "chevron.left"), + style: .plain, + target: self, + action: #selector(goBack) +) +``` - \ No newline at end of file +## Edge Cases + +| Scenario | Handling | +|----------|----------| +| Parent message deleted | Display a fallback UI or disable the composer | +| No replies | Show an empty state (e.g., "No replies yet") | +| Offline mode | Disable the composer and queue thread operations | + +## Error Handling + +| Error Type | Solution | +|------------|----------| +| Fetch failures | Show an error UI or retry mechanism when loading thread messages | +| Send failures | Handle send errors via delegate callbacks or show an alert with retry | +| Loading states | Display a `UIActivityIndicatorView` during fetch/send operations | +| Blocked users | Remove the composer and display a blocked status label | + +## Feature Matrix + +| Feature | Implementation | +|---------|----------------| +| Show thread option | `CometChatMessageList.onThreadRepliesClick` | +| Thread view screen | `ThreadedMessagesVC.swift` | +| Display threaded messages | `CometChatMessageList.set(parentMessage:)` | +| Send threaded message | `CometChatMessageComposer.set(parentMessageId:)` | +| Thread header | `CometChatThreadedMessageHeader` | +| Handle blocked user | Remove composer and show a blocked user label | + +## Related Components + +- [Message List](/ui-kit/ios/message-list) - Display messages in conversations +- [Message Composer](/ui-kit/ios/message-composer) - Compose and send messages +- [Threaded Messages Header](/ui-kit/ios/threaded-messages-header) - Thread header component + + + + Explore a complete sample application demonstrating threaded messaging + + + Browse the CometChat UIKit for iOS source code + + + +## Related Guides + + + + Customize the thread header component + + + Display and customize chat messages + + + Overview of messaging features + + diff --git a/ui-kit/ios/incoming-call.mdx b/ui-kit/ios/incoming-call.mdx index d3c3876e2..62e8b78ae 100644 --- a/ui-kit/ios/incoming-call.mdx +++ b/ui-kit/ios/incoming-call.mdx @@ -1,183 +1,222 @@ --- title: "Incoming Call" +description: "Display and handle incoming voice and video calls" --- -## Overview - -The `Incoming call` is a [Component](/ui-kit/ios/components-overview#components) that serves as a visual representation when the user receives an incoming call, such as a voice call or video call, providing options to answer or decline the call. +The `CometChatIncomingCall` component serves as a visual representation when the user receives an incoming call, such as a voice call or video call, providing options to answer or decline the call. - + CometChatIncomingCall showing incoming call interface with caller avatar, name, and accept/reject buttons -*** + +```json +{ + "component": "CometChatIncomingCall", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays incoming call interface with accept and reject options", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onAcceptClick", + "type": "(Call, UIViewController) -> Void" + }, + "props": { + "data": { + "call": { "type": "Call", "required": true } + }, + "callbacks": { + "onAcceptClick": "(Call, UIViewController) -> Void", + "onCancelClick": "(Call, UIViewController) -> Void", + "onError": "(CometChatException) -> Void" + }, + "sound": { + "disableSoundForCalls": { "type": "Bool", "default": false }, + "customSoundForCalls": { "type": "URL?", "default": "nil" } + }, + "viewSlots": { + "listItemView": "(Call) -> UIView", + "leadingView": "(Call) -> UIView", + "titleView": "(Call) -> UIView" + } + }, + "events": [ + { "name": "onIncomingCallAccepted", "payload": "Call", "description": "Fires when incoming call is accepted" }, + { "name": "onIncomingCallRejected", "payload": "Call", "description": "Fires when incoming call is rejected" }, + { "name": "onCallEnded", "payload": "Call", "description": "Fires when call ends" } + ], + "sdkListeners": [], + "compositionExample": { + "description": "IncomingCall is presented when a call is received", + "components": ["CometChatIncomingCall", "CometChatOngoingCall"], + "flow": "Call received → IncomingCall shown → User accepts → OngoingCall starts" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatIncomingCall` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | + +--- ## Usage ### Integration -`CometChatIncomingCall` being a custom **view controller**, offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application. +`CometChatIncomingCall` is a custom view controller that offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application. -```swift +```swift lines +// Create and configure incoming call view controller let cometChatIncomingCall = CometChatIncomingCall().set(call: call) + +// Present full screen cometChatIncomingCall.modalPresentationStyle = .fullScreen self.present(cometChatIncomingCall, animated: true) ``` - - - If you are already using a navigation controller, you can use the `pushViewController` function instead of presenting the view controller. - ### Actions [Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. -##### 1. SetOnAcceptClick +#### 1. SetOnAcceptClick The `setOnAcceptClick` action is typically triggered when the user clicks on the accept button, initiating a predefined action. However, by implementing the following code snippet, you can easily customize or override this default behavior to suit your specific requirements. -```swift +```swift lines let cometChatIncomingCall = CometChatIncomingCall() -.set(onAcceptClick: { call, controller in -//Perform Your Action - -}) + .set(onAcceptClick: { call, controller in + // Perform your custom action when call is accepted + }) ``` - - -##### 2. SetOnCancelClick +#### 2. SetOnCancelClick The `setOnCancelClick` action is typically triggered when the user clicks on the reject button, initiating a predefined action. However, by implementing the following code snippet, you can easily customize or override this default behavior to suit your specific requirements. -```swift +```swift lines let cometChatIncomingCall = CometChatIncomingCall() -.set(onCancelClick: { call, controller in - //Perform Your Action - -}) + .set(onCancelClick: { call, controller in + // Perform your custom action when call is rejected + }) ``` - - -##### 3. OnError +#### 3. OnError You can customize this behavior by using the provided code snippet to override the `On Error` and improve error handling. -```swift - +```swift lines let incomingCallConfiguration = IncomingCallConfiguration() -.set(onError:{ error in -//Perform Your Action - -}) + .set(onError: { error in + // Perform your custom error handling action + }) ``` - - -*** +--- ### Filters -**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK. +Filters allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized experience. Filters can be applied using RequestBuilders of Chat SDK. The IncomingCall component does not have any exposed filters. -*** +--- ### Events -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. +[Events](/ui-kit/ios/components-overview#events) are emitted by a Component. By using events you can extend existing functionality. Being global events, they can be applied in multiple locations and are capable of being added or removed. -Events emitted by the Incoming Call component is as follows. +Events emitted by the Incoming Call component are as follows: -| Event | Description | -| -------------------------- | -------------------------------------------------------------------------- | -| **onIncomingCallAccepted** | Triggers when the logged-in user accepts the incoming call. | -| **onIncomingCallRejected** | This event is triggered when the logged-in user rejects the incoming call. | -| **onCallEnded** | This event is triggered when the initiated call successfully ends. | +| Event | Description | +|-------|-------------| +| `onIncomingCallAccepted` | Triggers when the logged-in user accepts the incoming call | +| `onIncomingCallRejected` | Triggers when the logged-in user rejects the incoming call | +| `onCallEnded` | Triggers when the initiated call successfully ends | -```swift -// View controller from your project where you want to listen events. +```swift lines +// View controller from your project where you want to listen to events public class ViewController: UIViewController { - public override func viewDidLoad() { + public override func viewDidLoad() { super.viewDidLoad() - // Subscribing for the listener to listen events from user module + // Subscribe to call events CometChatCallEvents.addListener("UNIQUE_ID", self as CometChatCallEventListener) } - } - // Listener events from user module -extension ViewController: CometChatCallEventListener { + +// Listener events from call module +extension ViewController: CometChatCallEventListener { func onIncomingCallAccepted(call: Call) { - // Do Stuff + // Handle accepted call } - func onIncomingCallRejected(call: Call){ - // Do Stuff + + func onIncomingCallRejected(call: Call) { + // Handle rejected call } func onCallEnded(call: Call) { - // Do Stuff + // Handle ended call } } ``` -```swift Emitting Group Events -//emit this when logged in user accepts the incoming call +```swift lines +// Emitting Call Events + +// Emit when logged in user accepts the incoming call CometChatCallEvents.emitOnIncomingCallAccepted(call: Call) -//emit this when logged in user rejects the incoming call +// Emit when logged in user rejects the incoming call CometChatCallEvents.emitOnIncomingCallRejected(call: Call) -//emit this when logged in user cancels a call +// Emit when logged in user ends a call CometChatCallEvents.emitOnCallEnded(call: Call) ``` - - -*** +--- -```swift View Controller +```swift lines public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module - CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") + // Unsubscribe from call events + CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") } ``` - - -*** +--- ## Customization @@ -185,9 +224,9 @@ To fit your app's design requirements, you can customize the appearance of the c ### Style -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +Using Style you can customize the look and feel of the component in your app. These parameters typically control elements such as the color, size, shape, and fonts used within the component. -##### 1. IncomingCall Style +#### 1. IncomingCall Style You can customize the appearance of the `IncomingCall` Component by applying the `IncomingCallStyle` to it using the following code snippet. @@ -195,86 +234,87 @@ You can customize the appearance of the `IncomingCall` Component by applying the -```swift +```swift lines +// Create custom avatar style let customAvatarStyle = AvatarStyle() customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) - + +// Apply global incoming call styles CometChatIncomingCall.style.nameLabelFont = UIFont(name: "Times-New-Roman", size: 20) CometChatIncomingCall.style.callLabelFont = UIFont(name: "Times-New-Roman", size: 14) CometChatIncomingCall.style.acceptButtonCornerRadius = .init(cornerRadius: 8) CometChatIncomingCall.style.rejectButtonCornerRadius = .init(cornerRadius: 8) CometChatIncomingCall.avatarStyle = customAvatarStyle ``` - - **Instance level styling** -```swift +```swift lines +// Create custom avatar style var customAvatarStyle = AvatarStyle() customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) - + +// Create custom incoming call style var incomingCallStyle = IncomingCallStyle() incomingCallStyle.nameLabelFont = UIFont(name: "Times-New-Roman", size: 20) incomingCallStyle.callLabelFont = UIFont(name: "Times-New-Roman", size: 14) incomingCallStyle.acceptButtonCornerRadius = .init(cornerRadius: 8) incomingCallStyle.rejectButtonCornerRadius = .init(cornerRadius: 8) - + +// Apply styles to instance let incomingCall = CometChatIncomingCall() incomingCall.style = incomingCallStyle incomingCall.avatarStyle = customAvatarStyle ``` - - - + CometChatIncomingCall with custom styling showing custom fonts and rounded button corners -List of properties exposed by IncomingCallStyle - -| Property | Description | Code | -| ----------------------------- | --------------------------------------- | ------------------------------------------------- | -| `overlayBackgroundColor` | Background color for the overlay. | `overlayBackgroundColor: UIColor` | -| `acceptButtonBackgroundColor` | Background color for the accept button. | `acceptButtonBackgroundColor: UIColor` | -| `rejectButtonBackgroundColor` | Background color for the reject button. | `rejectButtonBackgroundColor: UIColor` | -| `acceptButtonTintColor` | Tint color for the accept button. | `acceptButtonTintColor: UIColor` | -| `rejectButtonTintColor` | Tint color for the reject button. | `rejectButtonTintColor: UIColor` | -| `acceptButtonImage` | Icon image for the accept button. | `acceptButtonImage: UIImage` | -| `rejectButtonImage` | Icon image for the reject button. | `rejectButtonImage: UIImage` | -| `acceptButtonCornerRadius` | Sets corner radius for accept button | `acceptButtonCornerRadius: CometChatCornerStyle?` | -| `rejectButtonCornerRadius` | Sets corner radius for reject button | `rejectButtonCornerRadius: CometChatCornerStyle?` | -| `acceptButtonBorderWidth` | Sets border width for accept button | `acceptButtonBorderWidth: CGFloat?` | -| `rejectButtonBorderWidth` | Sets border width for reject button | `rejectButtonBorderWidth: CGFloat?` | -| `acceptButtonBorderColor` | Sets border color for accept button | `acceptButtonBorderColor: UIColor?` | -| `rejectButtonBorderColor` | Sets border color for reject button | `rejectButtonBorderColor: UIColor?` | -| `backgroundColor` | Background color for the call view. | `backgroundColor: UIColor` | -| `cornerRadius` | Corner radius for the view. | `cornerRadius: nil` | -| `borderColor` | Border color for the view. | `borderColor: UIColor` | -| `borderWidth` | Border width for the view. | `borderWidth: CGFloat` | -| `callLabelColor` | Text color for the call label. | `callLabelColor: UIColor` | -| `callLabelFont` | Font for the call label. | `callLabelFont: UIFont` | -| `nameLabelColor` | Text color for the name label. | `nameLabelColor: UIColor` | -| `nameLabelFont` | Font for the name label. | `nameLabelFont: UIFont` | - -*** +List of properties exposed by IncomingCallStyle: + +| Property | Description | Code | +|----------|-------------|------| +| `overlayBackgroundColor` | Background color for the overlay | `overlayBackgroundColor: UIColor` | +| `acceptButtonBackgroundColor` | Background color for the accept button | `acceptButtonBackgroundColor: UIColor` | +| `rejectButtonBackgroundColor` | Background color for the reject button | `rejectButtonBackgroundColor: UIColor` | +| `acceptButtonTintColor` | Tint color for the accept button | `acceptButtonTintColor: UIColor` | +| `rejectButtonTintColor` | Tint color for the reject button | `rejectButtonTintColor: UIColor` | +| `acceptButtonImage` | Icon image for the accept button | `acceptButtonImage: UIImage` | +| `rejectButtonImage` | Icon image for the reject button | `rejectButtonImage: UIImage` | +| `acceptButtonCornerRadius` | Sets corner radius for accept button | `acceptButtonCornerRadius: CometChatCornerStyle?` | +| `rejectButtonCornerRadius` | Sets corner radius for reject button | `rejectButtonCornerRadius: CometChatCornerStyle?` | +| `acceptButtonBorderWidth` | Sets border width for accept button | `acceptButtonBorderWidth: CGFloat?` | +| `rejectButtonBorderWidth` | Sets border width for reject button | `rejectButtonBorderWidth: CGFloat?` | +| `acceptButtonBorderColor` | Sets border color for accept button | `acceptButtonBorderColor: UIColor?` | +| `rejectButtonBorderColor` | Sets border color for reject button | `rejectButtonBorderColor: UIColor?` | +| `backgroundColor` | Background color for the call view | `backgroundColor: UIColor` | +| `cornerRadius` | Corner radius for the view | `cornerRadius: nil` | +| `borderColor` | Border color for the view | `borderColor: UIColor` | +| `borderWidth` | Border width for the view | `borderWidth: CGFloat` | +| `callLabelColor` | Text color for the call label | `callLabelColor: UIColor` | +| `callLabelFont` | Font for the call label | `callLabelFont: UIFont` | +| `nameLabelColor` | Text color for the name label | `nameLabelColor: UIColor` | +| `nameLabelFont` | Font for the name label | `nameLabelFont: UIFont` | + +--- ### Functionality These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. -| Property | Description | Code | -| ---------------------- | --------------------------------------- | ------------------------------- | -| disableSoundForCalls | Disables sound for incoming calls. | `disableSoundForCalls = true` | -| setCustomSoundForCalls | Sets a custom sound for incoming calls. | `set(customSoundForCalls: URL)` | +| Property | Description | Code | +|----------|-------------|------| +| `disableSoundForCalls` | Disables sound for incoming calls | `disableSoundForCalls = true` | +| `setCustomSoundForCalls` | Sets a custom sound for incoming calls | `set(customSoundForCalls: URL)` | ### Advanced @@ -286,26 +326,24 @@ With this function, you can assign a custom view to the incoming call item view. -```swift +```swift lines cometChatIncomingCall.set(listItemView: { call in let customView = CustomListItemView() return customView }) ``` - - -Demonstration +Demonstration: - + CometChatIncomingCall with custom list item view showing compact call notification with avatar and action buttons -You can create a CustomListItemView as a custom `UIView`. +You can create a CustomListItemView as a custom `UIView`: -```swift swift +```swift lines import UIKit class CustomListItemView: UIView { @@ -405,36 +443,34 @@ class CustomListItemView: UIView { } ``` -*** +--- #### SetLeadingView -You can modify the leading view of a Incoming call component using the property below. +You can modify the leading view of an Incoming call component using the property below. -```swift +```swift lines cometChatIncomingCall.set(leadingView: { call in let view = CustomLeadingView() return view }) ``` - - -Demonstration +Demonstration: - + CometChatIncomingCall with custom leading view showing PRO USER badge with star icon -You can create a CustomLeadingView as a custom `UIView`. +You can create a CustomLeadingView as a custom `UIView`: -```swift +```swift lines import UIKit class CustomLeadingView: UIView { @@ -453,7 +489,7 @@ class CustomLeadingView: UIView { label.text = "PRO USER" label.font = UIFont.boldSystemFont(ofSize: 14) label.textColor = .white - text.textAlignment = .center + label.textAlignment = .center return label }() @@ -489,44 +525,40 @@ class CustomLeadingView: UIView { } } ``` - - -*** +--- #### SetTitleView -You can customize the title view of a incoming call component using the property below. +You can customize the title view of an incoming call component using the property below. -```swift +```swift lines cometChatIncomingCall.set(titleView: { call in let view = CustomTitleView() return view }) ``` - - -Demonstration +Demonstration: - + CometChatIncomingCall with custom title view showing Voice Call label with Important tag -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +You can create a `CustomTitleView` as a custom `UIView` which we will inflate in `setTitleView()`: -```swift +```swift lines import UIKit -class `CustomTitleView`: UIView { +class CustomTitleView: UIView { private let titleLabel: UILabel = { let label = UILabel() @@ -597,9 +629,205 @@ class `CustomTitleView`: UIView { } } ``` + + + +--- + +## Props + +All props are optional unless noted. + +--- + +### call + +The incoming call object to display. + +| | | +|---|---| +| Type | `Call` | +| Default | Auto-detected | + +--- + +### disableSoundForCalls + +Disables the incoming call ringtone. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### customSoundForCalls + +Custom sound file URL for incoming calls. + +| | | +|---|---| +| Type | `URL?` | +| Default | `nil` | + +--- + +### avatarStyle + +Customizes the appearance of the caller's avatar. + +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | + +```swift lines +import CometChatUIKitSwift + +let customAvatarStyle = AvatarStyle() +customAvatarStyle.backgroundColor = UIColor.systemPurple +customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) + +let incomingCall = CometChatIncomingCall() +incomingCall.avatarStyle = customAvatarStyle +``` + +--- + +## Events + +Events emitted by the Incoming Call component: + +| Event | Description | +|-------|-------------| +| `onIncomingCallAccepted` | Triggers when the logged-in user accepts the incoming call | +| `onIncomingCallRejected` | Triggers when the logged-in user rejects the incoming call | +| `onCallEnded` | Triggers when the call ends | + +--- + +## View Slots + +| Slot | Signature | Replaces | +|------|-----------|----------| +| `listItemView` | `(Call) -> UIView` | Entire list item | +| `leadingView` | `(Call) -> UIView` | Avatar / left section | +| `titleView` | `(Call) -> UIView` | Name / title text | +| `subtitleView` | `(Call) -> UIView` | Subtitle text (call type) | +| `trailingView` | `(Call) -> UIView` | Right section | + +### subtitleView + +You can customize the subtitle view of an incoming call component using the property below. + + + +```swift lines +cometChatIncomingCall.set(subtitleView: { call in + let view = CustomSubtitleView() + return view +}) +``` + + + +### trailingView + +You can customize the trailing view of an incoming call component using the property below. + + + +```swift lines +cometChatIncomingCall.set(trailingView: { call in + let view = CustomTrailingView() + return view +}) +``` + + + +--- + +## Common Patterns + +### Present Incoming Call Screen + +Present the incoming call screen when a call is received: + + + +```swift lines +// In your call listener +func onIncomingCallReceived(incomingCall: Call) { + DispatchQueue.main.async { + let incomingCallVC = CometChatIncomingCall() + incomingCallVC.set(call: incomingCall) + incomingCallVC.modalPresentationStyle = .fullScreen + + // Get the top view controller to present from + if let topVC = UIApplication.shared.keyWindow?.rootViewController { + topVC.present(incomingCallVC, animated: true) + } + } +} +``` + + + +### Handle Call Accept and Navigate to Ongoing Call +Transition from incoming call to ongoing call when accepted: + + + +```swift lines +let incomingCall = CometChatIncomingCall() +incomingCall.set(call: call) +incomingCall.set(onAcceptClick: { [weak self] acceptedCall, controller in + // Dismiss incoming call screen + controller.dismiss(animated: false) { + // Present ongoing call screen + let ongoingCall = CometChatOngoingCall() + ongoingCall.set(sessionId: acceptedCall.sessionId ?? "") + ongoingCall.modalPresentationStyle = .fullScreen + self?.present(ongoingCall, animated: true) + } +}) +``` + + +### Custom Ringtone for Incoming Calls + +Set a custom sound for incoming calls: + + +```swift lines +let incomingCall = CometChatIncomingCall() +incomingCall.set(call: call) + +// Use custom ringtone +if let soundURL = Bundle.main.url(forResource: "custom_ringtone", withExtension: "mp3") { + incomingCall.set(customSoundForCalls: soundURL) +} +``` + -*** +--- + +## Related Components + + + + Display outgoing call interface + + + Display active call interface + + + Display call history + + diff --git a/ui-kit/ios/ios-conversation.mdx b/ui-kit/ios/ios-conversation.mdx index 6124c475c..dcad85109 100644 --- a/ui-kit/ios/ios-conversation.mdx +++ b/ui-kit/ios/ios-conversation.mdx @@ -1,68 +1,79 @@ --- -title: "Building A Conversation List + Message View" +title: "Conversation List + Message View" sidebarTitle: "Conversation List + Message View" +description: "Build a two-panel conversation list + message view layout in iOS with CometChat UI Kit." --- -The **Conversation List + Message View** layout offers a modern two-panel chat experience. It's ideal for applications needing seamless switching between multiple conversations and chat windows—similar to **WhatsApp Web**, **Slack**, or **Microsoft Teams**. + -*** +| Field | Value | +| --- | --- | +| Package | `CometChatUIKitSwift` | +| Framework | UIKit / SwiftUI | +| Components | `CometChatConversations`, `CometChatMessageHeader`, `CometChatMessageList`, `CometChatMessageComposer` | +| Layout | Push navigation — conversation list → message view | +| Prerequisite | Complete [iOS Integration](/ui-kit/ios/getting-started) Steps 1–4 first | +| Pattern | iMessage, WhatsApp, Slack | -## **User Interface Preview** + + +This guide builds a conversation list with push navigation to messages. Users tap a conversation to open the chat view. + +This assumes you've already completed [iOS Integration](/ui-kit/ios/getting-started) (project created, UI Kit installed, init + login working, permissions configured). -### **Key Components** +--- -1. **Chat Header** – Displays user or group name, avatar, and back button. -2. **Message List** – Displays chat messages and real-time updates. -3. **Message Composer** – Allows sending of text, media, and reactions. +## What You're Building -*** +Three components working together: -## **Step-by-Step Guide** +1. **Conversation list** — shows all active conversations (users and groups) +2. **Message view** — displays chat messages for the selected conversation in real time +3. **Message composer** — text input with support for media, emojis, and reactions + +--- -### **Step 1: Setup SceneDelegate.swift** +## Step 1 — Setup SceneDelegate -Ensure UIKit is initialized and the user is logged in before presenting the conversation view. +Wire up the conversation list after successful login. When a user taps a conversation, push to the messages view. -```swift SceneDelegate.swift highlight={15-17} lines +```swift title="SceneDelegate.swift" highlight={13-15} lines import UIKit import CometChatUIKitSwift import CometChatSDK -import CometChatCallsSDK class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } let uikitSettings = UIKitSettings() - .set(appID: "<#Enter Your App ID Here#>") - .set(region: "<#Enter Your Region Code Here#>") - .set(authKey: "<#Enter Your AuthKey Here#>") + .set(appID: "APP_ID") // Replace with your App ID + .set(region: "REGION") // Replace with your Region + .set(authKey: "AUTH_KEY") // Replace with your Auth Key (dev only) .subscribePresenceForAllUsers() .build() CometChatUIKit.init(uiKitSettings: uikitSettings) { result in switch result { case .success: - debugPrint("CometChatUIKit initialization succeeded") + debugPrint("CometChat initialized") let uid = "cometchat-uid-1" CometChatUIKit.login(uid: uid) { loginResult in switch loginResult { case .success: - debugPrint("CometChatUIKit login succeeded") + debugPrint("Login successful") DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - self.setupConversationsView(windowScene: windowScene) + self?.setupConversationsView(windowScene: windowScene) } case .onError(let error): @@ -72,7 +83,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } case .failure(let error): - debugPrint("Initialization failed: \(error.localizedDescription)") + debugPrint("Init failed: \(error.localizedDescription)") } } } @@ -84,7 +95,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { conversationsVC.set(onItemClick: { [weak navController] conversation, _ in let messagesVC = MessagesVC() messagesVC.group = conversation.conversationWith as? Group - messagesVC.user = conversation.conversationWith as? CometChatSDK.User + messagesVC.user = conversation.conversationWith as? User navController?.pushViewController(messagesVC, animated: true) }) @@ -95,35 +106,39 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } ``` -*** +Key points: +- `CometChatConversations` displays the conversation list +- `onItemClick` fires when a user taps a conversation, passing the `Conversation` object +- Extract `User` or `Group` from `conversation.conversationWith` and pass to the messages view + +--- + +## Step 2 — Create MessagesVC + +Create a new Swift file for the messages view controller: -### **Step 2: Create MessagesVC.swift** +1. In Xcode, right-click your project folder in the Navigator +2. Select **New File...** +3. Choose **Swift File** and click Next +4. Name it `MessagesVC.swift` and click Create -This view controller handles chat between users or within groups. +Add the following code. This view controller assembles the header, message list, and composer. -```swift MessagesVC.swift lines +```swift title="MessagesVC.swift" lines import UIKit import CometChatSDK import CometChatUIKitSwift -/// A view controller that displays a chat interface using CometChat components class MessagesVC: UIViewController { // MARK: - Properties - - /// The user entity for one-on-one chats var user: User? - - /// The group entity for group chats var group: Group? // MARK: - UI Components - - /// Header view displaying user/group information private lazy var headerView: CometChatMessageHeader = { let view = CometChatMessageHeader() view.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type if let user = user { view.set(user: user) } else if let group = group { @@ -133,25 +148,9 @@ class MessagesVC: UIViewController { return view }() - /// Message input composer view - private lazy var composerView: CometChatMessageComposer = { - let composer = CometChatMessageComposer() - composer.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type - if let user = user { - composer.set(user: user) - } else if let group = group { - composer.set(group: group) - } - composer.set(controller: self) - return composer - }() - - /// List view displaying chat messages private lazy var messageListView: CometChatMessageList = { let listView = CometChatMessageList() listView.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type if let user = user { listView.set(user: user) } else if let group = group { @@ -161,8 +160,19 @@ class MessagesVC: UIViewController { return listView }() - // MARK: - Lifecycle Methods + private lazy var composerView: CometChatMessageComposer = { + let composer = CometChatMessageComposer() + composer.translatesAutoresizingMaskIntoConstraints = false + if let user = user { + composer.set(user: user) + } else if let group = group { + composer.set(group: group) + } + composer.set(controller: self) + return composer + }() + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() configureView() @@ -174,34 +184,29 @@ class MessagesVC: UIViewController { navigationController?.setNavigationBarHidden(false, animated: true) } - // MARK: - Private Methods - - /// Configure basic view properties + // MARK: - Setup private func configureView() { view.backgroundColor = .systemBackground navigationController?.setNavigationBarHidden(true, animated: false) } - /// Set up view hierarchy and constraints private func setupLayout() { - // Add subviews to the view hierarchy [headerView, messageListView, composerView].forEach { view.addSubview($0) } - // Set up constraints NSLayoutConstraint.activate([ - // Header view constraints + // Header headerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), headerView.heightAnchor.constraint(equalToConstant: 50), - // Message list view constraints + // Message list messageListView.topAnchor.constraint(equalTo: headerView.bottomAnchor), messageListView.leadingAnchor.constraint(equalTo: view.leadingAnchor), messageListView.trailingAnchor.constraint(equalTo: view.trailingAnchor), messageListView.bottomAnchor.constraint(equalTo: composerView.topAnchor), - // Composer view constraints + // Composer composerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), composerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), composerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) @@ -210,12 +215,33 @@ class MessagesVC: UIViewController { } ``` -*** +How it works: +- `CometChatMessageHeader` shows user/group info and back button +- `CometChatMessageList` displays messages with real-time updates +- `CometChatMessageComposer` handles text input, media, and reactions +- Pass either `user` or `group` to each component, never both -## **Next Steps** +--- -### **Enhance the User Experience** +## Step 3 — Run the Project -* **[Advanced Customizations](/ui-kit/ios/theme-introduction)** – Personalize the chat UI to align with your brand. +Build and run in Xcode. You should see the conversation list. Tap any conversation to push to the messages view. + +--- -*** +## Next Steps + + + + Customize colors, fonts, and styles to match your brand + + + Browse all prebuilt UI components + + + Back to the main setup guide + + + Chat features included out of the box + + diff --git a/ui-kit/ios/ios-one-to-one-chat.mdx b/ui-kit/ios/ios-one-to-one-chat.mdx index ae1c160d6..2cdb40fc4 100644 --- a/ui-kit/ios/ios-one-to-one-chat.mdx +++ b/ui-kit/ios/ios-one-to-one-chat.mdx @@ -1,68 +1,82 @@ --- -title: "Building A One To One/Group Chat Experience" -sidebarTitle: "One To One/Group Chat" +title: "One-to-One / Group Chat" +sidebarTitle: "One-to-One / Group Chat" +description: "Build a focused one-to-one or group chat experience in iOS with CometChat UI Kit." --- -The **One-to-One Chat** feature provides a streamlined **direct messaging interface**, making it ideal for **support chats, dating apps, and private messaging platforms**. This setup eliminates distractions by focusing solely on a **dedicated chat window**. + -*** +| Field | Value | +| --- | --- | +| Package | `CometChatUIKitSwift` | +| Framework | UIKit / SwiftUI | +| Components | `CometChatMessageHeader`, `CometChatMessageList`, `CometChatMessageComposer` | +| Layout | Single chat window — no sidebar, no conversation list | +| Prerequisite | Complete [iOS Integration](/ui-kit/ios/getting-started) Steps 1–4 first | +| Pattern | Support chat, embedded widgets, focused messaging | -## **User Interface Preview** + + +This guide builds a single chat window — no sidebar, no conversation list. Users go directly into a one-to-one or group chat. Good for support chat, contextual messaging, or any focused messaging experience. + +This assumes you've already completed [iOS Integration](/ui-kit/ios/getting-started) (project created, UI Kit installed, init + login working, permissions configured). -### **Key Components** +--- -1. **Chat Header** – Displays recipient details and optional call/video call buttons. -2. **Message View** – Shows real-time chat history. -3. **Message Input Box** – Enables users to send messages, media, and reactions. +## What You're Building -*** +Three components stacked vertically: -## **Step-by-Step Guide** +1. **Chat header** — displays recipient name, avatar, online status, and optional call buttons +2. **Message list** — real-time chat history with scrolling +3. **Message composer** — text input with media, emojis, and reactions -### **Step 1: Setup SceneDelegate.swift** +--- -Ensure UI Kit is initialized and the user is logged in before presenting the message view. +## Step 1 — Setup SceneDelegate -```swift SceneDelegate.swift highlight={15-17} lines +Fetch the user (or group) after login and launch directly into the messages view. + +```swift title="SceneDelegate.swift" highlight={13-15,34} lines import UIKit import CometChatUIKitSwift import CometChatSDK -import CometChatCallsSDK class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } let uikitSettings = UIKitSettings() - .set(appID: "<#Enter Your App ID Here#>") - .set(region: "<#Enter Your Region Code Here#>") - .set(authKey: "<#Enter Your AuthKey Here#>") + .set(appID: "APP_ID") // Replace with your App ID + .set(region: "REGION") // Replace with your Region + .set(authKey: "AUTH_KEY") // Replace with your Auth Key (dev only) .subscribePresenceForAllUsers() .build() CometChatUIKit.init(uiKitSettings: uikitSettings) { result in switch result { case .success: - debugPrint("CometChat UI Kit initialization succeeded") + debugPrint("CometChat initialized") let uid = "cometchat-uid-1" CometChatUIKit.login(uid: uid) { loginResult in switch loginResult { case .success: - debugPrint("CometChat UI Kit login succeeded") + debugPrint("Login successful") DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - self.setUpOneOneOrGroupConversation(windowScene: windowScene, uid: "cometchat-uid-2") + self?.setUpOneOneOrGroupConversation( + windowScene: windowScene, + uid: "cometchat-uid-2" // The user to chat with + ) } case .onError(let error): @@ -72,60 +86,85 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } case .failure(let error): - debugPrint("Initialization failed: \(error.localizedDescription)") + debugPrint("Init failed: \(error.localizedDescription)") } } } - func setUpOneOneOrGroupConversation(windowScene: UIWindowScene, uid : String) { + func setUpOneOneOrGroupConversation(windowScene: UIWindowScene, uid: String) { CometChat.getUser(UID: uid) { user in - DispatchQueue.main.async { let messagesVC = MessagesVC() - let navController = UINavigationController(rootViewController: messagesVC) messagesVC.user = user + + let navController = UINavigationController(rootViewController: messagesVC) self.window = UIWindow(windowScene: windowScene) self.window?.rootViewController = navController self.window?.makeKeyAndVisible() } } onError: { error in - + debugPrint("Failed to fetch user: \(error?.description ?? "")") } + } +} +``` + +Key points: +- `CometChat.getUser(UID:)` fetches the user object from the SDK — you need a real user object, not a manually constructed one. +- The highlighted lines show where to set the credentials and the UID of the user to chat with. +--- + +## Switching Between User and Group Chat + +To load a group chat instead of one-to-one, replace `getUser` with `getGroup`: + +```swift highlight={2} lines +func setUpGroupConversation(windowScene: UIWindowScene, guid: String) { + CometChat.getGroup(GUID: guid) { group in + DispatchQueue.main.async { + let messagesVC = MessagesVC() + messagesVC.group = group + + let navController = UINavigationController(rootViewController: messagesVC) + self.window = UIWindow(windowScene: windowScene) + self.window?.rootViewController = navController + self.window?.makeKeyAndVisible() + } + } onError: { error in + debugPrint("Failed to fetch group: \(error?.description ?? "")") } - } ``` -*** +--- + +## Step 2 — Create MessagesVC + +Create a new Swift file for the messages view controller: -### **Step 2: Create MessagesVC.swift** +1. In Xcode, right-click your project folder in the Navigator +2. Select **New File...** +3. Choose **Swift File** and click Next +4. Name it `MessagesVC.swift` and click Create -This view controller handles chat between users or within groups. +Add the following code. This view controller assembles the header, message list, and composer. -```swift MessagesVC.swift lines +```swift title="MessagesVC.swift" lines import UIKit import CometChatSDK import CometChatUIKitSwift -/// A view controller that displays a chat interface using CometChat components class MessagesVC: UIViewController { // MARK: - Properties - - /// The user entity for one-on-one chats var user: User? - - /// The group entity for group chats var group: Group? // MARK: - UI Components - - /// Header view displaying user/group information private lazy var headerView: CometChatMessageHeader = { let view = CometChatMessageHeader() view.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type if let user = user { view.set(user: user) } else if let group = group { @@ -135,25 +174,9 @@ class MessagesVC: UIViewController { return view }() - /// Message input composer view - private lazy var composerView: CometChatMessageComposer = { - let composer = CometChatMessageComposer() - composer.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type - if let user = user { - composer.set(user: user) - } else if let group = group { - composer.set(group: group) - } - composer.set(controller: self) - return composer - }() - - /// List view displaying chat messages private lazy var messageListView: CometChatMessageList = { let listView = CometChatMessageList() listView.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type if let user = user { listView.set(user: user) } else if let group = group { @@ -163,8 +186,19 @@ class MessagesVC: UIViewController { return listView }() - // MARK: - Lifecycle Methods + private lazy var composerView: CometChatMessageComposer = { + let composer = CometChatMessageComposer() + composer.translatesAutoresizingMaskIntoConstraints = false + if let user = user { + composer.set(user: user) + } else if let group = group { + composer.set(group: group) + } + composer.set(controller: self) + return composer + }() + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() configureView() @@ -176,34 +210,29 @@ class MessagesVC: UIViewController { navigationController?.setNavigationBarHidden(false, animated: true) } - // MARK: - Private Methods - - /// Configure basic view properties + // MARK: - Setup private func configureView() { view.backgroundColor = .systemBackground navigationController?.setNavigationBarHidden(true, animated: false) } - /// Set up view hierarchy and constraints private func setupLayout() { - // Add subviews to the view hierarchy [headerView, messageListView, composerView].forEach { view.addSubview($0) } - // Set up constraints NSLayoutConstraint.activate([ - // Header view constraints + // Header headerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), headerView.heightAnchor.constraint(equalToConstant: 50), - // Message list view constraints + // Message list messageListView.topAnchor.constraint(equalTo: headerView.bottomAnchor), messageListView.leadingAnchor.constraint(equalTo: view.leadingAnchor), messageListView.trailingAnchor.constraint(equalTo: view.trailingAnchor), messageListView.bottomAnchor.constraint(equalTo: composerView.topAnchor), - // Composer view constraints + // Composer composerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), composerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), composerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) @@ -212,12 +241,33 @@ class MessagesVC: UIViewController { } ``` -*** +How it works: +- `CometChatMessageHeader` shows user/group info and back button +- `CometChatMessageList` displays messages with real-time updates +- `CometChatMessageComposer` handles text input, media, and reactions +- Pass either `user` or `group` to each component, never both -## **Next Steps** +--- + +## Step 3 — Run the Project -### **Enhance the User Experience** +Build and run in Xcode. You should see the chat window load directly with the conversation for the UID you set. -* **[Advanced Customizations](/ui-kit/ios/theme-introduction)** – Personalize the chat UI to align with your brand. +--- -*** +## Next Steps + + + + Customize colors, fonts, and styles to match your brand + + + Browse all prebuilt UI components + + + Back to the main setup guide + + + Chat features included out of the box + + diff --git a/ui-kit/ios/ios-tab-based-chat.mdx b/ui-kit/ios/ios-tab-based-chat.mdx index 8c6d7b047..e49231e10 100644 --- a/ui-kit/ios/ios-tab-based-chat.mdx +++ b/ui-kit/ios/ios-tab-based-chat.mdx @@ -1,41 +1,59 @@ --- -title: "Building A Tab Based Messaging UI In iOS" -sidebarTitle: "Tab Based Chat Experience" +title: "Tab-Based Chat" +sidebarTitle: "Tab-Based Chat" +description: "Build a tab-based messaging UI with chats, calls, users, and groups in iOS with CometChat UI Kit." --- -This guide walks you through creating a **tab-based messaging interface** in your **iOS application** using **CometChat UI Kit for iOS**. The UI includes tabs for **Chats**, **Calls**, **Users**, and **Groups**, offering an organized and fluid experience. + -*** +| Field | Value | +| --- | --- | +| Package | `CometChatUIKitSwift` | +| Framework | UIKit / SwiftUI | +| Components | `CometChatConversations`, `CometChatCallLogs`, `CometChatUsers`, `CometChatGroups`, `CometChatMessageHeader`, `CometChatMessageList`, `CometChatMessageComposer` | +| Layout | UITabBarController with Chats, Calls, Users, Groups tabs | +| Prerequisite | Complete [iOS Integration](/ui-kit/ios/getting-started) Steps 1–4 first | +| Pattern | Full-featured messaging app with multiple sections | -## **User Interface Preview** + + +This guide builds a tabbed messaging UI — Chats, Calls, Users, and Groups tabs using `UITabBarController`. Good for full-featured apps that need more than just conversations. + +This assumes you've already completed [iOS Integration](/ui-kit/ios/getting-started) (project created, UI Kit installed, init + login working, permissions configured). -This layout contains: +--- + +## What You're Building + +Four tabs working together: -1. **Conversations** – Lists all recent chats. -2. **Calls** – Displays call logs. -3. **Users** – Lists available users. -4. **Groups** – Lists available groups. +1. **Chats** — conversation list with push navigation to messages +2. **Calls** — call logs history +3. **Users** — list of available users +4. **Groups** — list of available groups -*** +--- -## **Step-by-Step Guide** +## Step 1 — Setup SceneDelegate -### **Step 1: Initialize UIKit in `SceneDelegate.swift`** +Initialize CometChat and launch the tabbed view after login. -Ensure UIKit is initialized and the user is logged in before presenting the tabbed view. +```swift title="SceneDelegate.swift" highlight={9-11} lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -```swift SceneDelegate.swift highlight={5-7} lines func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let uikitSettings = UIKitSettings() - .set(appID: "<#Enter Your App ID Here#>") - .set(region: "<#Enter Your Region Code Here#>") - .set(authKey: "<#Enter Your AuthKey Here#>") + .set(appID: "APP_ID") // Replace with your App ID + .set(region: "REGION") // Replace with your Region + .set(authKey: "AUTH_KEY") // Replace with your Auth Key (dev only) .subscribePresenceForAllUsers() .build() @@ -59,16 +77,14 @@ func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options conn } ``` -*** +--- -### **Step 2: Setup Tab Bar** +## Step 2 — Setup Tab Bar -Create a method to display the tab layout. +Create the `UITabBarController` with all four tabs. Each tab has its own navigation controller. -```swift SceneDelegate.swift lines +```swift title="SceneDelegate.swift" lines func setupTabbedView(windowScene: UIWindowScene) { - - // Create the main Tab Bar Controller let tabBarController = UITabBarController() tabBarController.tabBar.backgroundColor = .white @@ -81,11 +97,10 @@ func setupTabbedView(windowScene: UIWindowScene) { tag: 0 ) - // Handle item click inside conversation list conversationsVC.set(onItemClick: { [weak conversationsNav] conversation, indexPath in let messagesVC = MessagesVC() messagesVC.group = conversation.conversationWith as? Group - messagesVC.user = conversation.conversationWith as? CometChatSDK.User + messagesVC.user = conversation.conversationWith as? User messagesVC.hidesBottomBarWhenPushed = true conversationsNav?.pushViewController(messagesVC, animated: true) }) @@ -117,7 +132,6 @@ func setupTabbedView(windowScene: UIWindowScene) { tag: 3 ) - // Assign all navigation controllers to the Tab Bar tabBarController.viewControllers = [ conversationsNav, callLogsNav, @@ -125,46 +139,48 @@ func setupTabbedView(windowScene: UIWindowScene) { groupsNav ] - // Ensures layout includes space for opaque bars like the navigation bar tabBarController.extendedLayoutIncludesOpaqueBars = true - // Setup and display main window with tabBarController as root window = UIWindow(windowScene: windowScene) window?.rootViewController = tabBarController window?.makeKeyAndVisible() - } ``` -*** +Key points: +- Each tab wraps its view controller in a `UINavigationController` for push navigation +- `onItemClick` on conversations pushes to the messages view +- `hidesBottomBarWhenPushed = true` hides the tab bar when viewing messages +- SF Symbols are used for tab icons — customize as needed -### **Step 3: Create `MessagesVC.swift`** +--- + +## Step 3 — Create MessagesVC + +Create a new Swift file for the messages view controller: -This view controller handles chat between users or within groups. +1. In Xcode, right-click your project folder in the Navigator +2. Select **New File...** +3. Choose **Swift File** and click Next +4. Name it `MessagesVC.swift` and click Create -```swift MessagesVC.swift lines +Add the following code. This view controller assembles the header, message list, and composer. + +```swift title="MessagesVC.swift" lines import UIKit import CometChatSDK import CometChatUIKitSwift -/// A view controller that displays a chat interface using CometChat components class MessagesVC: UIViewController { // MARK: - Properties - - /// The user entity for one-on-one chats var user: User? - - /// The group entity for group chats var group: Group? // MARK: - UI Components - - /// Header view displaying user/group information private lazy var headerView: CometChatMessageHeader = { let view = CometChatMessageHeader() view.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type if let user = user { view.set(user: user) } else if let group = group { @@ -174,25 +190,9 @@ class MessagesVC: UIViewController { return view }() - /// Message input composer view - private lazy var composerView: CometChatMessageComposer = { - let composer = CometChatMessageComposer() - composer.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type - if let user = user { - composer.set(user: user) - } else if let group = group { - composer.set(group: group) - } - composer.set(controller: self) - return composer - }() - - /// List view displaying chat messages private lazy var messageListView: CometChatMessageList = { let listView = CometChatMessageList() listView.translatesAutoresizingMaskIntoConstraints = false - // Configure for the appropriate conversation type if let user = user { listView.set(user: user) } else if let group = group { @@ -202,8 +202,19 @@ class MessagesVC: UIViewController { return listView }() - // MARK: - Lifecycle Methods + private lazy var composerView: CometChatMessageComposer = { + let composer = CometChatMessageComposer() + composer.translatesAutoresizingMaskIntoConstraints = false + if let user = user { + composer.set(user: user) + } else if let group = group { + composer.set(group: group) + } + composer.set(controller: self) + return composer + }() + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() configureView() @@ -215,34 +226,29 @@ class MessagesVC: UIViewController { navigationController?.setNavigationBarHidden(false, animated: true) } - // MARK: - Private Methods - - /// Configure basic view properties + // MARK: - Setup private func configureView() { view.backgroundColor = .systemBackground navigationController?.setNavigationBarHidden(true, animated: false) } - /// Set up view hierarchy and constraints private func setupLayout() { - // Add subviews to the view hierarchy [headerView, messageListView, composerView].forEach { view.addSubview($0) } - // Set up constraints NSLayoutConstraint.activate([ - // Header view constraints + // Header headerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), headerView.heightAnchor.constraint(equalToConstant: 50), - // Message list view constraints + // Message list messageListView.topAnchor.constraint(equalTo: headerView.bottomAnchor), messageListView.leadingAnchor.constraint(equalTo: view.leadingAnchor), messageListView.trailingAnchor.constraint(equalTo: view.trailingAnchor), messageListView.bottomAnchor.constraint(equalTo: composerView.topAnchor), - // Composer view constraints + // Composer composerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), composerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), composerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) @@ -251,12 +257,27 @@ class MessagesVC: UIViewController { } ``` -*** +--- -## **Next Steps** +## Step 4 — Run the Project -### **Enhance the User Experience** +Build and run in Xcode. You should see the tab bar at the bottom with Chats, Calls, Users, and Groups. Tap any conversation to push to the messages view. + +--- -* **[Advanced Customizations](/ui-kit/ios/theme-introduction)** – Personalize the chat UI to align with your brand. +## Next Steps -*** + + + Customize colors, fonts, and styles to match your brand + + + Browse all prebuilt UI components + + + Back to the main setup guide + + + Chat features included out of the box + + diff --git a/ui-kit/ios/localize.mdx b/ui-kit/ios/localize.mdx index af5cc2617..9e6197848 100644 --- a/ui-kit/ios/localize.mdx +++ b/ui-kit/ios/localize.mdx @@ -1,74 +1,82 @@ --- title: "Localize" +sidebarTitle: "Localization" +description: "Adapt CometChat UI Kit to different languages and customize date/time formatting for your iOS application" --- + + +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Localize Class | `CometChatLocalize` | +| Set Locale | `CometChatLocalize.set(locale: .french)` | +| Get Locale | `CometChatLocalize.getLocale()` | +| Supported Languages | 17 languages (en, fr, de, es, hi, ru, pt, zh, ja, ko, tr, ms, sv, lt, hu, nl) | +| Override Strings | Define same key in app's `Localizable.strings` | +| DateTime Formatter | `CometChatUIKit.dateTimeFormatter` or component-level | +| DateTime Closures | `time`, `today`, `yesterday`, `lastweek`, `otherDay`, `minute`, `minutes`, `hour`, `hours` | + + + ## Overview -CometChat UI Kit provides language localization to adapt to the language of a specific country or region. The CometChatLocalize class allows you to detect the language of your users based on their browser or device settings, and set the language accordingly. - -CometChatLocalize is a class that includes methods related to locale. Developers can use these methods to change the language of the UI Kit library. - -Presently, the UI Kit supports 17 languages for localization, which are: - -- English (en, en-US) -- English-UK (en-GB) -- Chinese (zh, zh-TW) -- Spanish (es) -- Hindi (hi) -- Russian (ru) -- Portuguese (pt) -- Malay (ms) -- French (fr) -- German (de) -- Swedish (sv) -- Lithuanian (lt) -- Hungarian (hu) -- Dutch (nl) -- Japanese (ja) -- Korean (ko) -- Turkish (tr) +CometChat UI Kit provides language localization to adapt to the language of a specific country or region. The `CometChatLocalize` class allows you to detect the language of your users based on their browser or device settings, and set the language accordingly. + +`CometChatLocalize` is a class that includes methods related to locale. Developers can use these methods to change the language of the UI Kit library. + +### Supported Languages + +The UI Kit supports 17 languages for localization: + +| Language | Code | Language | Code | +|----------|------|----------|------| +| English | `en`, `en-US` | Japanese | `ja` | +| English-UK | `en-GB` | Korean | `ko` | +| Chinese | `zh`, `zh-TW` | Turkish | `tr` | +| Spanish | `es` | Malay | `ms` | +| Hindi | `hi` | Swedish | `sv` | +| Russian | `ru` | Lithuanian | `lt` | +| Portuguese | `pt` | Hungarian | `hu` | +| French | `fr` | Dutch | `nl` | +| German | `de` | | | --- -### How Localization Works +## How Localization Works Localization in the SDK is powered by: -1. The **CometChatLocalize** class — for setting and fetching the active locale. -2. A **String** extension method called `.localize` — to fetch localized text dynamically. +1. The `CometChatLocalize` class — for setting and fetching the active locale +2. A `String` extension method called `.localize` — to fetch localized text dynamically -#### Example: - -```swift +```swift lines +// Example: Localizing a string key "CHATS".localize ``` The SDK checks the following bundles in order: -1. The app's Localizable.strings (for developer-defined overrides) +1. The app's `Localizable.strings` (for developer-defined overrides) 2. The SDK's built-in localization files 3. Fallback to English or the original key if no match is found --- -### Methods - -Here are the methods included in the CometChatLocalize class: +## Methods -| **Method** | **Description** | -|---------------------------------|------------------------------------------------------| -| **set(locale:)** | Sets the language using Language enum (.english, .french, etc.) | -| **getLocale()** | Returns the currently active locale. By default, it will return the current language from the device/browser. | +The `CometChatLocalize` class provides the following methods: +| Method | Description | +|--------|-------------| +| `set(locale:)` | Sets the language using Language enum (`.english`, `.french`, etc.) | +| `getLocale()` | Returns the currently active locale. By default, returns the current language from the device/browser | ### Usage -Here is how you can put these methods into use: - - - -```swift + +```swift lines // Set Language to French CometChatLocalize.set(locale: .french) @@ -80,51 +88,57 @@ let lang = CometChatLocalize.getLocale() --- -### App-Level Overrides +## App-Level Overrides -To customize any text used by the SDK, simply define the same key in your app’s Localizable.strings files. +To customize any text used by the SDK, simply define the same key in your app's `Localizable.strings` files. -Example – Localizable.strings (en.lproj): - - -```swift + +```swift lines "CHATS" = "Conversations"; "USERS" = "People"; ``` -When your app runs, this will override the SDK’s built-in translation for "CHATS" and "USERS" wherever they are used via .localize. +When your app runs, this will override the SDK's built-in translation for "CHATS" and "USERS" wherever they are used via `.localize`. No additional configuration is needed. --- -### How to discover available keys +## How to Discover Available Keys All localization keys used by the SDK are available in our [GitHub repository](https://github.com/cometchat/cometchat-uikit-ios/tree/v5/CometChatUIKitSwift/Components/Shared/Resources). This allows you to: -* Know exactly which keys are used -* Provide custom translations for them in your app -* Keep your localization files in sync with SDK updates +- Know exactly which keys are used +- Provide custom translations for them in your app +- Keep your localization files in sync with SDK updates -By using the CometChatLocalize class, you can provide a user-friendly, localized experience to your users, enhancing the overall user experience within your application. +By using the `CometChatLocalize` class, you can provide a user-friendly, localized experience to your users, enhancing the overall user experience within your application. + +--- ## Customization -CometChatUIKit for iOS allows developers to customize localization values easily. For example, if an English-language app requires the label "Chat" to be shown as "Chats," the developer can simply define the same localization key used in the UIKit inside the app's English localization file and assign it a different value. CometChatUIKit will automatically detect and use the overridden value from the app-level localization. +CometChatUIKit for iOS allows developers to customize localization values easily. For example, if an English-language app requires the label "Chat" to be shown as "Chats," the developer can simply define the same localization key used in the UIKit inside the app's English localization file and assign it a different value. CometChatUIKit will automatically detect and use the overridden value from the app-level localization. ### Steps to Customize Strings -1. Identify the String Key - - Check the UIKit source code for the exact key of the string you want to modify. [Localization file](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Resources/en.lproj/Localizable.strings). -2. Navigate to the app level localization file for that same langauge - - Added the same key with the changed vale you whant value. -3. Build and Run Your App - - The changes will automatically reflect wherever the key is used. + +1. **Identify the String Key** + - Check the UIKit source code for the exact key of the string you want to modify: [Localization file](https://github.com/cometchat/cometchat-uikit-ios/blob/v5/CometChatUIKitSwift/Components/Shared/Resources/en.lproj/Localizable.strings) + +2. **Navigate to the App Level Localization File** + - Add the same key with the changed value you want + +3. **Build and Run Your App** + - The changes will automatically reflect wherever the key is used + +--- ## DateTimeFormatter -This feature allows developers to customize how date and time values are displayed across the CometChat UI Kit components. It introduces the CometChatDateTimeFormatter class, enabling tailored formatting for strings such as "Today", "Yesterday", or time formats like "12:00 PM". + +This feature allows developers to customize how date and time values are displayed across the CometChat UI Kit components. It introduces the `CometChatDateTimeFormatter` class, enabling tailored formatting for strings such as "Today", "Yesterday", or time formats like "12:00 PM". Custom formats can be set based on locale, branding, or user preferences, enhancing localization and UX consistency. @@ -144,33 +158,35 @@ This system uses closures that you can override to provide your own custom strin `CometChatDateTimeFormatter` is a configuration class that exposes customizable closures for various time-related strings. Developers can assign custom behavior to each closure based on their desired formatting logic. -#### Available closures +#### Available Closures -| Property | Description | Code | -|---------------------------------------|--------------------------------------------------------------------------|---------------------------------------------------------| -| time | Called to format a timestamp as a standard time (e.g., "12:30 PM"). | `CometChatUIKit.dateTimeFormatter.time = { ... }` | -| today | Called when rendering messages sent today. | `CometChatUIKit.dateTimeFormatter.today = { ... }` | -| yesterday | Called for yesterday's messages. | `CometChatUIKit.dateTimeFormatter.yesterday = { ... }` | -| lastweek | Called for messages within the last week. | `CometChatUIKit.dateTimeFormatter.lastweek = { ... }` | -| otherDay | Called for dates older than last week. | `CometChatUIKit.dateTimeFormatter.otherDay = { ... }` | -| minute | Called when referring to "a minute ago". | `CometChatUIKit.dateTimeFormatter.minute = { ... }` | -| minutes | Called for "x minutes ago". | `CometChatUIKit.dateTimeFormatter.minutes = { ... }` | -| hour | Called for "an hour ago". | `CometChatUIKit.dateTimeFormatter.hour = { ... }` | -| hours | Called for "x hours ago". | `CometChatUIKit.dateTimeFormatter.hours = { ... }` | +| Property | Description | Code | +|----------|-------------|------| +| `time` | Called to format a timestamp as a standard time (e.g., "12:30 PM") | `CometChatUIKit.dateTimeFormatter.time = { ... }` | +| `today` | Called when rendering messages sent today | `CometChatUIKit.dateTimeFormatter.today = { ... }` | +| `yesterday` | Called for yesterday's messages | `CometChatUIKit.dateTimeFormatter.yesterday = { ... }` | +| `lastWeek` | Called for messages within the last week | `CometChatUIKit.dateTimeFormatter.lastWeek = { ... }` | +| `otherDay` | Called for dates older than last week | `CometChatUIKit.dateTimeFormatter.otherDay = { ... }` | +| `minute` | Called when referring to "a minute ago" | `CometChatUIKit.dateTimeFormatter.minute = { ... }` | +| `minutes` | Called for "x minutes ago" | `CometChatUIKit.dateTimeFormatter.minutes = { ... }` | +| `hour` | Called for "an hour ago" | `CometChatUIKit.dateTimeFormatter.hour = { ... }` | +| `hours` | Called for "x hours ago" | `CometChatUIKit.dateTimeFormatter.hours = { ... }` | -Each closure receives a timestamp (Int, representing UNIX time) and must return a String representing the formatted time. +Each closure receives a timestamp (`Int`, representing UNIX time) and must return a `String` representing the formatted time. --- -#### Integration Options +### Integration Options The formatter can be applied at three levels: -1. **Global Level**: A global formatter is available via `CometChatUIKit.dateTimeFormatter`. Use this to apply formatting across all components in the `CometChatUIKit`. +#### 1. Global Level + +A global formatter is available via `CometChatUIKit.dateTimeFormatter`. Use this to apply formatting across all components in the `CometChatUIKit`. -```swift +```swift lines CometChatUIKit.dateTimeFormatter.hour = { timestamp in return "Today" } @@ -179,16 +195,16 @@ CometChatUIKit.dateTimeFormatter.time = { timestamp in return "12:00 PM" } ``` - - -2. **Component Global Level**: Each component has a static formatter that overrides the global formatter only for that component across all instances. +#### 2. Component Global Level + +Each component has a static formatter that overrides the global formatter only for that component across all instances. -```swift +```swift lines CometChatMessageList.dateTimeFormatter.hour = { timestamp in return "Today" } @@ -197,15 +213,16 @@ CometChatMessageList.dateTimeFormatter.time = { timestamp in return "12:00 PM" } ``` - -3. **Local Component Level**: Components also expose an instance-level formatter for per-instance customization. This provides the highest precedence. +#### 3. Local Component Level + +Components also expose an instance-level formatter for per-instance customization. This provides the highest precedence. -```swift +```swift lines let messageList = CometChatMessageList() messageList.set(user: user) @@ -217,19 +234,36 @@ messageList.dateTimeFormatter.time = { timestamp in return "12:00 PM" } ``` - +--- + ### Component-Level Date-Time Formatting Options -The following components support dateTimeFormatter: +The following components support `dateTimeFormatter`: + +- [CometChatConversations](/ui-kit/ios/conversations#date-time-formatter) +- [CometChatMessageList](/ui-kit/ios/message-list#date-time-formatter) +- [CometChatCallLogs](/ui-kit/ios/call-logs#date-time-formatter) +- [CometChatMessageHeader](/ui-kit/ios/message-header#date-time-formatter) -* [CometChatConversations](/ui-kit/ios/conversations#date-time-formatter) -* [CometChatMessageList](/ui-kit/ios/message-list#date-time-formatter) -* [CometChatCallLogs](/ui-kit/ios/call-logs#date-time-formatter) -* [CometChatMessageHeader](/ui-kit/ios/message-header#date-time-formatter) +Each of these components checks the most relevant closure in `CometChatDateTimeFormatter` based on the timestamp and context. -Each of these components checks the most relevant closure in CometChatDateTimeFormatter based on the timestamp and context. +The `CometChatDateTimeFormatter` gives developers fine-grained control over how date and time appear throughout their app. Whether you're customizing for locale, branding, or clarity, this system ensures your app's time formatting is as user-friendly and context-aware as possible. + +--- -The `CometChatDateTimeFormatter` gives developers fine-grained control over how date and time appear throughout their app. Whether you’re customizing for locale, branding, or clarity, this system ensures your app’s time formatting is as user-friendly and context-aware as possible. +## Next Steps + + + + Customize the visual appearance of UI components + + + Configure color schemes for your app + + + Apply custom styles to individual components + + diff --git a/ui-kit/ios/mentions-formatter-guide.mdx b/ui-kit/ios/mentions-formatter-guide.mdx index 8f623bdc7..e7bbe2056 100644 --- a/ui-kit/ios/mentions-formatter-guide.mdx +++ b/ui-kit/ios/mentions-formatter-guide.mdx @@ -1,18 +1,24 @@ --- title: "Mentions Formatter" +sidebarTitle: "Mentions Formatter" +description: "Format and customize @mentions within text messages using CometChat UI Kit for iOS" --- ## Overview -The `CometChatMentionsFormatter` class is a part of the CometChat UI Kit, a ready-to-use chat UI component library for integrating CometChat into your iOS applications. This class provides functionality to format mentions within text messages displayed in the chat interface. Mentions allow users to reference other users within a conversation, providing a convenient way to direct messages or involve specific participants. +The `CometChatMentionsFormatter` class is part of the CometChat UI Kit, a ready-to-use chat UI component library for integrating CometChat into your iOS applications. This class provides functionality to format mentions within text messages displayed in the chat interface. Mentions allow users to reference other users within a conversation, providing a convenient way to direct messages or involve specific participants. + +--- ## Features -* **Mention Formatting**: Automatically formats mentions within text messages based on provided styles and settings. -* **Customizable Styles**: Allows customization of text styles for mentions, including colors, fonts, and background colors. -* **User and Group Member Mentions**: Supports mentions for both individual users and group members, providing flexibility in communication scenarios. -* **Mention List Generation**: Generates a list of suggested mentions based on user input, facilitating easy selection of recipients during message composition. -* **Mention Click Handling**: Provides a listener interface for handling click events on mentions, enabling custom actions to be performed when a mention is tapped by the user. +- **Mention Formatting**: Automatically formats mentions within text messages based on provided styles and settings +- **Customizable Styles**: Allows customization of text styles for mentions, including colors, fonts, and background colors +- **User and Group Member Mentions**: Supports mentions for both individual users and group members, providing flexibility in communication scenarios +- **Mention List Generation**: Generates a list of suggested mentions based on user input, facilitating easy selection of recipients during message composition +- **Mention Click Handling**: Provides a listener interface for handling click events on mentions, enabling custom actions to be performed when a mention is tapped by the user + +--- ## Usage @@ -20,62 +26,72 @@ To integrate the `CometChatMentionsFormatter` class into your application: 1. **Initialization**: Create an instance of the `CometChatMentionsFormatter` class and configure it with desired settings, such as mention text styles and limit settings. -2. **Set Mention Listeners**: Set listeners for handling mention click events (`.setonMentionCLicked`). +2. **Set Mention Listeners**: Set listeners for handling mention click events (`.setOnMentionClicked`). 3. **Format Messages**: Use the `.set(leftBubbleTextStyle)`, `.set(rightBubbleTextStyle)`, `.set(composerTextStyle)`, and `.set(conversationListTextStyle)` methods to format text messages with mentions appropriately for display in the chat interface. 4. **Customization**: Customize the appearance and behavior of mentions by adjusting the text styles, colors, and other formatting properties as needed. -`CometChatMentionsFormatter` can directly be initialised, tweak using its properties and passed into different configurations. +`CometChatMentionsFormatter` can be directly initialized, tweaked using its properties, and passed into different configurations. -Below is an example demonstrating how to use the `CometChatMentionsFormatter` class in components such as [CometChatConversations](/ui-kit/ios/conversations), [CometChatMessageList](/ui-kit/ios/message-list), [CometChatMessageComposer](/ui-kit/ios/message-composer). +Below is an example demonstrating how to use the `CometChatMentionsFormatter` class in components such as [CometChatConversations](/ui-kit/ios/conversations), [CometChatMessageList](/ui-kit/ios/message-list), and [CometChatMessageComposer](/ui-kit/ios/message-composer). -```swift +```swift lines +// Create a custom mention formatter instance let customMentionFormatter = CometChatMentionsFormatter() +// Apply the formatter to a message list let messageListView = CometChatMessageList() messageListView.set(textFormatters: [customMentionFormatter]) ``` - - +--- + ## Actions [Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. -##### setOnMentionClick +### setOnMentionClick Setting a listener for mention-click events in Message Bubbles enhances interactivity within the chat. This listener is activated when a mention is clicked, returning the corresponding user object. This feature transforms mentions into interactive links, enabling more in-depth and contextual engagement with the user associated with the clicked mention. -**Example** - -```swift +```swift lines +// Set up mention click handler let customMentionFormatter = CometChatMentionsFormatter() customMentionFormatter.set { message, tappedText, controller in + // Display the name of the first mentioned user controller?.view.showToastMessage(message: "\(message.mentionedUsers.first?.name)") } ``` - - -The following code snippet represents a UIView extension used to display `showToastMessage`. +The following code snippet represents a UIView extension used to display `showToastMessage`: -```swift Swift + + +```swift lines extension UIView { - func showToastMessage(message : String) { - let toastLabel = UILabel(frame: CGRect(x: self.frame.size.width/2 - 100, y: self.frame.size.height-120, width: 200, height: 35)) + func showToastMessage(message: String) { + // Create toast label with centered positioning + let toastLabel = UILabel(frame: CGRect( + x: self.frame.size.width/2 - 100, + y: self.frame.size.height - 120, + width: 200, + height: 35 + )) + + // Configure toast appearance toastLabel.backgroundColor = UIColor.black toastLabel.textColor = UIColor.white toastLabel.textAlignment = .center @@ -83,35 +99,42 @@ extension UIView { toastLabel.alpha = 2.0 toastLabel.layer.cornerRadius = 13 toastLabel.clipsToBounds = true + self.addSubview(toastLabel) + + // Animate fade out and remove UIView.animate(withDuration: 4.0, delay: 0.4, options: .curveEaseOut, animations: { toastLabel.alpha = 0.0 - }, completion: {(isCompleted) in + }, completion: { isCompleted in toastLabel.removeFromSuperview() }) } } ``` + + + +--- ## Customization -| Methods | Description | Code | -| ----------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | -| **Set Conversation List TextStyle** | Use to set stying for conversation list's formatted text. | `MentionTextStyle` | -| **Set GroupMembersRequestBuilder** | Sets the builder for fetching group members. | `GroupMembersRequest.GroupMembersRequestBuilder?` | -| **Set UsersRequestBuilder** | Sets the builder for fetching users. | `UsersRequest.UsersRequestBuilder?` | -| **Set OnMentionCLick** | Sets a listener for mention click in Message Bubbles events. | `((_ baseMessage: BaseMessage, _ tappedText: String, _ controller: UIViewController?)->())` | -| **Set composerTextStyle** | Use to set stying for composer's formatted text. | `MentionTextStyle` | +| Method | Description | Type | +|--------|-------------|------| +| **Set Conversation List TextStyle** | Sets styling for conversation list's formatted text | `MentionTextStyle` | +| **Set GroupMembersRequestBuilder** | Sets the builder for fetching group members | `GroupMembersRequest.GroupMembersRequestBuilder?` | +| **Set UsersRequestBuilder** | Sets the builder for fetching users | `UsersRequest.UsersRequestBuilder?` | +| **Set OnMentionClick** | Sets a listener for mention click events in Message Bubbles | `((_ baseMessage: BaseMessage, _ tappedText: String, _ controller: UIViewController?)->())` | +| **Set composerTextStyle** | Sets styling for composer's formatted text | `MentionTextStyle` | -## Advance +--- -For advanced-level customization, you can set the style of the Mentions formatters. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your formatters style. +## Advanced -### Composer Mention Text Style +For advanced-level customization, you can set the style of the Mentions formatters. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your own formatter styles. -Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatMessageComposer](/ui-kit/ios/message-composer) refer to the below code snippet +### Composer Mention Text Style -**Example** +Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatMessageComposer](/ui-kit/ios/message-composer), refer to the code snippet below. @@ -119,22 +142,20 @@ Assigns the list of text formatters. If the provided list is not null, it sets t -```swift +```swift lines +// Create and configure composer mention style let composerMentionStyle = MentionTextStyle() composerMentionStyle.textColor = UIColor(hex: "#30A46C") - + +// Apply the style globally CometChatMentionsFormatter.composerTextStyle = composerMentionStyle ``` - - ### Message Bubble Mention Text Style -Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatMessageList](/ui-kit/ios/message-list) - -**Example** +Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatMessageList](/ui-kit/ios/message-list), refer to the code snippet below. @@ -142,27 +163,23 @@ Assigns the list of text formatters. If the provided list is not null, it sets t -```swift +```swift lines +// Configure left bubble (incoming) mention style var leftBubbleMentionsStyle = MentionTextStyle() leftBubbleMentionsStyle.textColor = UIColor(hex: "#D6409F") - CometChatMentionsFormatter.leftBubbleTextStyle = leftBubbleMentionsStyle - + +// Configure right bubble (outgoing) mention style var rightBubbleMentionsStyle = MentionTextStyle() rightBubbleMentionsStyle.textColor = UIColor(hex: "#30A46C") - CometChatMentionsFormatter.rightBubbleTextStyle = rightBubbleMentionsStyle ``` - - ### Conversations Mention Text Style -Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatConversations](/ui-kit/ios/conversations) - -**Example** +Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel for [CometChatConversations](/ui-kit/ios/conversations), refer to the code snippet below. @@ -170,13 +187,23 @@ Assigns the list of text formatters. If the provided list is not null, it sets t -```swift +```swift lines +// Create and configure conversation list mention style let mentionsStyle = MentionTextStyle() mentionsStyle.textColor = UIColor(hex: "#30A46C") - + +// Apply the style globally CometChatMentionsFormatter.conversationListTextStyle = mentionsStyle ``` - - + +--- + +## Next Steps + +- [Message Composer](/ui-kit/ios/message-composer) — Learn about the message input component +- [Message List](/ui-kit/ios/message-list) — Display and customize chat messages +- [Conversations](/ui-kit/ios/conversations) — Manage conversation lists + +--- diff --git a/ui-kit/ios/message-bubble-styling.mdx b/ui-kit/ios/message-bubble-styling.mdx index b4be2c467..3d7e0fa88 100644 --- a/ui-kit/ios/message-bubble-styling.mdx +++ b/ui-kit/ios/message-bubble-styling.mdx @@ -1,87 +1,110 @@ --- title: "Message Bubble Styling" +sidebarTitle: "Message Bubble Styling" +description: "Customize the appearance of incoming and outgoing message bubbles in CometChat UI Kit for iOS" --- + + +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Incoming Style | `CometChatMessageBubble.style.incoming` | +| Outgoing Style | `CometChatMessageBubble.style.outgoing` | +| Global Properties | `backgroundColor`, `borderWidth`, `borderColor`, `cornerRadius` | +| Bubble Types | `textBubbleStyle`, `imageBubbleStyle`, `videoBubbleStyle`, `audioBubbleStyle`, `fileBubbleStyle`, `pollBubbleStyle`, `linkPreviewBubbleStyle`, `deleteBubbleStyle`, `aiAssistantBubbleStyle` | +| Action Bubble | `CometChatMessageBubble.actionBubbleStyle` | + + + ## Overview The MessageBubble styling API allows developers to customize the appearance of incoming and outgoing message bubbles globally or at the component level. This includes various message types such as text, image, video, audio, file, and document bubbles. There are two primary classes for styling message bubbles: -* **CometChat Incoming Message Bubble Style** -* **CometChat Outgoing Message Bubble Style** +- **CometChat Incoming Message Bubble Style** +- **CometChat Outgoing Message Bubble Style** Both classes provide properties for customizing background color, border, corner radius, and specific styles for individual message types. -### Properties +--- -**Global Styling (Static Variables)** +## Properties -* **backgroundColor:** The background color for message bubbles. -* **backgroundDrawable:** A background image for message bubbles. -* **borderWidth:** The width of the border for message bubbles. -* **borderColor:** The color of the border for message bubbles. -* **cornerRadius:** The corner radius for message bubbles. +### Global Styling (Static Variables) -**Specific Message Type Styles:** +| Property | Description | +|----------|-------------| +| **backgroundColor** | The background color for message bubbles | +| **backgroundDrawable** | A background image for message bubbles | +| **borderWidth** | The width of the border for message bubbles | +| **borderColor** | The color of the border for message bubbles | +| **cornerRadius** | The corner radius for message bubbles | -* **textBubbleStyle:** Style for text message bubbles. -* **imageBubbleStyle:** Style for image message bubbles. -* **videoBubbleStyle:** Style for video message bubbles. -* **audioBubbleStyle:** Style for audio message bubbles. -* **fileBubbleStyle:** Style for file message bubbles. -* **documentBubbleStyle:** Style for document message bubbles. +### Specific Message Type Styles + +| Property | Description | +|----------|-------------| +| **textBubbleStyle** | Style for text message bubbles | +| **imageBubbleStyle** | Style for image message bubbles | +| **videoBubbleStyle** | Style for video message bubbles | +| **audioBubbleStyle** | Style for audio message bubbles | +| **fileBubbleStyle** | Style for file message bubbles | +| **documentBubbleStyle** | Style for document message bubbles | + +--- ## Customization Examples ### Customizing Incoming Message Bubble -The following code snippet shows how customize the incoming message bubble style: +The following code snippet shows how to customize the incoming message bubble style: -```swift +```swift lines +// Customize incoming message bubble appearance CometChatMessageBubble.style.incoming.backgroundColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.incoming.borderWidth = 2 CometChatMessageBubble.style.incoming.borderColor = UIColor.black ``` - - ### Customizing Outgoing Message Bubble -The following code snippet shows how customize the outgoing message bubble style: +The following code snippet shows how to customize the outgoing message bubble style: -```swift +```swift lines +// Customize outgoing message bubble appearance CometChatMessageBubble.style.outgoing.backgroundColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.outgoing.borderWidth = 2 CometChatMessageBubble.style.outgoing.borderColor = UIColor.black ``` - - +--- + ## Text Bubble Text bubbles display plain text messages, which are the most common message type. -The following code snippet shows how customize the text message bubble: +The following code snippet shows how to customize the text message bubble: -```swift +```swift lines +// Customize text bubble for incoming messages CometChatMessageBubble.style.incoming.textBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") +// Customize text bubble for outgoing messages CometChatMessageBubble.style.outgoing.textBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -96,22 +119,24 @@ CometChatMessageBubble.style.outgoing.textBubbleStyle.backgroundColor = UIColor( +--- + ## Image Bubble Image bubbles display messages with images. -The following code snippet shows how customize the Image message bubble: +The following code snippet shows how to customize the image message bubble: -```swift +```swift lines +// Customize image bubble for incoming messages CometChatMessageBubble.style.incoming.imageBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") +// Customize image bubble for outgoing messages CometChatMessageBubble.style.outgoing.imageBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -126,24 +151,26 @@ CometChatMessageBubble.style.outgoing.imageBubbleStyle.backgroundColor = UIColor +--- + ## Video Bubble Video bubbles display messages with video clips. -The following code snippet shows how customize the Video message bubble: +The following code snippet shows how to customize the video message bubble: -```swift +```swift lines +// Customize video bubble for incoming messages CometChatMessageBubble.style.incoming.videoBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") CometChatMessageBubble.style.incoming.videoBubbleStyle.playButtonTint = UIColor(hexString: "#F76808") - + +// Customize video bubble for outgoing messages CometChatMessageBubble.style.outgoing.deleteBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.outgoing.videoBubbleStyle.playButtonTint = UIColor(hexString: "#F76808") ``` - - **Default** @@ -158,25 +185,27 @@ CometChatMessageBubble.style.outgoing.videoBubbleStyle.playButtonTint = UIColor( +--- + ## Audio Bubble -Audio bubbles display Audio messages. +Audio bubbles display audio messages. -The following code snippet shows how customize the Audio message bubble: +The following code snippet shows how to customize the audio message bubble: -```swift +```swift lines +// Customize audio bubble for incoming messages CometChatMessageBubble.style.incoming.audioBubbleStyle.audioWaveFormTintColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.incoming.audioBubbleStyle.playImageTintColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.incoming.audioBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") +// Customize audio bubble for outgoing messages CometChatMessageBubble.style.outgoing.audioBubbleStyle.playImageTintColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.outgoing.audioBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -191,24 +220,26 @@ CometChatMessageBubble.style.outgoing.audioBubbleStyle.backgroundColor = UIColor +--- + ## Poll Bubble -Poll bubbles display messages with polling. +Poll bubbles display messages with polling options. -The following code snippet shows how customize the Poll message bubble: +The following code snippet shows how to customize the poll message bubble: -```swift +```swift lines +// Customize poll bubble for incoming messages CometChatMessageBubble.style.incoming.pollBubbleStyle.optionProgressTintColor = UIColor(hexString: "#F76808") CometChatMessageBubble.style.incoming.pollBubbleStyle.selectedPollImageTint = UIColor(hexString: "#F76808") CometChatMessageBubble.style.incoming.pollBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") - + +// Customize poll bubble for outgoing messages CometChatMessageBubble.style.outgoing.pollBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -223,22 +254,24 @@ CometChatMessageBubble.style.outgoing.pollBubbleStyle.backgroundColor = UIColor( +--- + ## Link Preview Bubble -The Link Preview Bubble is designed to display a preview of links shared in messages. It enriches the messaging experience by showing details such as the page title, description, and an image from the linked content, making links more engaging and informative. +The Link Preview Bubble displays a preview of links shared in messages. It enriches the messaging experience by showing details such as the page title, description, and an image from the linked content, making links more engaging and informative. -The following code snippet shows how customize the Link preview message bubble: +The following code snippet shows how to customize the link preview message bubble: -```swift +```swift lines +// Customize link preview bubble for incoming messages CometChatMessageBubble.style.incoming.linkPreviewBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") - + +// Customize link preview bubble for outgoing messages CometChatMessageBubble.style.outgoing.linkPreviewBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -253,22 +286,23 @@ CometChatMessageBubble.style.outgoing.linkPreviewBubbleStyle.backgroundColor = U +--- + ## Action Bubble Action bubbles provide a customizable interface for displaying a variety of actions, such as group actions, within a chat. -The following code snippet shows how customize the action message bubble: +The following code snippet shows how to customize the action message bubble: -```swift +```swift lines +// Customize action bubble appearance CometChatMessageBubble.actionBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") CometChatMessageBubble.actionBubbleStyle.bubbleTextColor = UIColor(hexString: "#F76808") CometChatMessageBubble.actionBubbleStyle.borderColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -283,22 +317,24 @@ CometChatMessageBubble.actionBubbleStyle.borderColor = UIColor(hexString: "#F768 +--- + ## Delete Bubble -Delete bubbles displays messages that have been deleted by the sender. These indicate the message removal within the chat interface. +Delete bubbles display messages that have been deleted by the sender. These indicate the message removal within the chat interface. -The following code snippet shows how customize the delete message bubble: +The following code snippet shows how to customize the delete message bubble: -```swift +```swift lines +// Customize delete bubble for incoming messages CometChatMessageBubble.style.incoming.deleteBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") +// Customize delete bubble for outgoing messages CometChatMessageBubble.style.outgoing.deleteBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - **Default** @@ -313,28 +349,29 @@ CometChatMessageBubble.style.outgoing.deleteBubbleStyle.backgroundColor = UIColo +--- -## AIAssistantBubble +## AI Assistant Bubble The AI Assistant Bubble displays responses or messages sent by the AI assistant within the chat interface. These bubbles are designed to visually distinguish AI-generated messages from user messages, maintaining a clear and intuitive conversation flow. -You can customize the appearance of the AI Assistant message bubble to match your app’s theme — including background color, text color, font, and border styling. +You can customize the appearance of the AI Assistant message bubble to match your app's theme — including background color, text color, font, and border styling. The following code snippet shows how to customize the AI Assistant message bubble: -```swift +```swift lines +// Customize AI assistant bubble for incoming messages CometChatMessageBubble.style.incoming.aiAssistantBubbleStyle.backgroundColor = UIColor(hexString: "#FEEDE1") +// Customize AI assistant bubble for outgoing messages CometChatMessageBubble.style.outgoing.aiAssistantBubbleStyle.backgroundColor = UIColor(hexString: "#F76808") ``` - - -**Default** +{/* **Default** @@ -344,4 +381,20 @@ CometChatMessageBubble.style.outgoing.aiAssistantBubbleStyle.backgroundColor = U - + */} + +--- + +## Next Steps + + + + Display and customize the message list component + + + Customize the message input component + + + Learn about global styling options + + diff --git a/ui-kit/ios/message-composer.mdx b/ui-kit/ios/message-composer.mdx index c49a79373..524bd6220 100644 --- a/ui-kit/ios/message-composer.mdx +++ b/ui-kit/ios/message-composer.mdx @@ -1,661 +1,547 @@ --- title: "Message Composer" +description: "Enable users to write and send text, media, and custom messages" --- -## Overview + +```json +{ + "component": "CometChatMessageComposer", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "inherits": "UIView", + "description": "Rich text input for composing and sending text, media, attachments, mentions, voice notes, and custom messages.", + "props": { + "data": { + "user": "User? - recipient user for direct messaging", + "group": "Group? - recipient group for group messaging", + "parentMessageId": "Int? - parent message ID for thread replies" + }, + "callbacks": { + "onSendButtonClick": "(BaseMessage) -> Void", + "onTextChangedListener": "(String) -> Void", + "onError": "(CometChatException) -> Void" + }, + "visibility": { + "hideAttachmentButton": "Bool (default: false)", + "hideVoiceRecordingButton": "Bool (default: false)", + "hideStickersButton": "Bool (default: false)", + "hideSendButton": "Bool (default: false)", + "hideAIButton": "Bool (default: false)", + "hideHeaderView": "Bool (default: false)", + "hideFooterView": "Bool (default: false)" + }, + "behavior": { + "disableTypingEvents": "Bool (default: false)", + "disableMentions": "Bool (default: false)", + "placeholderText": "String (default: 'Type a message...')" + }, + "viewSlots": { + "headerView": "(User?, Group?) -> UIView", + "footerView": "(User?, Group?) -> UIView", + "sendButtonView": "(User?, Group?) -> UIView", + "auxillaryButtonView": "(User?, Group?) -> UIView", + "attachmentOptions": "(User?, Group?, UIViewController?) -> [CometChatMessageComposerAction]" + } + }, + "methods": { + "set(user:)": "Sets recipient user", + "set(group:)": "Sets recipient group", + "set(parentMessageId:)": "Sets parent message for threads", + "setInitialComposerText(_:)": "Pre-fills composer text", + "set(textFormatter:)": "Sets custom text formatter", + "setDisableMentionAll(_:)": "Disables @all mentions", + "setMentionAllLabel(_:_:)": "Customizes @all label" + }, + "styling": { + "globalStyle": "CometChatMessageComposer.style", + "instanceStyle": "MessageComposerStyle", + "subStyles": ["MediaRecorderStyle", "AttachmentSheetStyle", "SuggestionsStyle", "AIOptionsStyle", "MentionStyle"] + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatMessageComposer` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIView` | -MessageComposer is a [Component](/ui-kit/ios/components-overview#components) that enables users to write and send a variety of messages, including text, image, video, and custom messages. +The `CometChatMessageComposer` component enables users to write and send messages including text, images, videos, audio, files, and custom messages. It supports attachments, voice recording, stickers, mentions, and AI-powered features. -MessageComposer is comprised of the following [Base Components](/ui-kit/ios/components-overview#base-components): - -| Base Components | Description | -| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| [MessageInput](/ui-kit/ios/message-input) | This provides a basic layout for the contents of this component, such as the TextField and buttons | -| [ActionSheet](/ui-kit/ios/action-sheet) | The ActionSheet component presents a list of options in either a list or grid mode, depending on the user's preference | - -## Usage +--- -### Integration +## Where It Fits -The following code snippet illustrates how you can directly incorporate the MessageComposer component into your file. +`CometChatMessageComposer` provides a rich text input with attachment, emoji, voice recording, sticker, and send controls. Wire it alongside `CometChatMessageHeader` and `CometChatMessageList` to build a standard chat view. -```csharp -// syntax for set(user: User) -let messageComposer = CometChatMessageComposer() -messageComposer.set(user: user) -messageComposer.set(parentMessageId: 20) +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + CometChat.getUser(UID: "uid") { user in + DispatchQueue.main.async { + let header = CometChatMessageHeader() + header.set(user: user) + + let messageList = CometChatMessageList() + messageList.set(user: user) + + let composer = CometChatMessageComposer() + composer.set(user: user) + + // Add to view hierarchy and layout + } + } onError: { error in + print("Error: \(error?.errorDescription ?? "")") + } + } +} ``` -### Actions + + + -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. +--- -##### 1. onSendButtonClick +## Minimal Render -The `set(onSendButtonClick:)` event gets activated when the send message button is clicked. The following code snippet Overrides the action of the send button in CometChatMessageComposer. +```swift lines +import CometChatUIKitSwift - - -```swift -messageComposer.set(onSendButtonClick: { message in -// return custom action here -}) +let composer = CometChatMessageComposer() +composer.set(user: user) ``` - - - - -*** - -##### 2. OnTextChanged: + + + -The `set(onTextChanged:)` event gets activated when the user starts typing in message composer. This will return the text entered by the user. +--- - - -```swift -messageComposer.set(onTextChanged: { error in - // Handle action -}) -``` +## Actions and Events - +### Callback Props - +#### onSendButtonClick -*** +Fires when the send button is clicked. Overrides the default send behavior. -##### 3. SetOnError +```swift lines +import CometChatUIKitSwift -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatMessageComposer. +let composer = CometChatMessageComposer() +composer.set(user: user) - - -```swift -messageComposer.set(onError { error in - // Override on error +composer.set(onSendButtonClick: { message in + print("Custom send: \(message.id)") }) ``` - - - - -*** +#### onTextChangedListener -### Filters +Fires as the user types in the composer input. -MessageComposer component does not have any available filters. +```swift lines +import CometChatUIKitSwift -*** +let composer = CometChatMessageComposer() +composer.set(user: user) -### Events - -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. - -The MessageComposer Component does not emit any events of its own. - -*** - -## Customization - -To fit your app's design requirements, you can customize the appearance of the MessageComposer component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. - -### Style - -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. - -##### 1. MessageComposer Style - -To customize the styling, you can apply the `MessageComposerStyle` to the `MessageComposer` component. - -**Global level styling** - - - -```swift -CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = UIColor(hex: "#F76808") -CometChatMessageComposer.style.attachmentImageTint = UIColor(hex: "#F76808") -CometChatMessageComposer.style.voiceRecordingImageTint = UIColor(hex: "#F76808") -CometChatMessageComposer.style.stickerTint = UIColor(hex: "#F76808") -CometChatMessageComposer.style.aiImageTint = UIColor(hex: "#F76808") +composer.set(onTextChangedListener: { text in + print("Text changed: \(text)") +}) ``` - +#### onError - +Fires on internal errors. -**Instance level styling** - - - -```swift -let customComposerStyle = MessageComposerStyle() -customComposerStyle.activeSendButtonImageBackgroundColor = UIColor(hex: "#F76808") -customComposerStyle.attachmentImageTint = UIColor(hex: "#F76808") -customComposerStyle.voiceRecordingImageTint = UIColor(hex: "#F76808") -customComposerStyle.stickerTint = UIColor(hex: "#F76808") -customComposerStyle.aiImageTint = UIColor(hex: "#F76808") - -let messageComposer = CometChatMessageComposer() -messageComposer.style = customComposerStyle -``` +```swift lines +import CometChatUIKitSwift - +let composer = CometChatMessageComposer() +composer.set(user: user) - - - - - - -The following properties are exposed by MessageComposerStyle: - -| **Property** | **Description** | **Code** | -| ----------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| **Placeholder Text Font** | Font for the placeholder text in the input field. | `CometChatMessageComposer.style.placeHolderTextFont = CometChatTypography.Body.regular` | -| **Placeholder Text Color** | Color for the placeholder text in the input field. | `CometChatMessageComposer.style.placeHolderTextColor = CometChatTheme.textColorTertiary` | -| **Text Field Color** | Text color for the input field. | `CometChatMessageComposer.style.textFiledColor = CometChatTheme.textColorPrimary` | -| **Text Field Font** | Font for the input field text. | `CometChatMessageComposer.style.textFiledFont = CometChatTypography.Body.regular` | -| **Background Color** | Background color with dynamic support for light and dark mode. | `CometChatMessageComposer.style.backgroundColor = UIColor.dynamicColor(lightModeColor: ..., darkModeColor: ...)` | -| **Corner Radius** | Corner radius for the composer. | `CometChatMessageComposer.style.cornerRadius = CometChatCornerStyle?` | -| **Border Width** | Border width for the composer. | `CometChatMessageComposer.style.borderWidth = 0` | -| **Border Color** | Border color for the composer. | `CometChatMessageComposer.style.borderColor = .clear` | -| **Send Button Image** | Icon for the send button. | `CometChatMessageComposer.style.sendButtonImage = UIImage(named: "custom-send")` | -| **Send Button Tint Color** | Tint color for the send button image. | `CometChatMessageComposer.style.sendButtonImageTint = CometChatTheme.white` | -| **Active Send Button Background Color** | Background color for the send button when active. | `CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = CometChatTheme.primaryColor` | -| **Inactive Send Button Background Color** | Background color for the send button when inactive. | `CometChatMessageComposer.style.inactiveSendButtonImageBackgroundColor = CometChatTheme.neutralColor300` | -| **Compose Box Background Color** | Background color for the compose box. | `CometChatMessageComposer.style.composeBoxBackgroundColor = CometChatTheme.backgroundColor01` | -| **Compose Box Border Color** | Border color for the compose box. | `CometChatMessageComposer.style.composeBoxBorderColor = CometChatTheme.borderColorDefault` | -| **Compose Box Border Width** | Border width for the compose box. | `CometChatMessageComposer.style.composeBoxBorderWidth = 1` | -| **Compose Box Corner Radius** | Corner radius for the compose box. | `CometChatMessageComposer.style.composerBoxCornerRadius = .init(cornerRadius: CometChatSpacing.Radius.r2)` | -| **Compose Box Separator Color** | Color for the separator in the compose box. | `CometChatMessageComposer.style.composerSeparatorColor = CometChatTheme.borderColorLight` | -| **Attachment Image** | Icon for the attachment button. | `CometChatMessageComposer.style.attachmentImage = UIImage(systemName: "plus.circle")` | -| **Attachment Image Tint** | Tint color for the attachment image. | `CometChatMessageComposer.style.attachmentImageTint = CometChatTheme.iconColorSecondary` | -| **Voice Recording Image** | Icon for the voice recording button. | `CometChatMessageComposer.style.voiceRecordingImage = UIImage(systemName: "mic")?.withRenderingMode(.alwaysTemplate)` | -| **Voice Recording Image Tint** | Tint color for the voice recording image. | `CometChatMessageComposer.style.voiceRecordingImageTint = CometChatTheme.iconColorSecondary` | -| **AI Image** | Icon for the AI button. | `CometChatMessageComposer.style.aiImage = UIImage(named: "ai-image")` | -| **AI Image Tint** | Tint color for the AI image. | `CometChatMessageComposer.style.aiImageTint = CometChatTheme.iconColorSecondary` | -| **Sticker Image** | Icon for the sticker button. | `CometChatMessageComposer.style.stickerImage = UIImage(named: "sticker-image")` | -| **Sticker Image Tint** | Tint color for the sticker image. | `CometChatMessageComposer.style.stickerTint = CometChatTheme.iconColorSecondary` | -| **Edit Preview Title Font** | Font for the title in the edit preview. | `CometChatMessageComposer.style.editPreviewTitleTextFont = CometChatTypography.Body.regular` | -| **Edit Preview Message Font** | Font for the message text in the edit preview. | `CometChatMessageComposer.style.editPreviewMessageTextFont = CometChatTypography.Caption1.regular` | -| **Edit Preview Title Color** | Text color for the title in the edit preview. | `CometChatMessageComposer.style.editPreviewTitleTextColor = CometChatTheme.textColorPrimary` | -| **Edit Preview Message Color** | Text color for the message in the edit preview. | `CometChatMessageComposer.style.editPreviewMessageTextColor = CometChatTheme.textColorSecondary` | -| **Edit Preview Background Color** | Background color for the edit preview. | `CometChatMessageComposer.style.editPreviewBackgroundColor = CometChatTheme.backgroundColor03` | -| **Edit Preview Corner Radius** | Corner radius for the edit preview. | `CometChatMessageComposer.style.editPreviewCornerRadius = .init(cornerRadius: CometChatSpacing.Radius.r1)` | -| **Edit Preview Border Color** | Border color for the edit preview. | `CometChatMessageComposer.style.editPreviewBorderColor = .clear` | -| **Edit Preview Border Width** | Border width for the edit preview. | `CometChatMessageComposer.style.editPreviewBorderWidth = 0` | -| **Edit Preview Close Icon** | Icon for closing the edit preview. | `CometChatMessageComposer.style.editPreviewCloseIcon = UIImage(systemName: "xmark")?.withRenderingMode(.alwaysTemplate)` | -| **Edit Preview Close Icon Tint** | Tint color for the close icon in the edit preview. | `CometChatMessageComposer.style.editPreviewCloseIconTint = CometChatTheme.iconColorPrimary` | -| **Info Icon** | Icon for the info button. | `CometChatMessageComposer.style.infoIcon = UIImage(systemName: "info.circle")` | -| **Info Icon Tint** | Tint color for the info icon. | `CometChatMessageComposer.style.infoIconTint = CometChatTheme.errorColor` | -| **Info Text Color** | Text color for the info text. | `CometChatMessageComposer.style.infoTextColor = CometChatTheme.errorColor` | -| **Info Text Font** | Font for the info text. | `CometChatMessageComposer.style.infoTextFont = CometChatTypography.Caption1.regular` | -| **Info Separator Color** | Color for the separator in the info section. | `CometChatMessageComposer.style.infoSeparatorColor = CometChatTheme.borderColorLight` | -| **Info Background Color** | Background color for the info section. | `CometChatMessageComposer.style.infoBackgroundColor = CometChatTheme.backgroundColor02` | -| **Info Corner Radius** | Corner radius for the info section. | `CometChatMessageComposer.style.infoCornerRadius = .init(cornerRadius: CometChatSpacing.Radius.r1)` | -| **Info Border Color** | Border color for the info section. | `CometChatMessageComposer.style.infoBorderColor = .clear` | -| **Info Border Width** | Border width for the info section. | `CometChatMessageComposer.style.infoBorderWidth = 0` | - -##### 2. MediaRecorder Style - -To customize the media recording styling, you can apply the `MediaRecorderStyle` to the `MessageComposer` component. For more details, please refer to [MediaRecorder](/ui-kit/ios/component-styling#media-recorder) styles. - -**Global level styling** - - - -```swift -CometChatMessageComposer.mediaRecorderStyle.deleteButtonCornerRadius = .init(cornerRadius: 8) -CometChatMessageComposer.mediaRecorderStyle.pauseButtonCornerRadius = .init(cornerRadius: 8) -CometChatMessageComposer.mediaRecorderStyle.stopButtonCornerRadius = .init(cornerRadius: 8) -CometChatMessageComposer.mediaRecorderStyle.recordingButtonCornerRadius = .init(cornerRadius: 8) -CometChatMessageComposer.mediaRecorderStyle.recordingButtonBackgroundColor = UIColor(hex: "#F44649") +composer.set(onError: { error in + print("Composer error: \(error.errorDescription)") +}) ``` - +### SDK Events (Real-Time, Automatic) - +The component internally handles typing indicators and message sending. No manual SDK listener attachment needed. -**Instance level styling** +--- - - -```swift -var mediaRecorderStyle = MediaRecorderStyle() -mediaRecorderStyle.deleteButtonCornerRadius = .init(cornerRadius: 8) -mediaRecorderStyle.pauseButtonCornerRadius = .init(cornerRadius: 8) -mediaRecorderStyle.stopButtonCornerRadius = .init(cornerRadius: 8) -mediaRecorderStyle.recordingButtonCornerRadius = .init(cornerRadius: 8) -mediaRecorderStyle.recordingButtonBackgroundColor = UIColor(hex: "#F44649") +## Custom View Slots -let messageComposer = CometChatMessageComposer() -messageComposer.mediaRecorderStyle = mediaRecorderStyle -``` +| Slot | Signature | Replaces | +|------|-----------|----------| +| `headerView` | `(User?, Group?) -> UIView` | Area above the composer input | +| `footerView` | `(User?, Group?) -> UIView` | Area below the composer input | +| `sendButtonView` | `(User?, Group?) -> UIView` | Send button | +| `auxillaryButtonView` | `(User?, Group?) -> UIView` | Sticker and AI button area | +| `attachmentOptions` | `(User?, Group?, UIViewController?) -> [CometChatMessageComposerAction]` | Default attachment options list | - +### headerView - +Custom view above the composer input. - + -The following properties are exposed by Media Recorder Style: - -| **Property** | **Description** | **Code** | -| ---------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| **backgroundColor** | Sets the background color of the media recorder. | `mediaRecorderStyle.backgroundColor: UIColor = CometChatTheme.backgroundColor01` | -| **borderWidth** | Defines the width of the border for the media recorder. | `mediaRecorderStyle.borderWidth: CGFloat = 1` | -| **borderColor** | Specifies the border color of the media recorder. | `mediaRecorderStyle.borderColor: UIColor = CometChatTheme.borderColorLight` | -| **cornerRadius** | Configures the corner radius of the media recorder. | `mediaRecorderStyle.cornerRadius: CometChatCornerStyle? = nil` | -| **recordingButtonBackgroundColor** | Sets the background color of the recording button. | `mediaRecorderStyle.recordingButtonBackgroundColor: UIColor = CometChatTheme.iconColorHighlight` | -| **recordingButtonCornerRadius** | Configures the corner radius of the recording button. | `mediaRecorderStyle.recordingButtonCornerRadius: CometChatCornerStyle? = nil` | -| **recordingButtonBorderWidth** | Sets the border width of the recording button. | `mediaRecorderStyle.recordingButtonBorderWidth: CGFloat = 0` | -| **recordingButtonBorderColor** | Sets the border color of the recording button. | `mediaRecorderStyle.recordingButtonBorderColor: UIColor = .clear` | -| **recordingButtonImageTintColor** | Specifies the tint color of the recording button image. | `mediaRecorderStyle.recordingButtonImageTintColor: UIColor = CometChatTheme.white` | -| **recordingButtonImage** | The image displayed on the recording button. | `mediaRecorderStyle.recordingButtonImage: UIImage = UIImage(systemName: "mic.fill") ?? UIImage()` | -| **deleteButtonBackgroundColor** | Sets the background color of the delete button. | `mediaRecorderStyle.deleteButtonBackgroundColor: UIColor = CometChatTheme.backgroundColor01` | -| **deleteButtonImageTintColor** | Specifies the tint color of the delete button image. | `mediaRecorderStyle.deleteButtonImageTintColor: UIColor = CometChatTheme.iconColorSecondary` | -| **deleteButtonImage** | The image displayed on the delete button. | `mediaRecorderStyle.deleteButtonImage: UIImage = UIImage(systemName: "trash.fill") ?? UIImage()` | -| **deleteButtonCornerRadius** | Configures the corner radius of the delete button. | `mediaRecorderStyle.deleteButtonCornerRadius: CometChatCornerStyle? = nil` | -| **deleteButtonBorderWidth** | Sets the border width of the delete button. | `mediaRecorderStyle.deleteButtonBorderWidth: CGFloat = 1` | -| **deleteButtonBorderColor** | Specifies the border color of the delete button. | `mediaRecorderStyle.deleteButtonBorderColor: UIColor = CometChatTheme.borderColorLight` | - -##### 3. AI Options Style - -To customize the media recording styling, you can apply the `AIOptionsStyle` to the `MessageComposer` component. For more details, please refer to [MediaRecorder](/ui-kit/ios/component-styling#media-recorder) styles. - -**Global level styling** - - - -```swift -CometChatMessageComposer.aiOptionsStyle.backgroundColor = UIColor(hex: "#FFF9F5") -CometChatMessageComposer.aiOptionsStyle.textColor = .black -CometChatMessageComposer.aiOptionsStyle.aiImageTintColor = UIColor(hex: "#F76808") -``` - - - - - -**Instance level styling** - - - -```swift -var aIOptionsStyle = AIOptionsStyle() -aIOptionsStyle.backgroundColor = UIColor(hex: "#FFF9F5") -aIOptionsStyle.textColor = .black -aIOptionsStyle.aiImageTintColor = UIColor(hex: "#F76808") - -let messageComposer = CometChatMessageComposer() -messageComposer.aiOptionsStyle = aIOptionsStyle +```swift lines +import UIKit +import CometChatUIKitSwift + +let composer = CometChatMessageComposer() +composer.set(user: user) + +composer.set(headerView: { user, group in + let view = UIView() + view.backgroundColor = UIColor.purple.withAlphaComponent(0.1) + + let label = UILabel() + label.text = "User has paused their notifications" + label.font = UIFont.systemFont(ofSize: 14) + view.addSubview(label) + + return view +}) ``` - +### footerView - +Custom view below the composer input. - - - - -The following properties are exposed by AI Options Style: - -| **Property** | **Description** | **Code** | -| ---------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------ | -| **errorViewTextFont** | Specifies the font used for the text in the error view. | `aIOptionsStyle.errorViewTextFont: UIFont?` | -| **errorViewTextColor** | Sets the color of the text in the error view. | `aIOptionsStyle.errorViewTextColor: UIColor?` | -| **emptyViewTextFont** | Specifies the font used for the text in the empty view. | `aIOptionsStyle.emptyViewTextFont: UIFont?` | -| **emptyViewTextColor** | Sets the color of the text in the empty view. | `aIOptionsStyle.emptyViewTextColor: UIColor?` | -| **aiImageTintColor** | Configures the tint color for AI-related images. | `aIOptionsStyle.aiImageTintColor: UIColor = CometChatTheme.iconColorHighlight` | -| **textColor** | Sets the color of the text. | `aIOptionsStyle.textColor: UIColor = CometChatTheme.textColorPrimary` | -| **textFont** | Specifies the font for the text. | `aIOptionsStyle.textFont: UIFont = CometChatTypography.Heading4.regular` | -| **backgroundColor** | Sets the background color. | `aIOptionsStyle.backgroundColor: UIColor = CometChatTheme.backgroundColor01` | -| **borderWidth** | Sets the width of the border. | `aIOptionsStyle.borderWidth: CGFloat = 0` | -| **borderColor** | Sets the color of the border. | `aIOptionsStyle.borderColor: UIColor = .clear` | -| **cornerRadius** | Configures the corner radius of the view. | `aIOptionsStyle.cornerRadius: CometChatCornerStyle? = nil` | - -*** - -### Functionality - -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can set maximum lines text area will show before scrolling in the composer, edit a message, add header view and footer view to the composer, etc. - -Below is a list of customizations along with corresponding code snippets message composer offers - -| Property | Description | Code | -| --------------------------------- | -------------------------------------------------------- | ------------------------------------------ | -| setInitialComposerText | Sets the initial text in the composer when it loads. | `setInitialComposerText("Hello")` | -| disableTypingEvents | Disables sending typing indicators when the user types. | `disableTypingEvents = true` | -| disableMentions | Disables the mention feature in the composer. | `disableMentions = true` | -| hideImageAttachmentOption | Hides the option to attach images. | `hideImageAttachmentOption = true` | -| hideVideoAttachmentOption | Hides the option to attach videos. | `hideVideoAttachmentOption = true` | -| hideAudioAttachmentOption | Hides the option to attach audio files. | `hideAudioAttachmentOption = true` | -| hideFileAttachmentOption | Hides the option to attach files. | `hideFileAttachmentOption = true` | -| hidePollsOption | Hides the option to create polls. | `hidePollsOption = true` | -| hideCollaborativeDocumentOption | Hides the option for collaborative documents. | `hideCollaborativeDocumentOption = true` | -| hideCollaborativeWhiteboardOption | Hides the option for collaborative whiteboards. | `hideCollaborativeWhiteboardOption = true` | -| hideAttachmentButton | Hides the attachment button in the composer. | `hideAttachmentButton = true` | -| hideVoiceRecordingButton | Hides the voice recording button. | `hideVoiceRecordingButton = true` | -| hideStickersButton | Hides the stickers button. | `hideStickersButton = true` | -| hideSendButton | Hides the send button. | `hideSendButton = true` | -| setUser | Sets the user for direct messaging. | `set(user: User)` | -| setGroup | Sets the group for group messaging. | `set(group: Group)` | -| setParentMessageId | Sets the parent message ID for replying in a thread. | `set(parentMessageId: 12345)` | -| setMaxLine | Sets the maximum number of lines for the composer input. | `set(maxLine: 3)` | -| setCustomSoundForMessages | Sets a custom sound for sending messages. | `set(customSoundForMessages: URL?)` | -| disableSoundForMessages | Disables sound while sending messages. | `disableSoundForMessages = true` | - -*** - -### Advanced - -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. - -#### AttachmentOptions - -By using `set(attachmentOptions:)`, you can set a list of custom `MessageComposerActions` for the MessageComposer Component. This will override the existing list of `CometChatMessageComposerAction`. - - - -```swift -let messageComposer = CometChatMessageComposer() -messageComposer.set(attachmentOptions: { user, group, controller in - return [CometChatMessageComposerAction] +```swift lines +import UIKit +import CometChatUIKitSwift + +let composer = CometChatMessageComposer() +composer.set(user: user) + +composer.set(footerView: { user, group in + let view = UIView() + + let label = UILabel() + label.text = "Messages are end-to-end encrypted" + label.font = UIFont.systemFont(ofSize: 12) + label.textColor = .secondaryLabel + view.addSubview(label) + + return view }) ``` - +### sendButtonView - +Replace the send button. -**Demonstration** +```swift lines +import UIKit +import CometChatUIKitSwift - - - +let composer = CometChatMessageComposer() +composer.set(user: user) -In this example, we are overriding the existing MessageComposerActions List with Capture Photo actions. - - - -```swift -let messageComposer = CometChatMessageComposer() -messageComposer.setAttachmentOptions { user, group, controller in - let customComposerAction1 = CometChatMessageComposerAction( - id: "customAction1", - text: "Custom Option 1", - startIcon: UIImage(systemName: "play_circle"), - startIconTint: .black, - textColor: .black, - onActionClick: { - print("Custom Action 1 clicked!") - } - ) - let customComposerAction2 = CometChatMessageComposerAction( - id: "customAction2", - text: "Custom Option 2", - startIcon: UIImage(systemName: "add_box"), - startIconTint: .black, - textColor: .black, - onActionClick: { - print("Custom Action 2 clicked!") - } - ) - let customComposerAction3 = CometChatMessageComposerAction( - id: "customAction3", - text: "Custom Option 3", - startIcon: UIImage(systemName: "change_circle"), - startIconTint: .black, - textColor: .black, - onActionClick: { - print("Custom Action 3 clicked!") - } - ) - let customComposerAction4 = CometChatMessageComposerAction( - id: "customAction4", - text: "Custom Option 4", - startIcon: UIImage(systemName: "sunny"), - startIconTint: .black, - textColor: .black, - onActionClick: { - print("Custom Action 4 clicked!") - } - ) - - return [customComposerAction1 , customComposerAction2, customComposerAction3, customComposerAction4] -} +composer.set(sendButtonView: { user, group in + let button = UIButton(type: .system) + button.setImage(UIImage(systemName: "paperplane.fill"), for: .normal) + button.tintColor = .systemBlue + return button +}) ``` - +### auxillaryButtonView - +Replace the sticker and AI button area. -*** +```swift lines +import UIKit +import CometChatUIKitSwift + +let composer = CometChatMessageComposer() +composer.set(user: user) + +composer.set(auxillaryButtonView: { user, group in + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 8 + + let aiButton = UIButton(type: .system) + aiButton.setImage(UIImage(systemName: "sparkles"), for: .normal) + + let emojiButton = UIButton(type: .system) + emojiButton.setImage(UIImage(systemName: "face.smiling"), for: .normal) + + stackView.addArrangedSubview(aiButton) + stackView.addArrangedSubview(emojiButton) + + return stackView +}) +``` -#### SendButtonView +### attachmentOptions -By using `set(sendButtonView:)`, you can set a custom send button for the MessageComposer Component. +Override the default attachment options. - - -```swift -let messageComposer = CustomSendButton() -messageComposer.set(sendButtonView: { user, group in - let view = CustomSendButton() - return view +```swift lines +import UIKit +import CometChatUIKitSwift + +let composer = CometChatMessageComposer() +composer.set(user: user) + +composer.set(attachmentOptions: { user, group, controller in + return [ + CometChatMessageComposerAction( + id: "photo", + text: "Photo", + startIcon: UIImage(systemName: "photo"), + startIconTint: .systemBlue, + onActionClick: { print("Photo selected") } + ), + CometChatMessageComposerAction( + id: "camera", + text: "Camera", + startIcon: UIImage(systemName: "camera"), + startIconTint: .systemGreen, + onActionClick: { print("Camera selected") } + ), + CometChatMessageComposerAction( + id: "location", + text: "Location", + startIcon: UIImage(systemName: "location"), + startIconTint: .systemRed, + onActionClick: { print("Location selected") } + ) + ] }) ``` - - - +--- -**Demonstration** +## Common Patterns - - - +### Thread composer - - -```swift -import UIKit +```swift lines +let composer = CometChatMessageComposer() +composer.set(user: user) +composer.set(parentMessageId: parentMessage.id) +``` -class CustomSendButton: UIView { +### Minimal composer — text only - private let playButton: UIButton = { - let button = UIButton(type: .system) - let playImage = UIImage(systemName: "play.fill")?.withRenderingMode(.alwaysTemplate) - button.setImage(playImage, for: .normal) - button.tintColor = .purple - button.backgroundColor = .clear - button.addTarget(self, action: #selector(playButtonTapped), for: .touchUpInside) - return button - }() +```swift lines +let composer = CometChatMessageComposer() +composer.set(user: user) +composer.hideAttachmentButton = true +composer.hideVoiceRecordingButton = true +composer.hideStickersButton = true +composer.hideAIButton = true +``` - var onPlayTapped: (() -> Void)? // Closure to handle button tap +### Pre-filled text - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } +```swift lines +let composer = CometChatMessageComposer() +composer.set(user: user) +composer.setInitialComposerText("Hello! ") +composer.placeholderText = "Type a message..." +``` - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } +### Disable typing indicators - private func setupView() { - backgroundColor = UIColor.purple.withAlphaComponent(0.1) - layer.cornerRadius = 12 - addSubview(playButton) - - playButton.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - playButton.centerXAnchor.constraint(equalTo: centerXAnchor), - playButton.centerYAnchor.constraint(equalTo: centerYAnchor), - playButton.widthAnchor.constraint(equalToConstant: 30), - playButton.heightAnchor.constraint(equalToConstant: 30) - ]) - } - - @objc private func playButtonTapped() { - onPlayTapped?() // Executes the closure when tapped - } -} +```swift lines +let composer = CometChatMessageComposer() +composer.set(user: user) +composer.disableTypingEvents = true ``` - - - +### Disable mentions -*** +```swift lines +let composer = CometChatMessageComposer() +composer.set(user: user) +composer.disableMentions = true +``` -#### HeaderView +### Custom send button action -By using `set(headerView:)`, you can set a custom header view for the MessageComposer Component. +```swift lines +let composer = CometChatMessageComposer() +composer.set(user: user) - - -```swift -let messageComposer = CometChatMessageComposer() -messageComposer.set(headerView: { user, group in - let view = CustomHeaderView() - return view +composer.set(onSendButtonClick: { message in + print("Sending message: \(message)") }) ``` - - - +--- -**Demonstration** +## Styling - - - +### Style Hierarchy - - -```swift -import UIKit +1. Global styles (`CometChatMessageComposer.style`) apply to all instances +2. Instance styles override global for specific instances -class CustomHeaderView: UIView { - - private let iconImageView: UIImageView = { - let imageView = UIImageView() - imageView.image = UIImage(systemName: "bell.slash.fill") // Replace with the actual image if needed - imageView.tintColor = .purple - imageView.contentMode = .scaleAspectFit - return imageView - }() - - private let messageLabel: UILabel = { - let label = UILabel() - label.text = "User has paused their notifications" - label.textColor = .black - label.font = UIFont.systemFont(ofSize: 14, weight: .medium) - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } +### Global Level Styling - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } +```swift lines +import CometChatUIKitSwift - private func setupView() { - backgroundColor = UIColor.purple.withAlphaComponent(0.1) - layer.cornerRadius = 12 +CometChatMessageComposer.style.backgroundColor = .systemBackground +CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = .systemBlue +CometChatMessageComposer.style.attachmentImageTint = .systemGray +CometChatMessageComposer.style.voiceRecordingImageTint = .systemGray +``` - addSubview(iconImageView) - addSubview(messageLabel) +### Instance Level Styling - iconImageView.translatesAutoresizingMaskIntoConstraints = false - messageLabel.translatesAutoresizingMaskIntoConstraints = false +```swift lines +import CometChatUIKitSwift - NSLayoutConstraint.activate([ - iconImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12), - iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - iconImageView.widthAnchor.constraint(equalToConstant: 20), - iconImageView.heightAnchor.constraint(equalToConstant: 20), +var customStyle = MessageComposerStyle() +customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +customStyle.activeSendButtonImageBackgroundColor = .systemOrange +customStyle.composeBoxBackgroundColor = .white +customStyle.composeBoxBorderColor = .systemGray4 - messageLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 8), - messageLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12), - messageLabel.centerYAnchor.constraint(equalTo: centerYAnchor) - ]) - } -} +let composer = CometChatMessageComposer() +composer.style = customStyle ``` - - - + + + -*** +### Key Style Properties + +| Property | Type | Description | +|----------|------|-------------| +| `backgroundColor` | `UIColor` | Background color | +| `borderWidth` | `CGFloat` | Border width | +| `borderColor` | `UIColor` | Border color | +| `cornerRadius` | `CometChatCornerStyle?` | Corner radius | +| `placeHolderTextFont` | `UIFont` | Placeholder font | +| `placeHolderTextColor` | `UIColor` | Placeholder color | +| `textFiledColor` | `UIColor` | Input text color | +| `textFiledFont` | `UIFont` | Input text font | +| `sendButtonImage` | `UIImage?` | Send button icon | +| `sendButtonImageTint` | `UIColor` | Send button tint | +| `activeSendButtonImageBackgroundColor` | `UIColor` | Active send button background | +| `inactiveSendButtonImageBackgroundColor` | `UIColor` | Inactive send button background | +| `composeBoxBackgroundColor` | `UIColor` | Compose box background | +| `composeBoxBorderColor` | `UIColor` | Compose box border color | +| `composeBoxBorderWidth` | `CGFloat` | Compose box border width | +| `attachmentImage` | `UIImage?` | Attachment button icon | +| `attachmentImageTint` | `UIColor` | Attachment icon tint | +| `voiceRecordingImage` | `UIImage?` | Voice recording icon | +| `voiceRecordingImageTint` | `UIColor` | Voice recording tint | + +### Sub-Component Styles + +| Property | Type | Description | +|----------|------|-------------| +| `mediaRecorderStyle` | `MediaRecorderStyle` | Voice recording interface | +| `attachmentSheetStyle` | `AttachmentSheetStyle` | Attachment options sheet | +| `suggestionsStyle` | `SuggestionsStyle` | Mentions suggestions view | +| `aiOptionsStyle` | `AIOptionsStyle` | AI options menu | +| `mentionStyle` | `MentionStyle` | Mentions appearance | + +### Customization Matrix + +| What to change | Where | Property/API | +|----------------|-------|--------------| +| Override send behavior | Callback | `set(onSendButtonClick:)` | +| Track text input | Callback | `set(onTextChangedListener:)` | +| Toggle visibility | Props | `hide` boolean props | +| Custom attachments | View Slot | `set(attachmentOptions:)` | +| Replace UI sections | View Slot | `set(headerView:)`, `set(sendButtonView:)` | +| Change colors, fonts | Style | `MessageComposerStyle` properties | -#### SetTextFormatters +--- -Assigns the list of text formatters. If the provided list is not null, it sets the list. Otherwise, it assigns the default text formatters retrieved from the data source. To configure the existing Mentions look and feel check out [CometChatMentionsFormatter](/ui-kit/ios/mentions-formatter-guide) +## Props + +All props are optional. Sorted alphabetically. + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `disableMentions` | `Bool` | `false` | Disables the @mention feature | +| `disableSoundForMessages` | `Bool` | `false` | Disables sound when sending messages | +| `disableTypingEvents` | `Bool` | `false` | Disables sending typing indicators | +| `hideAIButton` | `Bool` | `false` | Hides the AI button | +| `hideAttachmentButton` | `Bool` | `false` | Hides the attachment button | +| `hideAudioAttachmentOption` | `Bool` | `false` | Hides the audio attachment option | +| `hideCollaborativeDocumentOption` | `Bool` | `false` | Hides the collaborative document option | +| `hideCollaborativeWhiteboardOption` | `Bool` | `false` | Hides the collaborative whiteboard option | +| `hideFileAttachmentOption` | `Bool` | `false` | Hides the file attachment option | +| `hideFooterView` | `Bool` | `false` | Hides the footer view | +| `hideHeaderView` | `Bool` | `false` | Hides the header view | +| `hideImageAttachmentOption` | `Bool` | `false` | Hides the image attachment option | +| `hidePollsOption` | `Bool` | `false` | Hides the polls option | +| `hideSendButton` | `Bool` | `false` | Hides the send button | +| `hideStickersButton` | `Bool` | `false` | Hides the stickers button | +| `hideVideoAttachmentOption` | `Bool` | `false` | Hides the video attachment option | +| `hideVoiceRecordingButton` | `Bool` | `false` | Hides the voice recording button | +| `maxLine` | `Int` | `5` | Maximum lines before scrolling | +| `placeholderText` | `String` | `"Type a message..."` | Placeholder text | +| `textFormatters` | `[CometChatTextFormatter]` | `[]` | Custom text formatters | -**Example** +--- - - -```swift -let composerTextStyle = MentionTextStyle() -.set(textBackgroundColor: .white) -.set(textColor: UIColor.black) -.set(textFont: UIFont.systemFont(ofSize: 18, weight: .heavy)) -.set(loggedInUserTextColor: UIColor.systemTeal) -.set(loggedInUserTextFont: UIFont.systemFont(ofSize: 18, weight: .bold)) +## Methods -let customMentionFormatter = CometChatMentionsFormatter() -.set(composerTextStyle: composerTextStyle) +### set(textFormatter:) -let messageComposerConfiguration = MessageComposerConfiguration() -.set(textFormatter: [customMentionFormatter]) +Sets a custom text formatter for the composer input. -let cometChatMessages = CometChatMessages() -.set(user: user) -.set(messageComposerConfiguration: messageComposerConfiguration) +```swift lines +let composer = CometChatMessageComposer() +let mentionFormatter = MentionTextFormatter(trackingCharacter: "@") +composer.set(textFormatter: mentionFormatter) ``` - +### setDisableMentionAll(_:) - +Disables or enables the @all mention feature that notifies all group members. -*** - - +```swift lines +let composer = CometChatMessageComposer() +composer.setDisableMentionAll(true) +``` -To ensure that the `MessageComposer` is properly configured, passing the controller is mandatory. +### setMentionAllLabel(_:_:) -* Swift +Customizes the label displayed for @all mentions in the suggestions list. -```swift -let composerView = CometChatMessageComposer() -composerView.set(controller: UIViewController) // Passing the controller is required +```swift lines +let composer = CometChatMessageComposer() +composer.setMentionAllLabel("Everyone", "Notify all members in this group") ``` - - -*** - - +--- -Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. +## Related Components - +- [Message List](/ui-kit/ios/message-list) — Display messages in a conversation +- [Message Header](/ui-kit/ios/message-header) — Display user/group details +- [Mentions Formatter](/ui-kit/ios/mentions-formatter-guide) — Configure @mention formatting diff --git a/ui-kit/ios/message-header.mdx b/ui-kit/ios/message-header.mdx index 81973492d..8ef148d9c 100644 --- a/ui-kit/ios/message-header.mdx +++ b/ui-kit/ios/message-header.mdx @@ -1,394 +1,292 @@ --- title: "Message Header" +description: "Display user or group details with typing indicators and navigation controls" --- -## Overview - -`MessageHeader` is a [Component](/ui-kit/ios/components-overview#components) that showcases the [User](/sdk/ios/users-overview) or [Group](/sdk/ios/groups-overview) details in the toolbar. Furthermore, it also presents a typing indicator and a back navigation button for ease of use. +The `CometChatMessageHeader` component displays user or group details in the toolbar including avatar, name, status, and typing indicators. It also provides navigation controls and call buttons. - + CometChatMessageHeader showing user avatar, name, online status, and call buttons in the navigation bar -The `MessageHeader` is comprised of the following components: - -| Components | Description | -| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| [ListItem Component](/ui-kit/ios/list-item) | This component’s view consists of avatar, status indicator , title, and subtitle. The fields are then mapped with the SDK’s user, group class. | -| Back Button | BackButton that allows users to navigate back from the current activity or screen to the previous one | - -## Usage - -### Integration - -You can add `MessageHeader` component directly by setting the user. - -```ruby Swift -// syntax for set(user: User) -messageHeader.set(user: user) // The object which is going to be rendered in the data item -``` - -### Actions - -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. - -The `MessageHeader` component does not have any exposed actions. - -##### 1. set(onBack:) - -This `set(onBack:)` method becomes valuable when a user needs to override the action triggered upon pressing the back button in CometChatMessageHeader. - - - -```swift -cometChatMessageHeader.set(onBack: { - // Override on back -}) -``` - - - - - -*** - -##### 2. set(onError:) - -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatMessageHeader. - - - -```swift -cometChatMessageHeader.set(onError: { error in - // Override on error -}) + +```json +{ + "component": "CometChatMessageHeader", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays user or group details in the toolbar with avatar, name, status, typing indicators, and navigation controls.", + "inherits": "UIView", + "primaryOutput": { + "callback": "onBack", + "type": "() -> Void" + }, + "props": { + "data": { + "user": { + "type": "User?", + "default": "nil", + "note": "User to display in header" + }, + "group": { + "type": "Group?", + "default": "nil", + "note": "Group to display in header" + } + }, + "callbacks": { + "onBack": "() -> Void", + "onError": "(CometChatException) -> Void", + "onAiChatHistoryClicked": "() -> Void", + "onAiNewChatClicked": "() -> Void" + }, + "visibility": { + "hideBackButton": { "type": "Bool", "default": false }, + "hideUserStatus": { "type": "Bool", "default": false }, + "hideVideoCallButton": { "type": "Bool", "default": false }, + "hideVoiceCallButton": { "type": "Bool", "default": false }, + "hideNewChatButton": { "type": "Bool", "default": false }, + "hideChatHistoryButton": { "type": "Bool", "default": false }, + "disableTyping": { "type": "Bool", "default": false } + }, + "style": { + "avatarStyle": { "type": "AvatarStyle", "default": "AvatarStyle()" }, + "statusIndicatorStyle": { "type": "StatusIndicatorStyle", "default": "StatusIndicatorStyle()" }, + "typingIndicatorStyle": { "type": "TypingIndicatorStyle", "default": "TypingIndicatorStyle()" } + }, + "formatting": { + "dateTimeFormatter": { "type": "CometChatDateTimeFormatter?", "default": "nil" } + }, + "viewSlots": { + "listItemView": "(User?, Group?) -> UIView", + "leadingView": "(User?, Group?) -> UIView", + "titleView": "(User?, Group?) -> UIView", + "subtitleView": "(User?, Group?) -> UIView", + "trailView": "(User?, Group?) -> UIView" + } + }, + "methods": { + "connection": { + "connect()": "Establishes WebSocket connection for real-time updates", + "disconnect()": "Disconnects WebSocket connection" + }, + "menuCustomization": { + "set(options:)": "((User?, Group?) -> [CometChatMessageHeaderOption])? - Sets custom menu options" + } + }, + "events": [], + "sdkListeners": [ + "onUserOnline", + "onUserOffline", + "onTypingStarted", + "onTypingEnded" + ], + "compositionExample": { + "description": "MessageHeader is typically used within CometChatMessages at the top of the chat screen", + "components": ["CometChatMessageHeader", "CometChatMessageList", "CometChatMessageComposer"], + "flow": "User views header → sees recipient info → taps back to return to conversations" + }, + "types": {} +} ``` + - - - - -*** - -### Filters - -**Filters** allow you to customize the data displayed in a list within a `Component`. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using `RequestBuilders` of Chat SDK. - -The `MessageHeader` component does not have any exposed filters. - -### Events - -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. - -The `MessageHeader` component does not produce any events. +| Field | Value | +|-------|-------| +| Component | `CometChatMessageHeader` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIView` | -## Customization - -To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. - -### Style - -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. - -##### 1. MessageHeader Style - -To customize the appearance, you can assign a `MessageHeaderStyle` object to the `MessageHeader` component. - -**Global level styling** - - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.textFont = UIFont(name: "Times-New-Roman", size: 18) - -CometChatMessageHeader.style.titleTextColor = UIColor(hex: "#F76808") -CometChatMessageHeader.style.titleTextFont = UIFont(name: "Times-New-Roman", size: 16) -CometChatMessageHeader.style.subtitleTextFont = UIFont(name: "Times-New-Roman", size: 12) -CometChatMessageHeader.style.avatarStyle = customAvatarStyle -``` +--- - +## Where It Fits - +`CometChatMessageHeader` displays the recipient's information at the top of the chat screen. It's typically used within `CometChatMessages` alongside `CometChatMessageList` and `CometChatMessageComposer`. -**Instance level styling** +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.textFont = UIFont(name: "Times-New-Roman", size: 18) +class ChatViewController: UIViewController { + + private var messageHeader: CometChatMessageHeader! + + override func viewDidLoad() { + super.viewDidLoad() + setupMessageHeader() + } + + private func setupMessageHeader(for user: User) { + messageHeader = CometChatMessageHeader() + messageHeader.set(user: user) -let messageHeaderStyle = MessageHeaderStyle() -messageHeaderStyle.titleTextColor = UIColor(hex: "#F76808") -messageHeaderStyle.titleTextFont = UIFont(name: "Times-New-Roman", size: 16) -messageHeaderStyle.subtitleTextFont = UIFont(name: "Times-New-Roman", size: 12) + // Handle back button + messageHeader.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) + }) -let messageHeader = CometChatMessageHeader() -messageHeader.style = messageHeaderStyle -messageHeader.avatarStyle = customAvatarStyle + view.addSubview(messageHeader) + } +} ``` - - - - - + CometChatMessageHeader showing user avatar, name, online status, and call buttons in the navigation bar -The properties exposed by `MessageHeaderStyle` are as follows: - -| **Property** | **Description** | **Code** | -| --------------------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -| **Title Text Color** | Used to set the text color of the header title. | `CometChatMessageHeader.style.titleTextColor = UIColor.black` | -| **Title Text Font** | Used to set the font style of the header title. | `CometChatMessageHeader.style.titleTextFont = UIFont.boldSystemFont(ofSize: 18)` | -| **Subtitle Text Color** | Used to set the text color of the subtitle in the header. | `CometChatMessageHeader.style.subtitleTextColor = UIColor.gray` | -| **Subtitle Text Font** | Used to set the font style of the subtitle in the header. | `CometChatMessageHeader.style.subtitleTextFont = UIFont.systemFont(ofSize: 14)` | -| **Back Button Image Tint Color** | Used to set the tint color of the back button image in the header. | `CometChatMessageHeader.style.backButtonImageTintColor = UIColor.blue` | -| **Private Group Badge Tint Color** | Used to set the tint color of the private group badge in the header. | `CometChatMessageHeader.style.privateGroupBadgeImageTintColor = UIColor.green` | -| **Password-Protected Badge Tint Color** | Used to set the tint color of the password-protected group badge in the header. | `CometChatMessageHeader.style.passwordProtectedGroupBadgeImageTintColor = UIColor.orange` | -| **Private Group Background Color** | Used to set the background color of the private group badge. | `CometChatMessageHeader.style.privateGroupImageBackgroundColor = UIColor.lightGray` | -| **Password-Protected Background Color** | Used to set the background color of the password-protected group badge. | `CometChatMessageHeader.style.passwordGroupImageBackgroundColor = UIColor.red` | -| **Group Image Background Color** | Used to set the background color for group icons in the header. | `CometChatMessageHeader.style.groupImageBackgroundColor = UIColor.clear` | -| **Avatar Style** | Used to customize the appearance of the avatar in the header. | `CometChatMessageHeader.style.avatarStyle = customAvatarStyle` | -| **Background Color** | Used to set the background color of the header. | `CometChatMessageHeader.style.backgroundColor = UIColor.white` | -| **Corner Radius** | Used to set the corner radius of the header. | `CometChatMessageHeader.style.cornerRadius = CometChatCornerStyle(cornerRadius: 8)` | -| **Border Width** | Used to set the border width of the header. | `CometChatMessageHeader.style.borderWidth = 2` | -| **Border Color** | Used to set the border color of the header. | `CometChatMessageHeader.style.borderColor = UIColor.gray` | -| **Back Button Icon** | Used to set a custom icon for the back button. | `CometChatMessageHeader.style.backButtonIcon = UIImage(named: "customBackIcon")` | -| **Private Group Icon** | Used to set a custom icon for private groups. | `CometChatMessageHeader.style.privateGroupIcon = UIImage(named: "privateIcon")` | -| **Protected Group Icon** | Used to set a custom icon for password-protected groups. | `CometChatMessageHeader.style.protectedGroupIcon = UIImage(named: "protectedIcon")` | -| **Background Image** | Used to set a background image for the header. | `CometChatMessageHeader.style.backgroundImage = UIImage(named: "headerBackground")` | -| **New Chat Icon** | Sets a custom icon for the new chat button for AI agent. | `CometChatAIAssistantChatHistory.newChatIcon = UIImage(named: "iconName")` | -| **Chat History Icon** | Sets a custom icon for the chat history button for AI agent. | `CometChatAIAssistantChatHistory.chatHistoryIcon = UIImage(named: "iconName")` | - -##### 2. Avatar Style - -If you want to apply customized styles to the `Avatar` component within the `MessageHeader` Component, you can use the following code snippet. For more information you can refer [Avatar Styles](/ui-kit/ios/component-styling#avatar#methods). - -**Global level styling** - - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) - -CometChatMessageHeader.style.avatarStyle = customAvatarStyle -``` - - +--- - +## Minimal Render -**Instance level styling** +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) - let messageHeader = CometChatMessageHeader() -messageHeader.avatarStyle = customAvatarStyle +messageHeader.set(user: user) ``` - - - - - + CometChatMessageHeader showing minimal render with user details and default styling -*** - -### Functionality - -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. +--- -Below is a list of customizations along with corresponding code snippets +## Actions and Events -| Method | Description | Code | -| ------------------- | ---------------------------------------------------------------------- | ---------------------------- | -| set(user:User) | Sets message header for CometChat user. | `.set(user:User)` | -| set(group:Group) | Sets message header for CometChat group. | `.set(group:Group)` | -| hideBackButton | Hides the back button of message header. | `hideBackButton = true` | -| hideUserStatus | Hides or shows the user status of user(online/offline/last active at). | `hideUserStatus = true` | -| hideVideoCallButton | Hides the video call button. | `hideVideoCallButton = true` | -| hideVoiceCallButton | Hides the voice call button. | `hideVoiceCallButton = true` | -| hideChatHistoryButton | Hides the chat history button in the component. | `CometChatAIAssistantChatHistory.hideChatHistoryButton = true` | -| hideNewChatButton | Hides the new chat button in the component for AI agent. | `CometChatAIAssistantChatHistory.hideNewChatButton = true` | -| onNewChatButtonClicked | Used to handle actions when the “New Chat” button is clicked. | `CometChatAIAssistantChatHistory.set(onNewChatButtonClicked: { user in })` | -| onMessageClicked | Used to handle actions when a message is clicked. | `CometChatAIAssistantChatHistory.set(onMessageClicked: { message in })` | +### Callback Props -*** +#### onBack -### Advanced +Fires when the back button is pressed. Use this for custom navigation handling. -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. +```swift lines +import CometChatUIKitSwift -#### Date Time Formatter +let messageHeader = CometChatMessageHeader() -The **CometChatMessageHeader** component supports full customization of how date and time are displayed using the [CometChatDateTimeFormatter](/ui-kit/ios/localize#datetimeformatter). +messageHeader.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) +}) +``` -This enables developers to localize, format, or personalize the date and time strings shown next to the message header such as “Today”, “Yesterday”, “12:45 PM”, etc. +#### onError -1. Component-Level (Global) +Fires when an error occurs. - - -```swift -CometChatMessageHeader.dateTimeFormatter.time = { timestamp in - return "Last seen at " + DateFormatter.localizedString(from: Date(timeIntervalSince1970: TimeInterval(timestamp)), dateStyle: .none, timeStyle: .short) -} +```swift lines +import CometChatUIKitSwift -CometChatMessageHeader.dateTimeFormatter.today = { timestamp in - return "Last seen: Today • \(formattedTime(from: timestamp))" -} +let messageHeader = CometChatMessageHeader() -CometChatMessageHeader.dateTimeFormatter.otherDay = { timestamp in // This will display older dates as "24 Apr 2025" instead of the default relative format. - let formatter = DateFormatter() - formatter.dateFormat = "dd MMM yyyy" - return formatter.string(from: Date(timeIntervalSince1970: TimeInterval(timestamp))) -} +messageHeader.set(onError: { error in + print("Error: \(error.errorDescription)") +}) ``` - +### Actions Reference - +| Method | Description | Example | +|--------|-------------|---------| +| `set(onBack:)` | Triggered when back button is pressed | Custom navigation | +| `set(onError:)` | Triggered when an error occurs | Show error alert | +| `set(user:)` | Sets the user to display | Configure header for user | +| `set(group:)` | Sets the group to display | Configure header for group | -2. Instance-Level (Local) +### SDK Events (Real-Time, Automatic) - - -```swift -let messageHeader = CometChatMessageHeader() -messageHeader.dateTimeFormatter.yesterday = { timestamp in - return "Yesterday at " + formattedTime(from: timestamp) -} -``` +| SDK Listener | Internal behavior | +|--------------|-------------------| +| `onUserOnline` | Updates status indicator to online | +| `onUserOffline` | Updates status indicator to offline | +| `onTypingStarted` | Shows typing indicator in subtitle | +| `onTypingEnded` | Hides typing indicator | - +--- - +## Custom View Slots -##### Available closures +{/* TODO: Add screenshot showing auxiliaryButtonView customization - Note: iOS MessageHeader uses trailView instead of auxiliaryButtonView (which is Android-specific). The trailView screenshot below demonstrates equivalent functionality for customizing the right side action buttons area. */} -| Property | Description | Code | -| --------- | ------------------------------------------------------------------- | -------------------------------------------------------------- | -| time | Called to format a timestamp as a standard time (e.g., "12:30 PM"). | `CometChatMessageHeader.dateTimeFormatter.time = { ... }` | -| today | Called when rendering messages sent today. | `CometChatMessageHeader.dateTimeFormatter.today = { ... }` | -| yesterday | Called for yesterday's messages. | `CometChatMessageHeader.dateTimeFormatter.yesterday = { ... }` | -| lastweek | Called for messages within the last week. | `CometChatMessageHeader.dateTimeFormatter.lastweek = { ... }` | -| otherDay | Called for dates older than last week. | `CometChatMessageHeader.dateTimeFormatter.otherDay = { ... }` | -| minute | Called when referring to "a minute ago". | `CometChatMessageHeader.dateTimeFormatter.minute = { ... }` | -| minutes | Called for "x minutes ago". | `CometChatMessageHeader.dateTimeFormatter.minutes = { ... }` | -| hour | Called for "an hour ago". | `CometChatMessageHeader.dateTimeFormatter.hour = { ... }` | -| hours | Called for "x hours ago". | `CometChatMessageHeader.dateTimeFormatter.hours = { ... }` | +| Slot | Signature | Replaces | +|------|-----------|----------| +| `listItemView` | `(User?, Group?) -> UIView` | Entire header content | +| `leadingView` | `(User?, Group?) -> UIView` | Avatar / left section | +| `titleView` | `(User?, Group?) -> UIView` | Name / title text | +| `subtitleView` | `(User?, Group?) -> UIView` | Status / subtitle text | +| `trailView` | `(User?, Group?) -> UIView` | Right side (call buttons) | -Each closure receives a timestamp (Int, representing UNIX time) and must return a String representing the formatted time. +### listItemView -*** +Replace the entire header content with a custom view. -#### SetListItemView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -With this function, you can assign a custom ListItem to the message header Component. +let messageHeader = CometChatMessageHeader() - - -```swift -let cometChatMessageHeader = CometChatMessageHeader() -cometChatMessageHeader.set(listItemView: { user, group in - let view = CustomListItemView() - return view +messageHeader.set(listItemView: { user, group in + let customView = CustomHeaderView() + customView.configure(user: user, group: group) + return customView }) ``` - +You can create a `CustomHeaderView` as a custom `UIView`: - - -Demonstration - - - - - -You can create a `CustomListItemView` as a custom `UIView`. Which we will inflate in `setListItemView()` - -```swift swift +```swift lines import UIKit +import CometChatSDK -class CustomListItemView: UIView { - +class CustomHeaderView: UIView { + private let backButton: UIButton = { let button = UIButton(type: .system) - let image = UIImage(systemName: "chevron.left")?.withRenderingMode(.alwaysTemplate) - button.setImage(image, for: .normal) + button.setImage(UIImage(systemName: "chevron.left"), for: .normal) button.tintColor = .black return button }() - - private let profileImageView: UIView = { - let view = UIView() - view.backgroundColor = UIColor.systemPurple - view.layer.cornerRadius = 18 - view.clipsToBounds = true - - let label = UILabel() - label.text = "GA" - label.font = UIFont.systemFont(ofSize: 16, weight: .bold) - label.textColor = .white - label.textAlignment = .center - label.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(label) - - NSLayoutConstraint.activate([ - label.centerXAnchor.constraint(equalTo: view.centerXAnchor), - label.centerYAnchor.constraint(equalTo: view.centerYAnchor) - ]) - - return view + + private let profileImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.layer.cornerRadius = 18 + imageView.clipsToBounds = true + imageView.backgroundColor = .lightGray + return imageView }() - + private let nameLabel: UILabel = { let label = UILabel() - label.text = "George Alan" - label.font = UIFont.systemFont(ofSize: 16, weight: .bold) + label.font = UIFont.systemFont(ofSize: 16, weight: .semibold) label.textColor = .black return label }() - + private let statusLabel: UILabel = { let label = UILabel() - label.text = "Online" - label.font = UIFont.systemFont(ofSize: 12, weight: .regular) + label.font = UIFont.systemFont(ofSize: 12) label.textColor = .gray return label }() - + private let videoCallButton: UIButton = { let button = UIButton(type: .system) - let image = UIImage(systemName: "video.fill")?.withRenderingMode(.alwaysTemplate) - button.setImage(image, for: .normal) + button.setImage(UIImage(systemName: "video.fill"), for: .normal) button.tintColor = .black return button }() - + private let callButton: UIButton = { let button = UIButton(type: .system) - let image = UIImage(systemName: "phone.fill")?.withRenderingMode(.alwaysTemplate) - button.setImage(image, for: .normal) + button.setImage(UIImage(systemName: "phone.fill"), for: .normal) button.tintColor = .black return button }() - + override init(frame: CGRect) { super.init(frame: frame) setupView() @@ -438,39 +336,42 @@ class CustomListItemView: UIView { rightButtonsStack.centerYAnchor.constraint(equalTo: centerYAnchor) ]) } + + func configure(user: User?, group: Group?) { + nameLabel.text = user?.name ?? group?.name ?? "Chat" + if let user = user { + statusLabel.text = user.status == .online ? "Online" : "Offline" + } else if let group = group { + statusLabel.text = "\(group.membersCount) members" + } + } } ``` -*** +### leadingView + +Customize the leading view (avatar area) of the header. -#### SetLeadingView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can modify the leading view of a group cell using .set(leadingView:). +let messageHeader = CometChatMessageHeader() - - -```swift -cometChatMessageHeader.set(leadingView: { user, group in +messageHeader.set(leadingView: { user, group in let view = CustomLeadingView() - return view -}) + return view +}) ``` - - - - -Demonstration - - + CometChatMessageHeader with custom leadingView showing avatar with Admin badge overlay -You can create a `CustomLeadingView` as a custom `UIView`. Which we will inflate in `setLeadingView()` +You can create a `CustomLeadingView` as a custom `UIView`: - - -```swift +```swift lines import UIKit class CustomLeadingView: UIView { @@ -480,22 +381,21 @@ class CustomLeadingView: UIView { imageView.contentMode = .scaleAspectFill imageView.layer.cornerRadius = 20 imageView.clipsToBounds = true - imageView.backgroundColor = .lightGray // Placeholder color + imageView.backgroundColor = .lightGray imageView.image = UIImage(systemName: "person.fill") return imageView }() - private let joinButton: UIButton = { - let button = UIButton() - button.setTitle("Join", for: .normal) - button.setTitleColor(.white, for: .normal) - button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold) - button.backgroundColor = .orange - button.layer.cornerRadius = 6 - button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) - button.setImage(UIImage(systemName: "star.circle"), for: .normal) - button.setTitle("Admin", for: .normal) - return button + private let badgeLabel: UILabel = { + let label = UILabel() + label.text = "Admin" + label.font = UIFont.systemFont(ofSize: 10, weight: .bold) + label.textColor = .white + label.backgroundColor = .orange + label.textAlignment = .center + label.layer.cornerRadius = 6 + label.clipsToBounds = true + return label }() override init(frame: CGRect) { @@ -509,10 +409,10 @@ class CustomLeadingView: UIView { private func setupView() { addSubview(profileImageView) - addSubview(joinButton) + addSubview(badgeLabel) profileImageView.translatesAutoresizingMaskIntoConstraints = false - joinButton.translatesAutoresizingMaskIntoConstraints = false + badgeLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor), @@ -522,50 +422,42 @@ class CustomLeadingView: UIView { profileImageView.heightAnchor.constraint(equalToConstant: 40), profileImageView.widthAnchor.constraint(equalToConstant: 40), - joinButton.trailingAnchor.constraint(equalTo: profileImageView.trailingAnchor), - joinButton.leadingAnchor.constraint(equalTo: profileImageView.leadingAnchor), - joinButton.bottomAnchor.constraint(equalTo: profileImageView.bottomAnchor), - joinButton.heightAnchor.constraint(equalToConstant: 12) + badgeLabel.trailingAnchor.constraint(equalTo: profileImageView.trailingAnchor), + badgeLabel.bottomAnchor.constraint(equalTo: profileImageView.bottomAnchor), + badgeLabel.widthAnchor.constraint(equalToConstant: 40), + badgeLabel.heightAnchor.constraint(equalToConstant: 12) ]) } } ``` - - - +### titleView -*** +Customize the title view of the header. -#### SetTitleView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can customize the title view of a group cell using .set(titleView:). +let messageHeader = CometChatMessageHeader() - - -```swift -cometChatMessageHeader.set(titleView: { user, group in +messageHeader.set(titleView: { user, group in let view = CustomTitleView() return view -}) +}) ``` - - - - -Demonstration - - + CometChatMessageHeader with custom titleView showing group name with Public badge -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +You can create a `CustomTitleView` as a custom `UIView`: - - -```swift - class CustomTitleView: UIView { +```swift lines +import UIKit + +class CustomTitleView: UIView { private let titleLabel: UILabel = { let label = UILabel() @@ -633,40 +525,56 @@ You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate i } ``` - - - +### subtitleView -*** +Customize the subtitle area (status, typing indicator). -#### SetTrailView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can modify the trailing view of a message header using .set(trailView:). +let messageHeader = CometChatMessageHeader() - - -```swift -cometChatMessageHeader.set(trailView: { user, group in - let view = CustomTrailView() - return view -}) +messageHeader.set(subtitleView: { user, group in + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 13) + label.textColor = UIColor.secondaryLabel + + if let user = user { + label.text = user.status == .online ? "🟢 Online" : "⚫ Offline" + } else if let group = group { + label.text = "\(group.membersCount) members" + } + + return label +}) ``` - +### trailView + +Customize the right side of the header (call buttons, etc.). + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - +let messageHeader = CometChatMessageHeader() -Demonstration +messageHeader.set(trailView: { user, group in + let view = CustomTrailView() + return view +}) +``` - + CometChatMessageHeader with custom trailView showing video call, voice call, and bookmark buttons -You can create a `CustomTrailView` as a custom `UIView`. Which we will inflate in `setTrailView()` +You can create a `CustomTrailView` as a custom `UIView`: - - -```swift +```swift lines import UIKit class CustomTrailView: UIView { @@ -689,7 +597,7 @@ class CustomTrailView: UIView { private let bookMarkButton: UIButton = { let button = UIButton(type: .system) - let image = UIImage(systemName: "phone.fill")?.withRenderingMode(.alwaysTemplate) + let image = UIImage(systemName: "bookmark.fill")?.withRenderingMode(.alwaysTemplate) button.setImage(image, for: .normal) button.tintColor = .black return button @@ -705,16 +613,12 @@ class CustomTrailView: UIView { } private func setupView() { - - let buttonsStack = UIStackView(arrangedSubviews: [videoCallButton, callButton]) + let buttonsStack = UIStackView(arrangedSubviews: [videoCallButton, callButton, bookMarkButton]) buttonsStack.axis = .horizontal buttonsStack.spacing = 16 buttonsStack.distribution = .fillEqually - buttonsStack.addArrangedSubview(videoCallButton) - buttonsStack.addArrangedSubview(callButton) - buttonsStack.addArrangedSubview(bookMarkButton) - + addSubview(buttonsStack) buttonsStack.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ @@ -725,78 +629,547 @@ class CustomTrailView: UIView { ]) } } - ``` - +--- - +## Styling -*** +### Style Hierarchy -#### SetSubTitleView +1. Global styles (`CometChatMessageHeader.style`) apply to all instances +2. Instance styles override global for specific instances -You can customize the subtitle view for each group item to meet your requirements +### Global Level Styling - - -```swift -cometChatMessageHeader.set(subtitleView: { user, group in - let view = CustomSubtitleView() - return view -}) +```swift lines +import UIKit +import CometChatUIKitSwift + +// Apply global styles that affect all CometChatMessageHeader instances +CometChatMessageHeader.style.backgroundColor = UIColor.systemBackground +CometChatMessageHeader.style.titleTextColor = UIColor.label +CometChatMessageHeader.style.titleTextFont = UIFont.systemFont(ofSize: 17, weight: .semibold) +CometChatMessageHeader.style.subtitleTextColor = UIColor.secondaryLabel +CometChatMessageHeader.style.subtitleTextFont = UIFont.systemFont(ofSize: 13) +CometChatMessageHeader.style.backButtonImageTintColor = UIColor.systemBlue + +// Custom avatar style +let avatarStyle = AvatarStyle() +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) +CometChatMessageHeader.style.avatarStyle = avatarStyle ``` - +### Instance Level Styling - +```swift lines +import UIKit +import CometChatUIKitSwift -**Example** +// Create a custom style for a specific instance +var customStyle = MessageHeaderStyle() +customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +customStyle.titleTextColor = UIColor.darkGray +customStyle.titleTextFont = UIFont.systemFont(ofSize: 18, weight: .bold) +customStyle.subtitleTextColor = UIColor.gray -Demonstration +let messageHeader = CometChatMessageHeader() +messageHeader.style = customStyle +``` - + CometChatMessageHeader with custom instance styling showing modified background color and text appearance -You can seamlessly integrate this `CustomSubtitleView` UIView file into the `.set(subtitleView:)` method within CometChatMessageHeader. +### Key Style Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `backgroundColor` | `UIColor` | `CometChatTheme.backgroundColor01` | Background color | +| `borderWidth` | `CGFloat` | `0` | Border width | +| `borderColor` | `UIColor` | `.clear` | Border color | +| `cornerRadius` | `CometChatCornerStyle?` | `nil` | Corner radius | +| `titleTextColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Title text color | +| `titleTextFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Title font | +| `subtitleTextColor` | `UIColor` | `CometChatTheme.textColorSecondary` | Subtitle text color | +| `subtitleTextFont` | `UIFont` | `CometChatTypography.Body.regular` | Subtitle font | +| `backButtonImageTintColor` | `UIColor` | `CometChatTheme.iconColorPrimary` | Back button tint | +| `backButtonIcon` | `UIImage?` | System chevron | Back button icon | +| `privateGroupBadgeImageTintColor` | `UIColor` | `CometChatTheme.iconColorSecondary` | Private group badge tint | +| `passwordProtectedGroupBadgeImageTintColor` | `UIColor` | `CometChatTheme.iconColorSecondary` | Password group badge tint | +| `avatarStyle` | `AvatarStyle` | `AvatarStyle()` | Avatar customization | +| `statusIndicatorStyle` | `StatusIndicatorStyle` | `StatusIndicatorStyle()` | Online/offline status indicator customization | +| `typingIndicatorStyle` | `TypingIndicatorStyle` | `TypingIndicatorStyle()` | Typing indicator customization | + +### Customization Matrix + +| What to change | Where | Property/API | Example | +|----------------|-------|--------------|---------| +| Background color | Style | `backgroundColor` | `UIColor.systemBackground` | +| Title appearance | Style | `titleTextColor`, `titleTextFont` | Custom colors and fonts | +| Subtitle appearance | Style | `subtitleTextColor`, `subtitleTextFont` | Custom colors and fonts | +| Back button | Style | `backButtonIcon`, `backButtonImageTintColor` | Custom icon and color | +| Avatar look | Style | `avatarStyle` | `AvatarStyle()` with custom radius | +| Status indicator | Style | `statusIndicatorStyle` | `StatusIndicatorStyle()` with custom colors | +| Typing indicator | Style | `typingIndicatorStyle` | `TypingIndicatorStyle()` with custom font | +| Hide back button | Property | `hideBackButton` | `header.hideBackButton = true` | +| Hide status | Property | `hideUserStatus` | `header.hideUserStatus = true` | +| Disable typing | Property | `disableTyping` | `header.disableTyping = true` | +| Hide AI buttons | Property | `hideNewChatButton`, `hideChatHistoryButton` | `header.hideNewChatButton = true` | +| Custom subtitle | View Slot | `set(subtitleView:)` | See Custom View Slots | +| Custom menu options | Method | `set(options:)` | See Menu Customization | + +--- + +## Connection Management + +Manually control the WebSocket connection for the message header. + +### connect() + +Establishes the WebSocket connection for real-time updates. Use this when you need to manually reconnect after disconnecting. + +```swift lines +@discardableResult +public func connect() -> Self +``` - - -```swift +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +// Manually connect to receive real-time updates +messageHeader.connect() +``` + +### disconnect() + +Disconnects the WebSocket connection. Use this when you want to temporarily stop receiving real-time updates, such as when the view is not visible. + +```swift lines +@discardableResult +public func disconnect() -> Self +``` + +```swift lines import UIKit +import CometChatUIKitSwift -class CustomSubtitleView: UILabel { +class ChatViewController: UIViewController { - init(membersCount: Int) { - super.init(frame: .zero) - self.text = "\(membersCount) members • \("group_description")" - self.textColor = UIColor.gray - self.font = UIFont.systemFont(ofSize: 14) - self.numberOfLines = 1 + private var messageHeader: CometChatMessageHeader! + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + messageHeader.disconnect() } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + messageHeader.connect() } } ``` - +--- + +## Menu Customization + +### set(options:) + +Sets custom menu options for the message header. These options appear in the header's menu (typically accessed via a more button or long press). + +```swift lines +@discardableResult +public func set(options: ((_ user: User?, _ group: Group?) -> [CometChatMessageHeaderOption])?) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((User?, Group?) -> [CometChatMessageHeaderOption])?` | Closure that returns an array of menu options based on the current user or group | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let messageHeader = CometChatMessageHeader() + +messageHeader.set(options: { user, group in + var options = [CometChatMessageHeaderOption]() + + // Add a custom "View Profile" option + let viewProfileOption = CometChatMessageHeaderOption( + id: "view_profile", + title: "View Profile", + icon: UIImage(systemName: "person.circle") + ) { user, group in + // Handle view profile action + print("View profile tapped") + } + options.append(viewProfileOption) + + // Add a custom "Mute Notifications" option + let muteOption = CometChatMessageHeaderOption( + id: "mute_notifications", + title: "Mute Notifications", + icon: UIImage(systemName: "bell.slash") + ) { user, group in + // Handle mute action + print("Mute notifications tapped") + } + options.append(muteOption) + + return options +}) +``` + +--- + +## Props + +All props are optional. Sorted alphabetically. + +### avatarStyle + +Customizes the appearance of the avatar in the message header. + +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor.systemBlue +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) +avatarStyle.borderWidth = 2 +avatarStyle.borderColor = UIColor.white + +messageHeader.set(avatarStyle: avatarStyle) +``` + +### dateTimeFormatter - +Custom formatter for date/time display in the message header (e.g., "Last seen at..."). -*** +| | | +|---|---| +| Type | `CometChatDateTimeFormatter?` | +| Default | `nil` | - +```swift lines +import CometChatUIKitSwift -To ensure that the `MessageHeader` is properly configured, passing the controller is mandatory. +let messageHeader = CometChatMessageHeader() + +let dateTimeFormatter = CometChatDateTimeFormatter() +dateTimeFormatter.todayFormat = "h:mm a" +dateTimeFormatter.yesterdayFormat = "'Yesterday at' h:mm a" +dateTimeFormatter.otherFormat = "MMM d, yyyy" + +messageHeader.dateTimeFormatter = dateTimeFormatter +``` + +### disableTyping + +Disables typing indicators in the message header. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() +messageHeader.disableTyping = true +``` + +### hideBackButton + +Hides the back button in the header. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideChatHistoryButton + +Hides the AI chat history button in the header. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() +messageHeader.hideChatHistoryButton = true +``` + +### hideNewChatButton -* Swift +Hides the AI new chat button in the header. -```swift -let headerView = CometChatMessageHeader() -headerView.set(controller: UIViewController) // Passing the controller is required +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() +messageHeader.hideNewChatButton = true +``` + +### hideUserStatus + +Hides the user status (online/offline/last active). + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideVideoCallButton + +Hides the video call button. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideVoiceCallButton + +Hides the voice call button. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### onAiChatHistoryClicked + +Callback triggered when the AI chat history button is clicked. + +| | | +|---|---| +| Type | `(() -> Void)?` | +| Default | `nil` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +messageHeader.set(onAiChatHistoryClicked: { [weak self] in + // Handle AI chat history button click + self?.presentAiChatHistory() +}) ``` - +### onAiNewChatClicked + +Callback triggered when the AI new chat button is clicked. + +| | | +|---|---| +| Type | `(() -> Void)?` | +| Default | `nil` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +messageHeader.set(onAiNewChatClicked: { [weak self] in + // Handle AI new chat button click + self?.startNewAiChat() +}) +``` + +### statusIndicatorStyle + +Customizes the appearance of the online/offline status indicator. + +| | | +|---|---| +| Type | `StatusIndicatorStyle` | +| Default | `StatusIndicatorStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +let statusIndicatorStyle = StatusIndicatorStyle() +statusIndicatorStyle.backgroundColor = UIColor.systemGreen +statusIndicatorStyle.borderWidth = 2 +statusIndicatorStyle.borderColor = UIColor.white +statusIndicatorStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 6) + +messageHeader.set(statusIndicatorStyle: statusIndicatorStyle) +``` + +### typingIndicatorStyle + +Customizes the appearance of the typing indicator in the message header subtitle. + +| | | +|---|---| +| Type | `TypingIndicatorStyle` | +| Default | `TypingIndicatorStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +let typingIndicatorStyle = TypingIndicatorStyle() +typingIndicatorStyle.textColor = UIColor.systemGray +typingIndicatorStyle.textFont = UIFont.italicSystemFont(ofSize: 13) + +messageHeader.set(typingIndicatorStyle: typingIndicatorStyle) +``` + +--- + +## Events + +The MessageHeader component does not emit any global UI events. + +--- + +## Date Time Formatter + +Customize how timestamps appear in the message header (e.g., "Last seen at...") using the `CometChatDateTimeFormatter`. + +### Global Level Formatting + +```swift lines +import CometChatUIKitSwift + +// Customize time format for last seen +CometChatMessageHeader.dateTimeFormatter.time = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "h:mm a" + return "Last seen at " + formatter.string(from: date) +} + +// Customize today format +CometChatMessageHeader.dateTimeFormatter.today = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "h:mm a" + return "Last seen today at " + formatter.string(from: date) +} + +// Customize yesterday format +CometChatMessageHeader.dateTimeFormatter.yesterday = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "h:mm a" + return "Last seen yesterday at " + formatter.string(from: date) +} +``` + +### Instance Level Formatting + +```swift lines +import CometChatUIKitSwift + +let messageHeader = CometChatMessageHeader() + +messageHeader.dateTimeFormatter.otherDay = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "MMM d, yyyy" + return "Last seen on " + formatter.string(from: date) +} +``` + +### Available Formatters + +| Formatter | Purpose | Default Format | +|-----------|---------|----------------| +| `time` | Standard time display | `h:mm a` | +| `today` | Last seen today | `Today at h:mm a` | +| `yesterday` | Last seen yesterday | `Yesterday at h:mm a` | +| `lastweek` | Last seen within last week | Day name | +| `otherDay` | Last seen older dates | `MMM d, yyyy` | + +--- + +## Common Patterns + +### Hide call buttons + +```swift lines +let messageHeader = CometChatMessageHeader() +messageHeader.set(user: user) +messageHeader.hideVideoCallButton = true +messageHeader.hideVoiceCallButton = true +``` + +### Custom back button action + +```swift lines +let messageHeader = CometChatMessageHeader() +messageHeader.set(user: user) + +messageHeader.set(onBack: { [weak self] in + // Custom navigation logic + self?.dismiss(animated: true) +}) +``` + +### Custom subtitle with typing indicator + +```swift lines +let messageHeader = CometChatMessageHeader() +messageHeader.set(user: user) + +messageHeader.set(subtitleView: { user, group in + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 12) + + if let user = user { + label.text = user.status == .online ? "Online" : "Offline" + label.textColor = user.status == .online ? .systemGreen : .secondaryLabel + } + + return label +}) +``` + +### Minimal header + +```swift lines +let messageHeader = CometChatMessageHeader() +messageHeader.set(user: user) +messageHeader.hideBackButton = true +messageHeader.hideUserStatus = true +messageHeader.hideVideoCallButton = true +messageHeader.hideVoiceCallButton = true +``` + +--- + +## Related Components + +- [Messages](/ui-kit/ios/messages) - Parent component containing MessageHeader +- [Message List](/ui-kit/ios/message-list) - Display messages in a conversation +- [Message Composer](/ui-kit/ios/message-composer) - Send messages in a conversation +- [Conversations](/ui-kit/ios/conversations) - Navigate back to conversation list diff --git a/ui-kit/ios/message-list.mdx b/ui-kit/ios/message-list.mdx index 0deb40de6..8f1c3fc9e 100644 --- a/ui-kit/ios/message-list.mdx +++ b/ui-kit/ios/message-list.mdx @@ -1,822 +1,838 @@ --- title: "Message List" +description: "Display and manage real-time chat messages with various message types" --- -## Overview - -`MessageList` is a [Composite Component](/ui-kit/ios/components-overview#composite-components) that displays a list of messages and effectively manages real-time operations. It includes various types of messages such as Text Messages, Media Messages, Stickers, and more. - -`MessageList` is primarily a list of the base component [MessageBubble](/ui-kit/ios/message-bubble-styling). The MessageBubble Component is utilized to create different types of chat bubbles depending on the message type. +The `CometChatMessageList` component displays a scrollable list of messages in a conversation. It supports text messages, media messages, reactions, threads, and real-time updates for new messages, edits, and deletions. - + CometChatMessageList showing a scrollable list of chat messages with text bubbles, timestamps, and read receipts in a conversation view -*** + +```json +{ + "component": "CometChatMessageList", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays a scrollable list of messages in a conversation with real-time updates for new messages, edits, deletions, reactions, and typing indicators.", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onMessageClick", + "type": "(BaseMessage) -> Void" + }, + "props": { + "data": { + "messagesRequestBuilder": { + "type": "MessagesRequest.MessageRequestBuilder?", + "default": "nil", + "note": "Custom request builder for filtering messages" + }, + "reactionsRequestBuilder": { + "type": "ReactionsRequest.ReactionsRequestBuilder?", + "default": "nil", + "note": "Custom request builder for fetching reactions" + } + }, + "callbacks": { + "onThreadRepliesClick": "(BaseMessage, MessageTemplate) -> Void", + "onReactionClick": "(ReactionCount, BaseMessage?) -> Void", + "onReactionListItemClick": "(MessageReaction, BaseMessage) -> Void", + "onError": "(CometChatException) -> Void", + "onEmpty": "() -> Void", + "onLoad": "([BaseMessage]) -> Void" + }, + "visibility": { + "hideAvatar": { "type": "Bool", "default": false }, + "hideReceipts": { "type": "Bool", "default": false }, + "hideDateSeparator": { "type": "Bool", "default": false }, + "hideHeaderView": { "type": "Bool", "default": false }, + "hideFooterView": { "type": "Bool", "default": false }, + "hideReactionOption": { "type": "Bool", "default": false }, + "hideReplyInThreadOption": { "type": "Bool", "default": false }, + "hideEditMessageOption": { "type": "Bool", "default": false }, + "hideDeleteMessageOption": { "type": "Bool", "default": false }, + "hideCopyMessageOption": { "type": "Bool", "default": false }, + "hideMessageInfoOption": { "type": "Bool", "default": false }, + "hideTranslateMessageOption": { "type": "Bool", "default": false }, + "hideMessagePrivatelyOption": { "type": "Bool", "default": false }, + "hideGroupActionMessages": { "type": "Bool", "default": false }, + "hideNewMessageIndicator": { "type": "Bool", "default": false }, + "hideEmptyView": { "type": "Bool", "default": false }, + "hideErrorView": { "type": "Bool", "default": false }, + "hideLoadingView": { "type": "Bool", "default": false } + }, + "sound": { + "disableSoundForMessages": { "type": "Bool", "default": false } + }, + "behavior": { + "scrollToBottomOnNewMessages": { "type": "Bool", "default": true }, + "startFromUnreadMessages": { "type": "Bool", "default": false }, + "showMarkAsUnreadOption": { "type": "Bool", "default": false }, + "messageAlignment": { "type": "MessageAlignment", "default": ".standard" } + }, + "viewSlots": { + "headerView": "() -> UIView", + "footerView": "() -> UIView", + "emptyStateView": "() -> UIView", + "errorStateView": "() -> UIView", + "loadingStateView": "() -> UIView", + "newMessageIndicatorView": "() -> UIView" + }, + "formatting": { + "datePattern": "(Int?) -> String", + "timePattern": "(Int) -> String", + "dateSeparatorPattern": "(Int?) -> String", + "textFormatters": "[CometChatTextFormatter]" + } + }, + "events": [], + "sdkListeners": [ + "onMessageReceived", + "onMessageEdited", + "onMessageDeleted", + "onTypingStarted", + "onTypingEnded", + "onMessageReactionAdded", + "onMessageReactionRemoved" + ], + "compositionExample": { + "description": "MessageList is typically used within CometChatMessages alongside MessageHeader and MessageComposer", + "components": ["CometChatMessageHeader", "CometChatMessageList", "CometChatMessageComposer"], + "flow": "User views messages → types in composer → sends message → MessageList updates" + }, + "types": { + "BaseMessage": { + "id": "Int", + "sender": "User?", + "receiver": "AppEntity?", + "sentAt": "Int", + "type": "String", + "category": "String" + }, + "MessageAlignment": { + "standard": "Outgoing messages on right, incoming on left", + "left": "All messages aligned to left" + } + } +} +``` + -## Usage +| Field | Value | +|-------|-------| +| Component | `CometChatMessageList` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | -### Integration +--- -The following code snippet illustrates how you can directly incorporate the MessageList component. +## Where It Fits - - -```swift -// syntax for set(user: User) -messageList.set(user: user) +`CometChatMessageList` is the core component for displaying messages in a chat. It's typically used within `CometChatMessages` alongside `CometChatMessageHeader` and `CometChatMessageComposer`. -// syntax for set(user: User, parentMessage: BaseMessage? = nil) -messageList.set(user: user, parentMessage: textMessage) +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class ChatViewController: UIViewController { + + private var messageList: CometChatMessageList! + + override func viewDidLoad() { + super.viewDidLoad() + setupMessageList() + } + + private func setupMessageList(for user: User) { + messageList = CometChatMessageList() + messageList.set(user: user) + + // Handle thread replies + messageList.set(onThreadRepliesClick: { [weak self] message, template in + self?.openThreadView(for: message) + }) + + // Handle reactions + messageList.set(onReactionClick: { [weak self] reactionCount, message in + guard let message = message else { return } + self?.showReactionDetails(reactionCount, for: message) + }) + + addChild(messageList) + view.addSubview(messageList.view) + messageList.didMove(toParent: self) + } + + private func openThreadView(for message: BaseMessage) { + let threadMessages = CometChatMessages() + threadMessages.set(user: message.sender as? User) + threadMessages.set(parentMessage: message) + navigationController?.pushViewController(threadMessages, animated: true) + } + + private func showReactionDetails(_ reactionCount: ReactionCount, for message: BaseMessage) { + // Show reaction details + } +} ``` - + + CometChatMessageList integrated within a chat view controller showing message bubbles with thread replies and reaction handling + + +--- - +## Minimal Render - +```swift lines +import CometChatUIKitSwift +import CometChatSDK -To retrieve messages for a specific entity, you must associate it with either a `User` or `Group` object. +let messageList = CometChatMessageList() +messageList.set(user: user) +``` - + + CometChatMessageList showing minimal render with default configuration displaying messages for a user conversation + -*** +--- -### Actions +## Filtering -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. +Use `MessagesRequest.MessageRequestBuilder` to filter which messages appear in the list. The builder pattern allows chaining multiple filter conditions. -##### 1. onThreadRepliesClick +```swift lines +import CometChatUIKitSwift +import CometChatSDK -`onThreadRepliesClick` is triggered when you click on the thread indicator of message bubble. The `onThreadRepliesClick` action doesn't have a predefined behavior. You can override this action using the following code snippet. +// Create a custom request builder +let messageRequestBuilder = MessagesRequest.MessageRequestBuilder() + .set(uid: "user-id") + .set(limit: 30) + .set(types: ["text", "image", "video"]) - - -```swift - let messageListView = CometChatMessageList() - messageListView.set(onThreadRepliesClick: { message, template in - // Your action onclick -}) +let messageList = CometChatMessageList() +messageList.set(user: user) +messageList.set(messagesRequestBuilder: messageRequestBuilder) ``` - +### Filter Recipes + +| Recipe | Code | +|--------|------| +| Text messages only | `.set(types: ["text"])` | +| Media messages only | `.set(types: ["image", "video", "audio", "file"])` | +| Search by keyword | `.set(searchKeyword: "hello")` | +| Limit results | `.set(limit: 50)` | +| Messages after timestamp | `.set(timestamp: 1234567890)` | +| Hide deleted messages | `.hideDeletedMessages(true)` | +| Specific categories | `.set(categories: ["message", "custom"])` | + +--- + +## Actions and Events - +### Callback Props -*** +#### onThreadRepliesClick -##### 2. onReactionClick +Fires when a user taps on the thread indicator of a message bubble. -`onReactionClick` is triggered when you click on a reaction on a message bubble. +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let messageList = CometChatMessageList() - - -```swift - let messageListView = CometChatMessageList() - messageListView.set(onReactionClick: { reactionCount, baseMessage in - // Your action onclick +messageList.set(onThreadRepliesClick: { [weak self] message, template in + guard let self = self else { return } + + let threadMessages = CometChatMessages() + if let user = message.sender as? User { + threadMessages.set(user: user) + } + threadMessages.set(parentMessage: message) + self.navigationController?.pushViewController(threadMessages, animated: true) }) ``` - +#### onReactionClick - +Fires when a user taps on a reaction on a message bubble. -*** - -##### 3. onReactionListItemClick +```swift lines +import CometChatUIKitSwift +import CometChatSDK -`onReactionListItemClick` is triggered when you click on the list item of CometChatReactionList on a message bubble. +let messageList = CometChatMessageList() - - -```swift - let messageListView = CometChatMessageList() - messageListView.set(onReactionListItemClick: { messageReaction, baseMessage in - // Your action onclick +messageList.set(onReactionClick: { [weak self] reactionCount, message in + guard let self = self, let message = message else { return } + print("Reaction \(reactionCount.reaction ?? "") tapped on message \(message.id)") }) ``` - +#### onReactionListItemClick - +Fires when a user taps on a specific reaction in the reaction list. -*** - -##### 4. set(onError:) +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatMessageList. +let messageList = CometChatMessageList() - - -```swift -cometChatGroupMembers.set(onError: { error in - // Override on error +messageList.set(onReactionListItemClick: { [weak self] messageReaction, message in + guard let self = self else { return } + print("User \(messageReaction.reactedBy?.name ?? "") reacted with \(messageReaction.reaction)") }) ``` - +#### onError - +Fires when an error occurs while loading messages. -*** - -##### 5. set(onEmpty:) +```swift lines +import CometChatUIKitSwift -This `set(onEmpty:)` method is triggered when the message list is empty in CometChatMessageList. +let messageList = CometChatMessageList() - - -```swift -cometChatMessageList.set(onEmpty: { - // Handle empty state +messageList.set(onError: { error in + print("Error loading messages: \(error.errorDescription)") }) ``` - - - +#### onEmpty -*** +Fires when the message list is empty. -##### 6. setOnLoad +```swift lines +import CometChatUIKitSwift -This set(onLoad:) method is triggered when messages are successfully loaded in CometChatMessageList. +let messageList = CometChatMessageList() - - -```swift -cometChatMessageList.set(onLoad: { messages in - // Handle loaded messages +messageList.set(onEmpty: { + print("No messages found") }) ``` - +#### onLoad - +Fires when messages are successfully loaded. -*** +```swift lines +import CometChatUIKitSwift +import CometChatSDK -### Filters +let messageList = CometChatMessageList() -You can adjust the `MessagesRequestBuilder` in the MessageList Component to customize your message list. Numerous options are available to alter the builder to meet your specific needs. For additional details on `MessagesRequestBuilder`, please visit [MessagesRequestBuilder](/sdk/ios/additional-message-filtering). +messageList.set(onLoad: { messages in + print("Loaded \(messages.count) messages") +}) +``` -In the example below, we are applying a filter to the messages based on a search substring and for a specific user. This means that only messages that contain the search term and are associated with the specified user will be displayed +### Actions Reference + +| Method | Description | Example | +|--------|-------------|---------| +| `set(onThreadRepliesClick:)` | Triggered when thread indicator is tapped | Open thread view | +| `set(onReactionClick:)` | Triggered when a reaction is tapped | Show reaction details | +| `set(onReactionListItemClick:)` | Triggered when reaction list item is tapped | Show who reacted | +| `set(onError:)` | Triggered when an error occurs | Show error alert | +| `set(onEmpty:)` | Triggered when list is empty | Show empty state | +| `set(onLoad:)` | Triggered when messages load | Analytics tracking | +| `scrollToBottom(isAnimated:)` | Scrolls to the bottom of the list | Navigate to latest | +| `goToMessage(withId:)` | Scrolls to a specific message | Jump to message | + +### SDK Events (Real-Time, Automatic) + +| SDK Listener | Internal behavior | +|--------------|-------------------| +| `onMessageReceived` | Adds new message to the list | +| `onMessageEdited` | Updates the edited message in place | +| `onMessageDeleted` | Removes or marks message as deleted | +| `onTypingStarted` | Shows typing indicator | +| `onTypingEnded` | Hides typing indicator | +| `onMessageReactionAdded` | Updates reaction count on message | +| `onMessageReactionRemoved` | Updates reaction count on message | - - -```swift -let messageRequestBuilder = MessagesRequest.MessageRequestBuilder() - .set(uid: "YOUR_UID") - .set(types: ["Text"]) - .set(searchKeyword: "sure") +--- -let cometChatMessages = CometChatMessages() -cometChatMessages.set(user: user) -cometChatMessages.set(messagesRequestBuilder:messageRequestBuilder) -``` +## Data Manipulation Methods - +Programmatically manage messages in the list using these methods. - +### add(message:) - +Adds a new message to the message list. -The following parameters in messageRequestBuilder will always be altered inside the message list +```swift lines +@discardableResult +public func add(message: BaseMessage) -> Self +``` -1. UID -2. GUID -3. types -4. categories +| Parameter | Type | Description | +|-----------|------|-------------| +| `message` | `BaseMessage` | The message to add to the list | - +```swift lines +import CometChatUIKitSwift +import CometChatSDK - +let messageList = CometChatMessageList() -Ensure to include the `uid` and `name` of the User in the implementation. +// Add a message programmatically +let textMessage = TextMessage(receiverUid: "user-id", text: "Hello!", receiverType: .user) +messageList.add(message: textMessage) +``` - +### update(message:) -*** +Updates an existing message in the list. -### Events +```swift lines +@discardableResult +public func update(message: BaseMessage) -> Self +``` -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. +| Parameter | Type | Description | +|-----------|------|-------------| +| `message` | `BaseMessage` | The message with updated content | -The MessageList Component does not emit any events of its own. +```swift lines +import CometChatUIKitSwift +import CometChatSDK -*** +let messageList = CometChatMessageList() -## Customization +// Update a message after editing +if let editedMessage = existingMessage as? TextMessage { + editedMessage.text = "Updated message text" + messageList.update(message: editedMessage) +} +``` -To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. +### remove(message:) -### Style +Removes a message from the list without deleting it from the server. -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +```swift lines +@discardableResult +public func remove(message: BaseMessage) -> Self +``` -##### 1. MessageList Style +| Parameter | Type | Description | +|-----------|------|-------------| +| `message` | `BaseMessage` | The message to remove from the list | -To customize the appearance, you can assign a `MessageListStyle` object to the `MessageList` component +```swift lines +import CometChatUIKitSwift +import CometChatSDK -**Global level styling** +let messageList = CometChatMessageList() - - -```swift -CometChatMessageList.style.backgroundColor = UIColor(hex: "#FBAA75") -CometChatMessageList.messageBubbleStyle.outgoing.backgroundColor = UIColor(hex: "#F76808") +// Remove a message from the UI +messageList.remove(message: messageToRemove) ``` - +### delete(message:) + +Deletes a message from both the list and the server. - +```swift lines +@discardableResult +public func delete(message: BaseMessage) -> Self +``` -**Instance level styling** +| Parameter | Type | Description | +|-----------|------|-------------| +| `message` | `BaseMessage` | The message to delete | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let messageListStyle = MessageListStyle() -messageListStyle.backgroundColor = UIColor(hex: "#FBAA75") - let messageList = CometChatMessageList() -messageList.messageBubbleStyle.outgoing.backgroundColor = UIColor(hex: "#F76808") -messageList.style = messageListStyle + +// Delete a message permanently +messageList.delete(message: messageToDelete) ``` - +### clearList() - +Removes all messages from the list. - - - +```swift lines +@discardableResult +public func clearList() -> Self +``` -List of properties exposed by MessageListStyle - -| **Property** | **Description** | **Code** | -| ------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| **Background Color** | Background color with dynamic support for light and dark mode. | `CometChatMessageList.style.backgroundColor = UIColor.dynamicColor(lightModeColor: ..., darkModeColor: ...)` | -| **Border Width** | Border width for the component. | `CometChatMessageList.style.borderWidth = 0` | -| **Border Color** | Border color for the component. | `CometChatMessageList.style.borderColor = .clear` | -| **Corner Radius** | Corner radius for the component. | `CometChatMessageList.style.cornerRadius = CometChatCornerStyle?` | -| **Shimmer Gradient Color 1** | First color of the shimmer gradient. | `CometChatMessageList.style.shimmerGradientColor1 = CometChatTheme.backgroundColor04` | -| **Shimmer Gradient Color 2** | Second color of the shimmer gradient. | `CometChatMessageList.style.shimmerGradientColor2 = CometChatTheme.backgroundColor03` | -| **Empty State Title Color** | Text color for the title in the empty state. | `CometChatMessageList.style.emptyStateTitleColor = CometChatTheme.textColorPrimary` | -| **Empty State Title Font** | Font for the title in the empty state. | `CometChatMessageList.style.emptyStateTitleFont = CometChatTypography.Heading3.bold` | -| **Empty State Subtitle Color** | Text color for the subtitle in the empty state. | `CometChatMessageList.style.emptyStateSubtitleColor = CometChatTheme.textColorSecondary` | -| **Empty State Subtitle Font** | Font for the subtitle in the empty state. | `CometChatMessageList.style.emptyStateSubtitleFont = CometChatTypography.Body.regular` | -| **Error State Title Color** | Text color for the title in the error state. | `CometChatMessageList.style.errorStateTitleColor = CometChatTheme.textColorPrimary` | -| **Error State Title Font** | Font for the title in the error state. | `CometChatMessageList.style.errorStateTitleFont = CometChatTypography.Heading3.bold` | -| **Error State Subtitle Color** | Text color for the subtitle in the error state. | `CometChatMessageList.style.errorStateSubtitleColor = CometChatTheme.textColorSecondary` | -| **Error State Subtitle Font** | Font for the subtitle in the error state. | `CometChatMessageList.style.errorStateSubtitleFont = CometChatTypography.Body.regular` | -| **Threaded Message Image** | Icon image for threaded messages. | `CometChatMessageList.style.threadedMessageImage = UIImage(systemName: "arrow.turn.down.right")` | -| **Error Image** | Icon image for error state. | `CometChatMessageList.style.errorImage = UIImage(named: "error-icon")` | -| **Empty Image** | Icon image for empty state. | `CometChatMessageList.style.emptyImage = UIImage(named: "empty-icon")` | -| **New Message Indicator Image** | Icon image for new message indicator. | `CometChatMessageList.style.newMessageIndicatorImage = UIImage?` | -| **New Message Indicator Text Color** | Text color for unread messages indicator. | `CometChatMessageList.style.newMessageIndicatorTextColor = UIColor?` | -| **New Message Indicator Text Font** | Text font for unread messages indicator. | `CometChatMessageList.style.newMessageIndicatorTextFont = UIFont?` | -| **New Message Indicator Background Color** | Background color for unread messages indicator. | `CometChatMessageList.style.newMessageIndicatorBackgroundColor = UIColor?` | - - - -*** - -### Functionality - -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. - -Below is a list of customizations along with corresponding code snippets - -| Property | Description | Code | -| ------------------------------- | ------------------------------------------------------------ | ------------------------------------------- | -| hideAvatar | Hides the avatar of the sender. | `hideAvatar = true` | -| hideGroupActionMessages | Hides group action messages (like join/leave notifications). | `hideGroupActionMessages = true` | -| hideReplyInThreadOption | Hides the reply in thread option. | `hideReplyInThreadOption = true` | -| hideTranslateMessageOption | Hides the message translation option. | `hideTranslateMessageOption = true` | -| hideEditMessageOption | Hides the edit message option. | `hideEditMessageOption = true` | -| hideDeleteMessageOption | Hides the delete message option. | `hideDeleteMessageOption = true` | -| hideReactionOption | Hides the reaction option on messages. | `hideReactionOption = true` | -| hideMessagePrivatelyOption | Hides the option to message privately. | `hideMessagePrivatelyOption = true` | -| hideCopyMessageOption | Hides the option to copy a message. | `hideCopyMessageOption = true` | -| hideMessageInfoOption | Hides the message info option. | `hideMessageInfoOption = true` | -| hideHeaderView | Hides the header view of the message list. | `hideHeaderView = true` | -| hideFooterView | Hides the footer view of the message list. | `hideFooterView = true` | -| hideDateSeparator | Hides the date separator between messages. | `hideDateSeparator = true` | -| scrollToBottomOnNewMessages | Scrolls to the bottom when new messages arrive. | `scrollToBottomOnNewMessages = true` | -| hideReceipts | Hides the message read receipts (ticks). | `hideReceipts = true` | -| disableSoundForMessages | Disables the sound when a new message arrives. | `disableSoundForMessages = true` | -| hideEmptyView | Hides the empty state view when no messages are available. | `hideEmptyView = true` | -| hideErrorView | Hides the error view when an error occurs. | `hideErrorView = true` | -| hideLoadingView | Hides the loading view when fetching messages. | `hideLoadingView = true` | -| hideNewMessageIndicator | Hides the "new message" indicator. | `hideNewMessageIndicator = true` | -| scrollToBottom(isAnimated:) | Scrolls to the bottom of the message list. | `scrollToBottom(isAnimated: true)` | -| set(messageAlignment:) | Sets the alignment of messages in the list. | `set(messageAlignment: .left)` | -| set(smartRepliesKeywords:) | Sets keywords for smart replies. | `set(smartRepliesKeywords: ["Hi", "Bye"])` | -| set(smartRepliesDelayDuration:) | Sets the delay duration for smart replies. | `set(smartRepliesDelayDuration: 2)` | -| set(user:parentMessage:) | Sets the user and an optional parent message. | `set(user: user, parentMessage: message)` | -| set(group:parentMessage:) | Sets the group and an optional parent message. | `set(group: group, parentMessage: message)` | -| set(messagesRequestBuilder:) | Sets the message request builder. | `set(messagesRequestBuilder: builder)` | -| set(reactionsRequestBuilder:) | Sets the reactions request builder. | `set(reactionsRequestBuilder: builder)` | -| set(parentMessageId:) | Sets the parent message ID. | `set(parentMessageId: 12345)` | -| hideModerationView | Hides the moderation view in the AI assistant chat. | `hideModerationView = true` | -|hideThreadView | Hides the thread view in the AI assistant chat. | `hideThreadView = true` | -| set(suggestedMessages:) | List of predefined replies shown in the AI assistant. | `suggestedMessages = ["Hello", "Hi"]` | -| hideSuggestedMessages | Hides the suggested message replies. | `hideSuggestedMessages = true` | -| set(emptyChatGreetingView:) | Custom view displayed when the AI assistant chat is empty. | `emptyChatGreetingView = { /* custom view */ }` | -| set(streamingSpeed:) | Sets the speed of streaming for AI assistant messages. | `streamingSpeed = 50` | -| goToMessage(withId:) | Scrolls the message list to a specific message, making it visible to the user based on the provided message ID | `goToMessage(messageId: Int)` | -| startFromUnreadMessages | Starts the message list from the first unread message.. | `startFromUnreadMessages = true` | -| showMarkAsUnreadOption | Sets the visibility of the “Mark as unread” option in the message actions menu. | `showMarkAsUnreadOption = true` | - - -*** - -### Advance - -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. - -#### Date Time Formatter - -The **CometChatMessageList** component supports full customization of how date and time are displayed using the [CometChatDateTimeFormatter](/ui-kit/ios/localize#datetimeformatter). - -This enables developers to localize, format, or personalize the date and time strings shown next to each message such as “Today”, “Yesterday”, “12:45 PM”, etc. - -1. Component-Level (Global) - - - -```swift -CometChatMessageList.dateTimeFormatter.time = { timestamp in - return "at " + DateFormatter.localizedString(from: Date(timeIntervalSince1970: TimeInterval(timestamp)), dateStyle: .none, timeStyle: .short) -} +```swift lines +import CometChatUIKitSwift -CometChatMessageList.dateTimeFormatter.today = { timestamp in - return "Today • \(formattedTime(from: timestamp))" -} +let messageList = CometChatMessageList() -CometChatMessageList.dateTimeFormatter.otherDay = { timestamp in // This will display older dates as "24 Apr 2025" instead of the default relative format. - let formatter = DateFormatter() - formatter.dateFormat = "dd MMM yyyy" - return formatter.string(from: Date(timeIntervalSince1970: TimeInterval(timestamp))) -} +// Clear all messages from the list +messageList.clearList() ``` - +### isEmpty() - +Checks if the message list is empty. -2. Instance-Level (Local) +```swift lines +public func isEmpty() -> Bool +``` + +```swift lines +import CometChatUIKitSwift - - -```swift let messageList = CometChatMessageList() -messageList.dateTimeFormatter.yesterday = { timestamp in - return "Yesterday at " + formattedTime(from: timestamp) + +// Check if list is empty +if messageList.isEmpty() { + print("No messages in the list") } ``` - +--- - +## Connection Management -##### Available closures +Manually control the WebSocket connection for the message list. -| Property | Description | Code | -| --------- | ------------------------------------------------------------------- | ------------------------------------------------------------ | -| time | Called to format a timestamp as a standard time (e.g., "12:30 PM"). | `CometChatMessageList.dateTimeFormatter.time = { ... }` | -| today | Called when rendering messages sent today. | `CometChatMessageList.dateTimeFormatter.today = { ... }` | -| yesterday | Called for yesterday's messages. | `CometChatMessageList.dateTimeFormatter.yesterday = { ... }` | -| lastweek | Called for messages within the last week. | `CometChatMessageList.dateTimeFormatter.lastweek = { ... }` | -| otherDay | Called for dates older than last week. | `CometChatMessageList.dateTimeFormatter.otherDay = { ... }` | -| minute | Called when referring to "a minute ago". | `CometChatMessageList.dateTimeFormatter.minute = { ... }` | -| minutes | Called for "x minutes ago". | `CometChatMessageList.dateTimeFormatter.minutes = { ... }` | -| hour | Called for "an hour ago". | `CometChatMessageList.dateTimeFormatter.hour = { ... }` | -| hours | Called for "x hours ago". | `CometChatMessageList.dateTimeFormatter.hours = { ... }` | +### connect() -Each closure receives a timestamp (Int, representing UNIX time) and must return a String representing the formatted time. +Establishes the WebSocket connection for real-time updates. Use this when you need to manually reconnect after disconnecting. -*** +```swift lines +@discardableResult +public func connect() -> Self +``` -#### SetHeaderView +```swift lines +import CometChatUIKitSwift -You can set custom headerView to the Message List component using the following method. +let messageList = CometChatMessageList() - - -```swift -let messageListView = CometChatMessageList() -messageListView.set(headerView: CustomHeaderView) +// Manually connect to receive real-time updates +messageList.connect() ``` - +### disconnect() - +Disconnects the WebSocket connection. Use this when you want to temporarily stop receiving real-time updates, such as when the view is not visible. - - - - -Following is the code of CustomHeaderView - UIView Class +```swift lines +@discardableResult +public func disconnect() -> Self +``` -```swift -import UIKit +```swift lines +import CometChatUIKitSwift -class CustomHeaderView: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { - - private var collectionData: [CollectionItem] = [ - CollectionItem(title: "Notes", icon: UIImage(systemName: "doc.text.fill")), - CollectionItem(title: "Pinned Messages", icon: UIImage(systemName: "bookmark.fill")), - CollectionItem(title: "Saved Links", icon: UIImage(systemName: "link")) - ] - - private lazy var collectionView: UICollectionView = { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - layout.minimumInteritemSpacing = 10 - layout.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10) - - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.register(CustomHeaderViewCell.self, forCellWithReuseIdentifier: CustomHeaderViewCell.identifier) - collectionView.backgroundColor = .clear - collectionView.showsHorizontalScrollIndicator = false - collectionView.delegate = self - collectionView.dataSource = self - collectionView.tag = 1 - return collectionView - }() - - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = UIColor(white: 0.95, alpha: 1) - setupUI() - } - - private func setupUI() { - view.addSubview(collectionView) - - collectionView.translatesAutoresizingMaskIntoConstraints = false - - NSLayoutConstraint.activate([ - collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), - collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 10) - ]) - } - - // MARK: - UICollectionView DataSource & Delegate - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return collectionData.count - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomHeaderViewCell.identifier, for: indexPath) as? CustomHeaderViewCell else { - return UICollectionViewCell() - } - - cell.configure(with: collectionData[indexPath.row]) - return cell - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - return CGSize(width: 150, height: 40) - } -} +let messageList = CometChatMessageList() -struct CollectionItem { - let title: String - let icon: UIImage? +// Disconnect when view disappears +override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + messageList.disconnect() } -class CustomHeaderViewCell: UICollectionViewCell { - - static let identifier = "CustomCollectionViewCell" - - private let iconImageView: UIImageView = { - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFit - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.font = UIFont.systemFont(ofSize: 14, weight: .medium) - label.textColor = UIColor.purple - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - backgroundColor = UIColor(white: 0.95, alpha: 1) // Light purple background - layer.cornerRadius = 18 - clipsToBounds = true - - addSubview(iconImageView) - addSubview(titleLabel) - - NSLayoutConstraint.activate([ - iconImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), - iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - iconImageView.widthAnchor.constraint(equalToConstant: 20), - iconImageView.heightAnchor.constraint(equalToConstant: 20), - - titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 5), - titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), - titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor) - ]) - } - - func configure(with model: CollectionItem) { - iconImageView.image = model.icon - titleLabel.text = model.title - } +// Reconnect when view appears +override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + messageList.connect() } ``` -*** +--- + +## Custom View Slots + +| Slot | Signature | Replaces | +|------|-----------|----------| +| `headerView` | `UIView` | Header above message list | +| `footerView` | `UIView` | Footer below message list | +| `emptyView` | `UIView` | Empty state display | +| `errorView` | `UIView` | Error state display | +| `loadingView` | `UIView` | Loading state display | +| `newMessageIndicatorView` | `UIView` | New message indicator | + +### set(headerView:) + +Replaces the default header with a custom view. + +| | | +|---|---| +| Signature | `(UIView) -> Self` | +| Replaces | Default header above message list | + +```swift lines +import UIKit +import CometChatUIKitSwift -#### SetFooterView +let messageList = CometChatMessageList() -You can set custom footerView to the Message List component using the following method. +let headerView = UIView() +headerView.backgroundColor = UIColor.systemGray6 -Example +let label = UILabel() +label.text = "Pinned Messages" +label.font = UIFont.systemFont(ofSize: 14, weight: .medium) +label.textColor = UIColor.secondaryLabel +headerView.addSubview(label) - - -```swift -let messageListView = CometChatMessageList(frame: .null) -messageListView.set(footerView: CustomFooterView) +messageList.set(headerView: headerView) ``` - +{/* TODO: Add screenshot showing headerView customization */} - +### set(footerView:) - - - +Replaces the default footer with a custom view. -Following is the code of CustomFooterView UIView Class +| | | +|---|---| +| Signature | `(UIView) -> Self` | +| Replaces | Default footer below message list | -```swift +```swift lines import UIKit +import CometChatUIKitSwift -class CustomFooterView: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { - - private var collectionData: [CollectionItem] = [ - CollectionItem(title: "Ice Breakers", icon: UIImage(systemName: "sun.max.fill")), - CollectionItem(title: "+1-212-456-7890", icon: UIImage(systemName: "phone.fill")), - CollectionItem(title: "+ Instagram", icon: UIImage(systemName: "camera.fill")) - ] - - private lazy var collectionView: UICollectionView = { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - layout.minimumInteritemSpacing = 10 - layout.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10) - - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.register(CustomFooterViewCell.self, forCellWithReuseIdentifier: CustomFooterViewCell.identifier) - collectionView.backgroundColor = .clear - collectionView.showsHorizontalScrollIndicator = false - collectionView.delegate = self - collectionView.dataSource = self - collectionView.tag = 1 - return collectionView - }() - - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = UIColor(white: 0.95, alpha: 1) - setupUI() - } - - private func setupUI() { - view.addSubview(collectionView) - - collectionView.translatesAutoresizingMaskIntoConstraints = false - - NSLayoutConstraint.activate([ - collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), - collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 10) - ]) - } - - // MARK: - UICollectionView DataSource & Delegate - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return collectionData.count - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomFooterViewCell.identifier, for: indexPath) as? CustomFooterViewCell else { - return UICollectionViewCell() - } - - cell.configure(with: collectionData[indexPath.row]) - return cell - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - return CGSize(width: 150, height: 40) - } -} +let messageList = CometChatMessageList() -struct CollectionItem { - let title: String - let icon: UIImage? -} +let footerView = UIView() +footerView.backgroundColor = UIColor.systemGray6 -class CustomFooterViewCell: UICollectionViewCell { - - static let identifier = "CustomCollectionViewCell" - - private let iconImageView: UIImageView = { - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFit - imageView.translatesAutoresizingMaskIntoConstraints = false - return imageView - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.font = UIFont.systemFont(ofSize: 14, weight: .medium) - label.textColor = UIColor.purple - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - backgroundColor = UIColor(white: 0.95, alpha: 1) // Light purple background - layer.cornerRadius = 18 - clipsToBounds = true - - addSubview(iconImageView) - addSubview(titleLabel) - - NSLayoutConstraint.activate([ - iconImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), - iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - iconImageView.widthAnchor.constraint(equalToConstant: 20), - iconImageView.heightAnchor.constraint(equalToConstant: 20), - - titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 5), - titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), - titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor) - ]) - } - - func configure(with model: CollectionItem) { - iconImageView.image = model.icon - titleLabel.text = model.title - } +let quickRepliesStack = UIStackView() +quickRepliesStack.axis = .horizontal +quickRepliesStack.spacing = 8 + +let replies = ["👍", "Thanks!", "Got it"] +for reply in replies { + let button = UIButton(type: .system) + button.setTitle(reply, for: .normal) + button.backgroundColor = UIColor.systemBackground + button.layer.cornerRadius = 16 + quickRepliesStack.addArrangedSubview(button) } + +footerView.addSubview(quickRepliesStack) +messageList.set(footerView: footerView) ``` -*** +{/* TODO: Add screenshot showing footerView customization */} -#### SetDateSeparatorPattern +### set(emptyView:) -You can modify the date pattern of the message list date separator to your requirement using `setDateSeparatorPattern()`. This method accepts a function with a return type String. Inside the function, you can create your own pattern and return it as a String. +Replaces the default empty state view with a custom view. -**Example** +| | | +|---|---| +| Signature | `(UIView) -> Self` | +| Replaces | Default empty state when no messages exist | - - -```swift -let messageListView = CometChatMessageList() -.set(user: user) -messageListView.set(dateSeparatorPattern: { timestamp in - guard let timestamp = timestamp else { - return "" - } - let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) - let formatter = DateFormatter() - formatter.dateFormat = "hh:mm MM/yyyy" - return formatter.string(from: date) -}) -``` +```swift lines +import UIKit +import CometChatUIKitSwift - +let messageList = CometChatMessageList() - +let emptyView = UIView() +let imageView = UIImageView(image: UIImage(systemName: "bubble.left.and.bubble.right")) +imageView.tintColor = UIColor.tertiaryLabel - +let label = UILabel() +label.text = "No messages yet. Start the conversation!" +label.textColor = UIColor.secondaryLabel +label.textAlignment = .center -Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. +emptyView.addSubview(imageView) +emptyView.addSubview(label) - +messageList.set(emptyView: emptyView) +``` -*** +### set(errorView:) -#### SetDatePattern +Replaces the default error state view with a custom view. -You can modify the date pattern to your requirement using .set(datePattern:). This method accepts a function with a return type String. Inside the function, you can create your own pattern and return it as a String. +| | | +|---|---| +| Signature | `(UIView) -> Self` | +| Replaces | Default error state when loading fails | -**Example** +```swift lines +import UIKit +import CometChatUIKitSwift - - -```swift -let messageListView = CometChatMessageList() -messageListView.set(datePattern: { timestamp in - guard let timestamp = timestamp else { - return "" - } - let date = Date(timeIntervalSince1970: TimeInterval(timestamp/1000)) - let formatter = DateFormatter() - formatter.dateFormat = "dd-MM-yyyy" - return formatter.string(from: date) -}) +let messageList = CometChatMessageList() + +let errorView = UIView() +let errorLabel = UILabel() +errorLabel.text = "Something went wrong!" +errorLabel.textColor = .red +errorLabel.textAlignment = .center + +let retryButton = UIButton(type: .system) +retryButton.setTitle("Retry", for: .normal) + +errorView.addSubview(errorLabel) +errorView.addSubview(retryButton) + +messageList.set(errorView: errorView) ``` - +### set(loadingView:) - +Replaces the default loading indicator with a custom view. -*** +| | | +|---|---| +| Signature | `(UIView) -> Self` | +| Replaces | Default loading indicator | -#### SetTimePattern +```swift lines +import UIKit +import CometChatUIKitSwift -You can modify the date pattern to your requirement using `.set(timePattern:)`. This method accepts a function with a return type String. Inside the function, you can create your own pattern and return it as a String. +let messageList = CometChatMessageList() -**Example** +let loadingView = UIActivityIndicatorView(style: .large) +loadingView.color = UIColor.systemBlue +loadingView.startAnimating() - - -```swift -let messageListView = CometChatMessageList() -messageListView.set(timePattern: { timestamp in - let time = Date(timeIntervalSince1970: TimeInterval(timestamp)) - let formatter = DateFormatter() - formatter.dateFormat = "HH:mm" - return formatter.string(from: time) -}) +messageList.set(loadingView: loadingView) ``` - +### set(newMessageIndicatorView:) - +Replaces the default new message indicator with a custom view. -*** +| | | +|---|---| +| Signature | `(UIView) -> Self` | +| Replaces | Default new message indicator | + +```swift lines +import UIKit +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let newMessageIndicatorView = NewUnreadMessageIndicator() +messageList.set(newMessageIndicatorView: newMessageIndicatorView) + +class NewUnreadMessageIndicator: UIView { + + private let label: UILabel = { + let label = UILabel() + label.text = "New Messages ↓" + label.textColor = .white + label.font = UIFont.systemFont(ofSize: 14, weight: .medium) + label.textAlignment = .center + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = UIColor.systemBlue + layer.cornerRadius = 16 + + addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: centerXAnchor), + label.centerYAnchor.constraint(equalTo: centerYAnchor) + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} +``` -#### SetTextFormatters +--- -This functionality dynamically assigns a list of text formatters. If a custom list is provided, it uses that list. Otherwise, it gracefully falls back to the default text formatters retrieved from the data source for seamless integration. +## Text Formatters -**Example** +Customize how text is displayed in messages using text formatters. -This code customizes a CometChat text formatter to identify and style the word "sure", with handling options for interactions like string search, scrolling, and item clicks. The custom formatter is then applied to CometChat messages. +```swift lines +import CometChatUIKitSwift +import CometChatSDK -```ruby Swift let myCustomTextFormatter = MyCustomTextFormatter(trackingCharacter: "#") -let cometChatMessages = CometChatMessages() +let cometChatMessages = CometChatMessages() .set(user: user) .set(textFormatter: [myCustomTextFormatter]) ``` -Demonstration: +### set(textFormatters:) + +Sets custom text formatters for message text display. + +```swift lines +@discardableResult +public func set(textFormatters: [CometChatTextFormatter]) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `textFormatters` | `[CometChatTextFormatter]` | Array of text formatters to apply | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let hashtagFormatter = HashtagTextFormatter(trackingCharacter: "#") +let mentionFormatter = MentionTextFormatter(trackingCharacter: "@") + +messageList.set(textFormatters: [hashtagFormatter, mentionFormatter]) +``` + +### setMentionAllLabel(_:_:) + +Customizes the label displayed for @all mentions. + +```swift lines +@discardableResult +public func setMentionAllLabel(_ title: String, _ subtitle: String) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `title` | `String` | The title for the @all mention | +| `subtitle` | `String` | The subtitle for the @all mention | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +// Customize the @all mention label +messageList.setMentionAllLabel("Everyone", "Notify all members") +``` - - -```swift +You can create a custom text formatter: +```swift lines import Foundation import CometChatSDK import CometChatUIKitSwift class MyCustomTextFormatter: CometChatTextFormatter { -override func getRegex() -> String { -return "(\\bsure\\b)" - + + override func getRegex() -> String { + return "(\\bsure\\b)" } override func getTrackingCharacter() -> Character { @@ -825,33 +841,32 @@ return "(\\bsure\\b)" override func search(string: String, suggestedItems: ((_: [SuggestionItem]) -> ())? = nil) { // This function would call an API or perform a local search - // For now, it does nothing } override func onScrollToBottom(suggestionItemList: [SuggestionItem], listItem: ((_: [SuggestionItem]) -> ())?) { // This function would call the next page of an API - // For now, it does nothing } override func onItemClick(suggestedItem: SuggestionItem, user: User?, group: Group?) { - // Do something with the clicked item + // Handle clicked item } override func handlePreMessageSend(baseMessage: BaseMessage, suggestionItemList: [SuggestionItem]) { - // This function would modify the message before it's sent - // For now, it does nothing + // Modify the message before it's sent } override func prepareMessageString( - baseMessage: BaseMessage, - regexString: String, - alignment: MessageBubbleAlignment = .left, - formattingType: FormattingType + baseMessage: BaseMessage, + regexString: String, + alignment: MessageBubbleAlignment = .left, + formattingType: FormattingType ) -> NSAttributedString { let attrString = NSMutableAttributedString(string: "SURE") - if alignment == .left { // Received message + if alignment == .left { + // Received message styling attrString.addAttribute(.foregroundColor, value: UIColor.blue, range: NSRange(location: 0, length: attrString.length)) - } else { // Sent message + } else { + // Sent message styling attrString.addAttribute(.foregroundColor, value: UIColor.green, range: NSRange(location: 0, length: attrString.length)) } attrString.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: attrString.length)) @@ -859,119 +874,1169 @@ return "(\\bsure\\b)" } override func onTextTapped(baseMessage: BaseMessage, tappedText: String, controller: UIViewController?) { - // Your Action + // Handle text tap action } - } ``` - +--- + +## AI Features + +Configure AI-powered features for the message list. + +### enableSmartReplies - +Enables AI-powered smart reply suggestions. -*** +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -#### SetTemplate and AddTemplate +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.enableSmartReplies = true +``` -[CometChatMessageTemplate](/ui-kit/ios/message-template) is a pre-defined structure for creating message views that can be used as a starting point or blueprint for creating message views often known as message bubbles. For more information, you can refer to [CometChatMessageTemplate](/ui-kit/ios/message-template). +### enableConversationStarters -*** +Enables AI-powered conversation starter suggestions. -#### SetLoadingView +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | -You can set a custom loading view using .set(loadingView:). This method accepts a UIView to display while data is being fetched. +```swift lines +import CometChatUIKitSwift - - -```swift -let loadingIndicator = UIActivityIndicatorView(style: .medium) -loadingIndicator.startAnimating() -cometChatMessageList.set(loadingView: loadingIndicator) +let messageList = CometChatMessageList() +messageList.enableConversationStarters = true ``` - +### enableConversationSummary + +Enables AI-powered conversation summary feature. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - +```swift lines +import CometChatUIKitSwift -*** +let messageList = CometChatMessageList() +messageList.enableConversationSummary = true +``` -#### SetErrorView +### set(smartRepliesKeywords:) -You can customize the error view using .set(errorView:). This method accepts a UIView that appears when an error occurs. +Sets keywords that trigger smart reply suggestions. - - -```swift -let errorLabel = UILabel() -errorLabel.text = "Something went wrong!" -errorLabel.textColor = .red -cometChatMessageList.set(errorView: errorLabel) +```swift lines +@discardableResult +public func set(smartRepliesKeywords: [String]) -> Self ``` - +| Parameter | Type | Description | +|-----------|------|-------------| +| `smartRepliesKeywords` | `[String]` | Keywords that trigger smart replies | + +```swift lines +import CometChatUIKitSwift - +let messageList = CometChatMessageList() -*** +// Set keywords that trigger smart replies +messageList.set(smartRepliesKeywords: ["help", "question", "support"]) +``` -#### SetEmptyView +### set(smartRepliesDelayDuration:) -You can customize the empty state view using .set(emptyView:). This method accepts a UIView that appears when no conversations are available. +Sets the delay duration before showing smart reply suggestions. - - -```swift -let emptyLabel = UILabel() -emptyLabel.text = "No conversations found" -emptyLabel.textColor = .gray -emptyLabel.textAlignment = .center -cometChatMessageList.set(emptyView: emptyLabel) +```swift lines +@discardableResult +public func set(smartRepliesDelayDuration: TimeInterval) -> Self ``` - +| Parameter | Type | Description | +|-----------|------|-------------| +| `smartRepliesDelayDuration` | `TimeInterval` | Delay in seconds before showing suggestions | - +```swift lines +import CometChatUIKitSwift -*** +let messageList = CometChatMessageList() -#### SetNewMessageIndicatorView +// Set a 2-second delay before showing smart replies +messageList.set(smartRepliesDelayDuration: 2.0) +``` -Set a custom view for the unread message indicator. +--- - - -```swift -let newMessageIndicatorView = NewUnreadMessageIndicator() -cometChatMessageList.set(newMessageIndicatorView:: newMessageIndicatorView) +## Reactions Configuration -class NewUnreadMessageIndicator: UIView { - // Your custom view -} +Configure how reactions are displayed and behave in the message list. + +### reactionsConfiguration + +Configuration object for the reactions feature. + +| | | +|---|---| +| Type | `ReactionsConfiguration` | +| Default | `ReactionsConfiguration()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let reactionsConfig = ReactionsConfiguration() +reactionsConfig.reactionLimit = 5 +reactionsConfig.showReactionCount = true + +messageList.reactionsConfiguration = reactionsConfig +``` + +### reactionListConfiguration + +Configuration object for the reaction list display. + +| | | +|---|---| +| Type | `ReactionListConfiguration` | +| Default | `ReactionListConfiguration()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let reactionListConfig = ReactionListConfiguration() +reactionListConfig.showUserNames = true + +messageList.reactionListConfiguration = reactionListConfig +``` + +### quickReactionsConfiguration + +Configuration object for quick reactions. + +| | | +|---|---| +| Type | `QuickReactionsConfiguration` | +| Default | `QuickReactionsConfiguration()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let quickReactionsConfig = QuickReactionsConfiguration() +quickReactionsConfig.quickReactions = ["👍", "❤️", "😂", "😮", "😢"] + +messageList.quickReactionsConfiguration = quickReactionsConfig +``` + +### messageInformationConfiguration + +Configuration object for message information display. + +| | | +|---|---| +| Type | `MessageInformationConfiguration` | +| Default | `MessageInformationConfiguration()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let messageInfoConfig = MessageInformationConfiguration() +messageInfoConfig.showReadReceipts = true +messageInfoConfig.showDeliveryReceipts = true + +messageList.messageInformationConfiguration = messageInfoConfig +``` + +--- + +## Styling + +### Style Hierarchy + +1. Global styles (`CometChatMessageList.style`) apply to all instances +2. Instance styles override global for specific instances + +### Global Level Styling + +```swift lines +import UIKit +import CometChatUIKitSwift + +// Apply global styles that affect all CometChatMessageList instances +CometChatMessageList.style.backgroundColor = UIColor.systemBackground +CometChatMessageList.style.emptyStateTitleColor = UIColor.label +CometChatMessageList.style.emptyStateTitleFont = UIFont.systemFont(ofSize: 20, weight: .bold) +CometChatMessageList.style.emptyStateSubtitleColor = UIColor.secondaryLabel + +// Customize message bubble styles +CometChatMessageList.messageBubbleStyle.outgoing.backgroundColor = UIColor.systemBlue +CometChatMessageList.messageBubbleStyle.incoming.backgroundColor = UIColor.systemGray5 +``` + +### Instance Level Styling + +```swift lines +import UIKit +import CometChatUIKitSwift + +// Create a custom style for a specific instance +let messageListStyle = MessageListStyle() +messageListStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +messageListStyle.borderWidth = 0 +messageListStyle.borderColor = .clear + +let messageList = CometChatMessageList() +messageList.style = messageListStyle +``` + + + CometChatMessageList with custom styling applied showing modified background color and message bubble appearance + + +### Key Style Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `backgroundColor` | `UIColor` | `CometChatTheme.backgroundColor01` | Background color of the list | +| `borderWidth` | `CGFloat` | `0` | Border width for the component | +| `borderColor` | `UIColor` | `.clear` | Border color for the component | +| `cornerRadius` | `CometChatCornerStyle?` | `nil` | Corner radius for the component | +| `shimmerGradientColor1` | `UIColor` | `CometChatTheme.backgroundColor04` | First shimmer gradient color | +| `shimmerGradientColor2` | `UIColor` | `CometChatTheme.backgroundColor03` | Second shimmer gradient color | +| `emptyStateTitleColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Empty state title color | +| `emptyStateTitleFont` | `UIFont` | `CometChatTypography.Heading3.bold` | Empty state title font | +| `emptyStateSubtitleColor` | `UIColor` | `CometChatTheme.textColorSecondary` | Empty state subtitle color | +| `emptyStateSubtitleFont` | `UIFont` | `CometChatTypography.Body.regular` | Empty state subtitle font | +| `errorStateTitleColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Error state title color | +| `errorStateTitleFont` | `UIFont` | `CometChatTypography.Heading3.bold` | Error state title font | +| `newMessageIndicatorTextColor` | `UIColor?` | `nil` | New message indicator text color | +| `newMessageIndicatorBackgroundColor` | `UIColor?` | `nil` | New message indicator background | + +### Style Properties + +#### emojiKeyboardStyle + +Customizes the appearance of the emoji keyboard. + +| | | +|---|---| +| Type | `EmojiKeyboardStyle` | +| Default | `EmojiKeyboardStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let emojiKeyboardStyle = EmojiKeyboardStyle() +emojiKeyboardStyle.backgroundColor = UIColor.systemBackground +emojiKeyboardStyle.borderColor = UIColor.systemGray4 + +messageList.emojiKeyboardStyle = emojiKeyboardStyle +``` + +#### dateSeparatorStyle + +Customizes the appearance of date separators between messages. + +| | | +|---|---| +| Type | `DateSeparatorStyle` | +| Default | `DateSeparatorStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let dateSeparatorStyle = DateSeparatorStyle() +dateSeparatorStyle.textColor = UIColor.secondaryLabel +dateSeparatorStyle.textFont = UIFont.systemFont(ofSize: 12, weight: .medium) +dateSeparatorStyle.backgroundColor = UIColor.systemGray6 + +messageList.dateSeparatorStyle = dateSeparatorStyle +``` + +#### newMessageIndicatorStyle + +Customizes the appearance of the new message indicator. + +| | | +|---|---| +| Type | `NewMessageIndicatorStyle` | +| Default | `NewMessageIndicatorStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let newMessageIndicatorStyle = NewMessageIndicatorStyle() +newMessageIndicatorStyle.textColor = UIColor.white +newMessageIndicatorStyle.backgroundColor = UIColor.systemBlue +newMessageIndicatorStyle.cornerRadius = 16 + +messageList.newMessageIndicatorStyle = newMessageIndicatorStyle +``` + +#### messageBubbleStyle + +Customizes the appearance of message bubbles. + +| | | +|---|---| +| Type | `MessageBubbleStyle` | +| Default | `MessageBubbleStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let messageBubbleStyle = MessageBubbleStyle() +messageBubbleStyle.outgoing.backgroundColor = UIColor.systemBlue +messageBubbleStyle.incoming.backgroundColor = UIColor.systemGray5 +messageBubbleStyle.outgoing.textColor = UIColor.white +messageBubbleStyle.incoming.textColor = UIColor.label + +messageList.messageBubbleStyle = messageBubbleStyle +``` + +#### actionBubbleStyle + +Customizes the appearance of action message bubbles (e.g., group actions). + +| | | +|---|---| +| Type | `ActionBubbleStyle` | +| Default | `ActionBubbleStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let actionBubbleStyle = ActionBubbleStyle() +actionBubbleStyle.backgroundColor = UIColor.systemGray6 +actionBubbleStyle.textColor = UIColor.secondaryLabel +actionBubbleStyle.textFont = UIFont.systemFont(ofSize: 13, weight: .regular) + +messageList.actionBubbleStyle = actionBubbleStyle +``` + +#### callActionBubbleStyle + +Customizes the appearance of call action message bubbles. + +| | | +|---|---| +| Type | `CallActionBubbleStyle` | +| Default | `CallActionBubbleStyle()` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +let callActionBubbleStyle = CallActionBubbleStyle() +callActionBubbleStyle.backgroundColor = UIColor.systemGreen.withAlphaComponent(0.1) +callActionBubbleStyle.iconTintColor = UIColor.systemGreen +callActionBubbleStyle.textColor = UIColor.label + +messageList.callActionBubbleStyle = callActionBubbleStyle +``` + +### Customization Matrix + +| What to change | Where | Property/API | Example | +|----------------|-------|--------------|---------| +| Background color | Style | `backgroundColor` | `UIColor.systemBackground` | +| Empty state text | Style | `emptyStateTitleColor`, `emptyStateTitleFont` | Custom colors and fonts | +| Error state text | Style | `errorStateTitleColor`, `errorStateTitleFont` | Custom colors and fonts | +| Loading shimmer | Style | `shimmerGradientColor1`, `shimmerGradientColor2` | Custom gradient colors | +| Outgoing bubble | Style | `messageBubbleStyle.outgoing` | `UIColor.systemBlue` | +| Incoming bubble | Style | `messageBubbleStyle.incoming` | `UIColor.systemGray5` | +| Hide avatars | Property | `hideAvatar` | `messageList.hideAvatar = true` | +| Hide receipts | Property | `hideReceipts` | `messageList.hideReceipts = true` | +| Custom header | View Slot | `set(headerView:)` | See Custom View Slots section | + +--- + +## Props + +All props are optional. Sorted alphabetically. + +### actionBubbleStyle + +Customizes the appearance of action message bubbles. + +| | | +|---|---| +| Type | `ActionBubbleStyle` | +| Default | `ActionBubbleStyle()` | + +### callActionBubbleStyle + +Customizes the appearance of call action message bubbles. + +| | | +|---|---| +| Type | `CallActionBubbleStyle` | +| Default | `CallActionBubbleStyle()` | + +### dateSeparatorStyle + +Customizes the appearance of date separators. + +| | | +|---|---| +| Type | `DateSeparatorStyle` | +| Default | `DateSeparatorStyle()` | + +### disableSoundForMessages + +Disables notification sounds for new messages. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### disableSwipeToReply + +Disables the swipe-to-reply gesture on messages. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.disableSwipeToReply = true ``` - +### emojiKeyboardStyle + +Customizes the appearance of the emoji keyboard. + +| | | +|---|---| +| Type | `EmojiKeyboardStyle` | +| Default | `EmojiKeyboardStyle()` | + +### emptySubtitleText + +Custom subtitle text for the empty state view. - +| | | +|---|---| +| Type | `String` | +| Default | `""` | -*** +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.emptySubtitleText = "Send a message to start the conversation" +``` - +### emptyTitleText -To ensure that the `MessageList` is properly configured, passing the controller is mandatory. +Custom title text for the empty state view. -* Swift +| | | +|---|---| +| Type | `String` | +| Default | `"No Messages"` | -```swift -let messageListView = CometChatMessageList() -messageListView.set(controller: UIViewController) // Passing the controller is required +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.emptyTitleText = "No messages yet" ``` - +### enableConversationStarters + +Enables AI-powered conversation starter suggestions. -*** +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | - +### enableConversationSummary + +Enables AI-powered conversation summary feature. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### enableSmartReplies + +Enables AI-powered smart reply suggestions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### errorSubtitleText + +Custom subtitle text for the error state view. + +| | | +|---|---| +| Type | `String` | +| Default | `""` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.errorSubtitleText = "Please check your connection and try again" +``` + +### errorTitleText + +Custom title text for the error state view. + +| | | +|---|---| +| Type | `String` | +| Default | `"Something went wrong"` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.errorTitleText = "Unable to load messages" +``` + +### hideAvatar + +Hides the sender's avatar in message bubbles. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideBubbleHeader + +Hides the header section of message bubbles (sender name, timestamp). + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.hideBubbleHeader = true +``` + +### hideCopyMessageOption + +Hides the copy message option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideDateSeparator + +Hides the date separator between messages. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideDeleteMessageOption + +Hides the delete message option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideEditMessageOption + +Hides the edit message option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideEmptyView + +Hides the empty state view when no messages are available. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideErrorView + +Hides the error view when an error occurs. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideFlagMessageOption + +Hides the flag/report message option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.hideFlagMessageOption = true +``` + +### hideFooterView + +Hides the footer view of the message list. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideGroupActionMessages + +Hides group action messages (join/leave notifications). + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideHeaderView + +Hides the header view of the message list. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideLoadingView + +Hides the loading view when fetching messages. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideMessageInfoOption + +Hides the message info option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideMessagePrivatelyOption + +Hides the option to message privately. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideNewMessageIndicator + +Hides the new message indicator. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideReactionOption + +Hides the reaction option on messages. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideReceipts + +Hides message read receipts (ticks). + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideReplyInThreadOption + +Hides the reply in thread option. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideReplyMessageOption + +Hides the reply to message option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.hideReplyMessageOption = true +``` + +### hideShareMessageOption + +Hides the share message option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() +messageList.hideShareMessageOption = true +``` + +### hideTranslateMessageOption + +Hides the message translation option. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### messageAlignment + +Sets the alignment of messages in the list. + +| | | +|---|---| +| Type | `MessageAlignment` | +| Default | `.standard` | + +### messageBubbleStyle + +Customizes the appearance of message bubbles. + +| | | +|---|---| +| Type | `MessageBubbleStyle` | +| Default | `MessageBubbleStyle()` | + +### messageInformationConfiguration + +Configuration object for message information display. + +| | | +|---|---| +| Type | `MessageInformationConfiguration` | +| Default | `MessageInformationConfiguration()` | + +### messagesRequestBuilder + +Custom request builder for filtering messages. + +| | | +|---|---| +| Type | `MessagesRequest.MessageRequestBuilder?` | +| Default | `nil` | + +### newMessageIndicatorStyle + +Customizes the appearance of the new message indicator. + +| | | +|---|---| +| Type | `NewMessageIndicatorStyle` | +| Default | `NewMessageIndicatorStyle()` | + +### quickReactionsConfiguration + +Configuration object for quick reactions. + +| | | +|---|---| +| Type | `QuickReactionsConfiguration` | +| Default | `QuickReactionsConfiguration()` | + +### reactionsConfiguration + +Configuration object for the reactions feature. + +| | | +|---|---| +| Type | `ReactionsConfiguration` | +| Default | `ReactionsConfiguration()` | + +### reactionListConfiguration + +Configuration object for the reaction list display. + +| | | +|---|---| +| Type | `ReactionListConfiguration` | +| Default | `ReactionListConfiguration()` | + +### reactionsRequestBuilder + +Custom request builder for fetching reactions. + +| | | +|---|---| +| Type | `ReactionsRequest.ReactionsRequestBuilder?` | +| Default | `nil` | + +### scrollToBottomOnNewMessages + +Automatically scrolls to bottom when new messages arrive. + +| | | +|---|---| +| Type | `Bool` | +| Default | `true` | + +### showMarkAsUnreadOption + +Shows the "Mark as unread" option in message actions. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### startFromUnreadMessages + +Starts the message list from the first unread message. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### textFormatters + +Array of text formatters for customizing message text display. + +| | | +|---|---| +| Type | `[CometChatTextFormatter]` | +| Default | `[]` | + +--- + +## Events + +The MessageList component provides callback events for handling state changes. + +### set(onLoad:) + +Fires when messages are successfully loaded. + +```swift lines +@discardableResult +public func set(onLoad: @escaping ([BaseMessage]) -> Void) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `onLoad` | `([BaseMessage]) -> Void` | Callback with loaded messages | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let messageList = CometChatMessageList() + +messageList.set(onLoad: { messages in + print("Loaded \(messages.count) messages") + // Perform analytics tracking or other actions +}) +``` + +### set(onEmpty:) + +Fires when the message list is empty. + +```swift lines +@discardableResult +public func set(onEmpty: @escaping () -> Void) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `onEmpty` | `() -> Void` | Callback when list is empty | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +messageList.set(onEmpty: { + print("No messages found") + // Show custom empty state or prompt user to start conversation +}) +``` + +--- + +## Date Time Formatter + +Customize how timestamps appear in the message list using the `CometChatDateTimeFormatter`. + +### Global Level Formatting + +```swift lines +import CometChatUIKitSwift + +// Customize time format +CometChatMessageList.dateTimeFormatter.time = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "HH:mm" + return formatter.string(from: date) +} + +// Customize today format +CometChatMessageList.dateTimeFormatter.today = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "h:mm a" + return "Today • " + formatter.string(from: date) +} + +// Customize older dates format +CometChatMessageList.dateTimeFormatter.otherDay = { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "dd MMM yyyy" + return formatter.string(from: date) +} +``` + +### Instance Level Formatting + +#### set(datePattern:) + +Sets a custom date pattern for message timestamps. + +```swift lines +@discardableResult +public func set(datePattern: @escaping (Int?) -> String) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `datePattern` | `(Int?) -> String` | Closure that formats timestamp to date string | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +messageList.set(datePattern: { timestamp in + guard let timestamp = timestamp else { return "" } + let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000)) + let formatter = DateFormatter() + formatter.dateFormat = "dd-MM-yyyy" + return formatter.string(from: date) +}) +``` + +#### set(timePattern:) + +Sets a custom time pattern for message timestamps. + +```swift lines +@discardableResult +public func set(timePattern: @escaping (Int) -> String) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `timePattern` | `(Int) -> String` | Closure that formats timestamp to time string | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +messageList.set(timePattern: { timestamp in + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = DateFormatter() + formatter.dateFormat = "HH:mm" + return formatter.string(from: date) +}) +``` + +#### set(dateSeparatorPattern:) + +Sets a custom pattern for date separators between messages. + +```swift lines +@discardableResult +public func set(dateSeparatorPattern: @escaping (Int?) -> String) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `dateSeparatorPattern` | `(Int?) -> String` | Closure that formats timestamp to date separator string | + +```swift lines +import CometChatUIKitSwift + +let messageList = CometChatMessageList() + +messageList.set(dateSeparatorPattern: { timestamp in + guard let timestamp = timestamp else { return "" } + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + + if Calendar.current.isDateInToday(date) { + return "Today" + } else if Calendar.current.isDateInYesterday(date) { + return "Yesterday" + } else { + let formatter = DateFormatter() + formatter.dateFormat = "EEEE, MMM d" + return formatter.string(from: date) + } +}) +``` + +### Available Formatters + +| Formatter | Purpose | Default Format | +|-----------|---------|----------------| +| `time` | Standard time display | `h:mm a` | +| `today` | Messages sent today | `Today` | +| `yesterday` | Messages from yesterday | `Yesterday` | +| `lastweek` | Messages within last week | Day name | +| `otherDay` | Older messages | `MMM d, yyyy` | +| `datePattern` | Custom date pattern | Configurable | +| `timePattern` | Custom time pattern | Configurable | +| `dateSeparatorPattern` | Date separator between messages | Configurable | + +--- + +## Common Patterns + +### Hide message options + +```swift lines +let messageList = CometChatMessageList() +messageList.set(user: user) +messageList.hideReplyInThreadOption = true +messageList.hideEditMessageOption = true +messageList.hideDeleteMessageOption = true +messageList.hideReactionOption = true +messageList.hideCopyMessageOption = true +``` + +### Disable sounds + +```swift lines +let messageList = CometChatMessageList() +messageList.set(user: user) +messageList.disableSoundForMessages = true +``` + +### Custom empty state + +```swift lines +let messageList = CometChatMessageList() +messageList.set(user: user) + +messageList.set(emptyStateView: { + let label = UILabel() + label.text = "Start a conversation!" + label.textAlignment = .center + label.textColor = .secondaryLabel + return label +}) +``` + +### Scroll to bottom on new messages + +```swift lines +let messageList = CometChatMessageList() +messageList.set(user: user) +messageList.scrollToBottomOnNewMessages = true +``` + +### Hide UI elements + +```swift lines +let messageList = CometChatMessageList() +messageList.set(user: user) +messageList.hideAvatar = true +messageList.hideReceipts = true +messageList.hideDateSeparator = true +messageList.hideHeaderView = true +messageList.hideFooterView = true +``` + +--- -Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. +## Related Components - +- [Messages](/ui-kit/ios/messages) - Parent component containing MessageList +- [Message Composer](/ui-kit/ios/message-composer) - Send messages in a conversation +- [Message Header](/ui-kit/ios/message-header) - Display user/group details +- [Message Template](/ui-kit/ios/message-template) - Create custom message bubble templates +- [Threaded Messages](/ui-kit/ios/threaded-messages) - Display threaded conversations diff --git a/ui-kit/ios/message-template.mdx b/ui-kit/ios/message-template.mdx index 6a7b1ea46..9e1e7efdc 100644 --- a/ui-kit/ios/message-template.mdx +++ b/ui-kit/ios/message-template.mdx @@ -1,12 +1,16 @@ --- title: "Message Template" +sidebarTitle: "Message Template" +description: "Define and customize the structure and behavior of message bubbles using CometChat UI Kit for iOS" --- ## Overview -A MessageTemplate provides you with the capability to define and customize both the structure and the behavior of the [MessageBubble](/ui-kit/ios/message-bubble-styling). It acts as a schema or design blueprint for the creation of a variety of [MessageBubble](/ui-kit/ios/message-bubble-styling) components, allowing you to manage the appearance and interactions of [MessageBubble](/ui-kit/ios/message-bubble-styling) within your application effectively and consistently. +A MessageTemplate provides you with the capability to define and customize both the structure and the behavior of the [MessageBubble](/ui-kit/ios/message-bubble-styling). It acts as a schema or design blueprint for creating a variety of message bubble components, allowing you to manage their appearance and interactions within your application effectively and consistently. -### Structure +--- + +## Structure @@ -24,216 +28,232 @@ The MessageBubble structure can typically be broken down into the following view 5. **Bottom view**: This view can be used to extend the MessageBubble with additional elements, such as link previews or a 'load more' button for long messages. It's typically placed beneath the Content view. -6. **Thread view**:This is where the thread reply icon and reply counts are displayed. It's located below the footer view. +6. **Thread view**: This is where the thread reply icon and reply counts are displayed. It's located below the footer view. 7. **Footer view**: This is where the timestamp of the message and its delivery or read status are displayed. It's located at the bottom of the MessageBubble. 8. **Status Info view**: This is where the timestamp of the message and its delivery or read status are displayed. It's located inside the MessageBubble just below the content view. -### Properties - -MessageTemplate provides you with methods that allow you to alter various properties of the MessageBubble. These properties include aspects such as the `type` and `category` of a message, the appearance and behavior of the header, content, and footer sections of the message bubble, +--- -1. **Type** +## Properties - Using `setType()` you can set the type of CometChatMessage, This will map your MessageTemplate to the corresponding CometChatMessage. You can set the MessageTemplates Type using the following code snippet. +MessageTemplate provides you with methods that allow you to alter various properties of the MessageBubble. These properties include aspects such as the `type` and `category` of a message, the appearance and behavior of the header, content, and footer sections of the message bubble. - ```csharp +### 1. Type - let type = "custom_template"//replace this with your own custom type +Using `setType()` you can set the type of CometChatMessage. This will map your MessageTemplate to the corresponding CometChatMessage. You can set the MessageTemplate's Type using the following code snippet: - //Creating a custom message template - let customMessageTemplate = - CometChatMessageTemplate(category: category, type: type, contentView: { message, alignment, controller in - return UIView() //replace this with your own UI for message list +```swift lines +let type = "custom_template" // Replace with your own custom type - }, bubbleView: nil, headerView: nil, footerView: nil) { message, alignment, controller in - return UIView() //replace this with your own UI for message composer - } options: { message, group, controller in - return [CometChatMessageOption]() //replace this with your own options - } - ``` +// Creating a custom message template +let customMessageTemplate = CometChatMessageTemplate( + category: category, + type: type, + contentView: { message, alignment, controller in + return UIView() // Replace with your own UI for message list + }, + bubbleView: nil, + headerView: nil, + footerView: nil +) { message, alignment, controller in + return UIView() // Replace with your own UI for message composer +} options: { message, group, controller in + return [CometChatMessageOption]() // Replace with your own options +} +``` -2. **Category** +### 2. Category Using `.setCategory()` you can set the category of a MessageTemplate. This will create a MessageTemplate with the specified category and link it with a CometChatMessage of the same category. Please refer to our guide on [Message Categories](/sdk/ios/message-structure-and-hierarchy) for a deeper understanding of message categories. -```csharp -let category = "custom_category"//replace this with your own category - -//Creating a custom message template -//You can also set UI for bubbleView, headerView and footerView instead of nil -let customMessageTemplate = - CometChatMessageTemplate(category: category, type: type, contentView: { message, alignment, controller in - return UIView() //replace this with your own UI for message list - - }, bubbleView: nil, headerView: nil, footerView: nil) { message, alignment, controller in - return UIView() //replace this with your own UI for message composer - } options: { message, group, controller in - return [CometChatMessageOption]() //replace this with your own options - } +```swift lines +let category = "custom_category" // Replace with your own category + +// Creating a custom message template +// You can also set UI for bubbleView, headerView and footerView instead of nil +let customMessageTemplate = CometChatMessageTemplate( + category: category, + type: type, + contentView: { message, alignment, controller in + return UIView() // Replace with your own UI for message list + }, + bubbleView: nil, + headerView: nil, + footerView: nil +) { message, alignment, controller in + return UIView() // Replace with your own UI for message composer +} options: { message, group, controller in + return [CometChatMessageOption]() // Replace with your own options +} ``` -3. **Header View** +### 3. Header View - The .`template.headerView` method allows you to assign a custom header view to the MessageBubble. By default, it is configured to display the sender's name. +The `template.headerView` method allows you to assign a custom header view to the MessageBubble. By default, it is configured to display the sender's name. - ```swift - var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - - for (index, template) in allTemplates.enumerated() { - var template = template - template.headerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - return UIView() +```swift lines +var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - } - } - ``` +for (index, template) in allTemplates.enumerated() { + var template = template + template.headerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + return UIView() + } +} +``` -4. **Content View** +### 4. Content View - The `template.contentView` method allows you to assign a custom content view to the MessageBubble. By default, it displays the [Text Bubble](/ui-kit/ios/message-bubble-styling#text-bubble), [Image Bubble](/ui-kit/ios/message-bubble-styling-styling#image-bubble), [File Bubble](/ui-kit/ios/message-bubble-styling-styling), [Audio Bubble](/ui-kit/ios/message-bubble-styling-styling#audio-bubble), or [Video Bubble](/ui-kit/ios/message-bubble-styling#video-bubble), depending on the message type. +The `template.contentView` method allows you to assign a custom content view to the MessageBubble. By default, it displays the [Text Bubble](/ui-kit/ios/message-bubble-styling#text-bubble), [Image Bubble](/ui-kit/ios/message-bubble-styling#image-bubble), [File Bubble](/ui-kit/ios/message-bubble-styling), [Audio Bubble](/ui-kit/ios/message-bubble-styling#audio-bubble), or [Video Bubble](/ui-kit/ios/message-bubble-styling#video-bubble), depending on the message type. - ```swift - var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() +```swift lines +var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.contentView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - return UIView() +for (index, template) in allTemplates.enumerated() { + var template = template + template.contentView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + return UIView() } - } - ``` +} +``` -5. **Footer View** +### 5. Footer View - The `template.footerView` method allows you to assign a custom Footer view to the MessageBubble. By default, it displays the receipt and timestamp. +The `template.footerView` method allows you to assign a custom Footer view to the MessageBubble. By default, it displays the receipt and timestamp. - ```swift - var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() +```swift lines +var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.footerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - return UIView() +for (index, template) in allTemplates.enumerated() { + var template = template + template.footerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + return UIView() } - } - ``` +} +``` -6. **Bottom View** +### 6. Bottom View - The `template.bottomView` method allows you to assign a custom Bottom view to the MessageBubble.By defuault is has buttons such as link previews or a 'load more' button for long messages. +The `template.bottomView` method allows you to assign a custom Bottom view to the MessageBubble. By default, it has buttons such as link previews or a 'load more' button for long messages. - ```swift - var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() +```swift lines +var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.bottomView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - return UIView() +for (index, template) in allTemplates.enumerated() { + var template = template + template.bottomView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + return UIView() } - } - ``` +} +``` -7. **Bubble View** +### 7. Bubble View - The `template.bubbleView` method allows you to assign a custom Bubble view to the MessageBubble. By default, headerView, contentView, and footerView together form a message bubble. +The `template.bubbleView` method allows you to assign a custom Bubble view to the MessageBubble. By default, headerView, contentView, and footerView together form a message bubble. - ```swift - var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() +```swift lines +var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.bubbleView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - return UIView() +for (index, template) in allTemplates.enumerated() { + var template = template + template.bubbleView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + return UIView() } - } - ``` +} +``` -8. **Options** +### 8. Options - The `template.options` lets you set the list of actions that a user can perform on a message. This includes actions like reacting to, editing, or deleting a message. +The `template.options` lets you set the list of actions that a user can perform on a message. This includes actions like reacting to, editing, or deleting a message. - ```csharp - var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.options = { message, group, controller in - let loggedInUser = CometChat.getLoggedInUser() - let options = CometChatUIKit.getDataSource().getMessageOptions(loggedInUser: loggedInUser!, messageObject: message!, controller: controller, group: group) +```swift lines +var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - return options +for (index, template) in allTemplates.enumerated() { + var template = template + template.options = { message, group, controller in + let loggedInUser = CometChat.getLoggedInUser() + let options = CometChatUIKit.getDataSource().getMessageOptions( + loggedInUser: loggedInUser!, + messageObject: message!, + controller: controller, + group: group + ) + return options } - allTemplates[index] = template - } - ``` + allTemplates[index] = template +} +``` -*** +--- ## Customization Let's dive into how you can use the [properties](#properties) of MessageTemplate to customize an existing template or add a new one to the [MessageList](/ui-kit/ios/message-list) component. -The First step is to fetch the list of existing templates when you want to modify or add to them. This can be done using the getAllMessageTemplates() method from the DataSource of the CometChatUIKit class. +The first step is to fetch the list of existing templates when you want to modify or add to them. This can be done using the `getAllMessageTemplates()` method from the DataSource of the CometChatUIKit class: -```javascript -var messageTemplates : [CometChatMessageTemplate] = CometChatUIKit.getDataSource().getAllMessageTemplates() +```swift lines +var messageTemplates: [CometChatMessageTemplate] = CometChatUIKit.getDataSource().getAllMessageTemplates() ``` +--- + ### Existing Templates -You will need to first get the MessageTemplates object for the type of message you want to customize. You will be customizing the TextMessage Bubble here. The code snippet to get the Text MessageTemplate is as follows. +You will need to first get the MessageTemplates object for the type of message you want to customize. In this example, we'll customize the TextMessage Bubble. The code snippet to get the Text MessageTemplate is as follows: -```swift -var messageTemplates : [CometChatMessageTemplate] = CometChatUIKit.getDataSource().getAllMessageTemplates() +```swift lines +var messageTemplates: [CometChatMessageTemplate] = CometChatUIKit.getDataSource().getAllMessageTemplates() for i in 0.. - -You will be using `CometChatMessageBubble` Component for example here so to apply Template to Messages you will have to use [MessageList](/ui-kit/ios/message-list) component. +You will be using the `CometChatMessageBubble` Component for this example. To apply Template to Messages, you will have to use the [MessageList](/ui-kit/ios/message-list) component. -By utilizing this code snippet, you will retrieve `text templates`. +By utilizing this code snippet, you will retrieve text templates: -```swift -let messageTemplates : CometChatMessageTemplate = CometChatUIKit.getDataSource().getTextMessageTemplate() +```swift lines +// Get text message template +let messageTemplates: CometChatMessageTemplate = CometChatUIKit.getDataSource().getTextMessageTemplate() +// Configure message list with template let messageListConfiguration = MessageListConfiguration() .set(templates: [messageTemplates]) - +// Apply to CometChatMessages let cometChatMessages = CometChatMessages() .set(user: user) .set(messageListConfiguration: messageListConfiguration) ``` - - @@ -241,14 +261,12 @@ let cometChatMessages = CometChatMessages() - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- -#### Header view +#### Header View The `template.headerView` method of MessageTemplate allows you to add custom views to the header of your message bubbles. In the example below, we will add a custom UIView `custom_header_view` to the header view of every text message in the MessageList. @@ -256,10 +274,12 @@ The `template.headerView` method of MessageTemplate allows you to add custom vie -```swift custom_header_view + + + +```swift lines import UIKit import CometChatUIKitSwift -import UIKit class HeaderViewStyled: UIView { @@ -322,37 +342,36 @@ class HeaderViewStyled: UIView { } } ``` + + -```swift Swift +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { + +for (index, template) in allTemplates.enumerated() { var template = template template.headerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in let customHeaderView = HeaderViewStyled() return customHeaderView - } - allTemplates[index] = template -} + } + allTemplates[index] = template +} let cometChatMessages = CometChatMessageList() cometChatMessages.set(templates: allTemplates) ``` - - - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- -#### Content view +#### Content View The `template.contentView` method of MessageTemplate allows you to add a custom view to the content of your message bubbles. In the example below, we will add a custom `custom_message_view_file` to the content view of every text message in the MessageList. @@ -361,9 +380,8 @@ The `template.contentView` method of MessageTemplate allows you to add a custom - - -```swift custom_message_view_file + +```swift lines import UIKit import CometChatSDK import CometChatUIKitSwift @@ -375,7 +393,7 @@ class ContentViewStyled: UIView { let imageView = UIImageView() imageView.contentMode = .scaleAspectFit imageView.clipsToBounds = true - imageView.layer.cornerRadius = 8 // For rounded corners + imageView.layer.cornerRadius = 8 imageView.translatesAutoresizingMaskIntoConstraints = false return imageView }() @@ -411,7 +429,7 @@ class ContentViewStyled: UIView { // MARK: - Setup View private func setupView() { - backgroundColor = UIColor.systemGray6 // Light gray background + backgroundColor = UIColor.systemGray6 layer.cornerRadius = 12 layer.masksToBounds = true @@ -425,11 +443,10 @@ class ContentViewStyled: UIView { // MARK: - Constraints private func setupConstraints() { NSLayoutConstraint.activate([ - // Product Image View Constraints productImageView.topAnchor.constraint(equalTo: topAnchor, constant: 16), productImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), productImageView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), - productImageView.heightAnchor.constraint(equalTo: productImageView.widthAnchor), // Keep it square + productImageView.heightAnchor.constraint(equalTo: productImageView.widthAnchor), buyNowButton.topAnchor.constraint(equalTo: productImageView.bottomAnchor, constant: 16), buyNowButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), @@ -450,49 +467,46 @@ class ContentViewStyled: UIView { } } ``` - - -```swift Swift +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.contentView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - let customView = ContentViewStyled() - return customView - } - allTemplates[index] = template -} + +for (index, template) in allTemplates.enumerated() { + var template = template + template.contentView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + let customView = ContentViewStyled() + return customView + } + allTemplates[index] = template +} let cometChatMessages = CometChatMessageList() cometChatMessages.set(templates: allTemplates) ``` - - - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- #### Bottom View -The `template.bottomView `method of MessageTemplate allows you to add a custom button view to your message bubbles. In the example below, we will add a custom UIView `custom_bottom_view_file` to the bottom view of every text message in the MessageList. +The `template.bottomView` method of MessageTemplate allows you to add a custom button view to your message bubbles. In the example below, we will add a custom UIView `custom_bottom_view_file` to the bottom view of every text message in the MessageList. -```swift custom_bottom_view_file + + +```swift lines import UIKit class BottomViewStyled: UIView { @@ -549,35 +563,34 @@ class BottomViewStyled: UIView { } } ``` + + -```swift Swift +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.bottomView = { (baseMessage: BaseMessage?, bubbleAlignment:MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - let customView = BottomViewStyled() - return customView - } - allTemplates[index] = template -} + +for (index, template) in allTemplates.enumerated() { + var template = template + template.bottomView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + let customView = BottomViewStyled() + return customView + } + allTemplates[index] = template +} let cometChatMessages = CometChatMessageList() cometChatMessages.set(templates: allTemplates) ``` - - - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- #### Footer View @@ -587,7 +600,9 @@ The `template.footerView` method of MessageTemplate allows you to add a footer v -```swift custom_footer_view + + +```swift lines import UIKit class FooterViewStyled: UIView { @@ -613,7 +628,6 @@ class FooterViewStyled: UIView { addSubview(reactionsStackView) NSLayoutConstraint.activate([ - reactionsStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), reactionsStackView.topAnchor.constraint(equalTo: topAnchor, constant: 8), reactionsStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), @@ -633,39 +647,47 @@ class FooterViewStyled: UIView { } } ``` + + -```swift Swiftjavascript + + +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.footerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - let customView = FooterViewStyled() - return customView - } - allTemplates[index] = template -} + +for (index, template) in allTemplates.enumerated() { + var template = template + template.footerView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + let customView = FooterViewStyled() + return customView + } + allTemplates[index] = template +} let cometChatMessages = CometChatMessageList() cometChatMessages.set(templates: allTemplates) ``` + + - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** + +--- #### Bubble View -The` template.bubbleView` method of MessageTemplate allows you to add a bubble view to your message bubbles. In the example below, we will add a custom UIView `custom_bubble_view` to the bubble view of every text message in the MessageList. +The `template.bubbleView` method of MessageTemplate allows you to add a bubble view to your message bubbles. In the example below, we will add a custom UIView `custom_bubble_view` to the bubble view of every text message in the MessageList. -```swift custom_bubble_view + + +```swift lines import UIKit class CustomMessageView: UIView { @@ -691,7 +713,7 @@ class CustomMessageView: UIView { private let doubleTickImageView: UIImageView = { let imageView = UIImageView() - imageView.image = UIImage(named: "double_tick") // Add your double tick image here + imageView.image = UIImage(named: "double_tick") imageView.contentMode = .scaleAspectFit imageView.translatesAutoresizingMaskIntoConstraints = false return imageView @@ -717,6 +739,7 @@ class CustomMessageView: UIView { // MARK: - Initialization init(message: BaseMessage) { super.init(frame: .zero) + // Add subviews addSubview(bubbleView) addSubview(timeStackView) @@ -748,10 +771,13 @@ class CustomMessageView: UIView { doubleTickImageView.widthAnchor.constraint(equalToConstant: 16), doubleTickImageView.heightAnchor.constraint(equalToConstant: 16) ]) + + // Configure with message data if let textMessage = message as? TextMessage { messageLabel.text = textMessage.text var status = "Sent" doubleTickImageView.image = UIImage(named: "single-tick") + if textMessage.readAt > 0 { status = "Read" doubleTickImageView.image = UIImage(named: "message-read") @@ -766,7 +792,6 @@ class CustomMessageView: UIView { timeLabel.text = "\(time)" } - } required init?(coder: NSCoder) { @@ -774,29 +799,34 @@ class CustomMessageView: UIView { } } ``` + + -```swift Swiftjavascript + + +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.bubbleView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in - let customBubbleView = CustomBubbleView() - return customBubbleView - } - allTemplates[index] = template + +for (index, template) in allTemplates.enumerated() { + var template = template + template.bubbleView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> (UIView)? in + let customBubbleView = CustomBubbleView() + return customBubbleView + } + allTemplates[index] = template } let cometChatMessages = CometChatMessages() cometChatMessages.set(templates: allTemplates) ``` + + - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- #### Options List @@ -808,16 +838,25 @@ However, if you wish to override or modify these options, you can use the `templ -```swift Swiftphp + + +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() + for (index, template) in allTemplates.enumerated() { var template = template template.options = { message, group, controller in let loggedInUser = CometChat.getLoggedInUser() - var options = CometChatUIKit.getDataSource().getMessageOptions(loggedInUser: loggedInUser!, messageObject: message!, controller: controller, group: group) + var options = CometChatUIKit.getDataSource().getMessageOptions( + loggedInUser: loggedInUser!, + messageObject: message!, + controller: controller, + group: group + ) + for (index, option) in (options ?? []).enumerated() { if option.id == "replyInThread" { - + // Create custom options let forwardOption = CometChatMessageOption(id: "customOptionId", title: "Forward", icon: UIImage(systemName: "chevron.right")) let favoriteOption = CometChatMessageOption(id: "favoriteOptionId", title: "Mark as Favorite", icon: UIImage(systemName: "star")) let deleteOption = CometChatMessageOption(id: "deleteOptionId", title: "Delete", icon: UIImage(systemName: "trash")) @@ -826,22 +865,21 @@ for (index, template) in allTemplates.enumerated() { } } return options ?? [] - } allTemplates[index] = template -} +} let cometChatMessages = CometChatMessageList() cometChatMessages.set(templates: allTemplates) ``` + + - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- #### Status Info View @@ -853,7 +891,9 @@ In the example below, we will integrate a custom UIView file named `custom_statu -```swift custom_status_view + + +```swift lines import UIKit import CometChatSDK import CometChatUIKitSwift @@ -871,7 +911,7 @@ class StatusInfoView: UIView { private let doubleTickImageView: UIImageView = { let imageView = UIImageView() - imageView.image = UIImage(named: "double_tick") // Add your double tick image here + imageView.image = UIImage(named: "double_tick") imageView.contentMode = .scaleAspectFit imageView.translatesAutoresizingMaskIntoConstraints = false return imageView @@ -889,6 +929,7 @@ class StatusInfoView: UIView { // MARK: - Initialization init(baseMessage: BaseMessage) { super.init(frame: .zero) + // Add subviews addSubview(timeStackView) timeStackView.addArrangedSubview(timeLabel) @@ -906,9 +947,11 @@ class StatusInfoView: UIView { doubleTickImageView.heightAnchor.constraint(equalToConstant: 16) ]) + // Configure with message data if let textMessage = baseMessage as? TextMessage { var status = "Sent" doubleTickImageView.image = UIImage(named: "single-tick") + if textMessage.readAt > 0 { status = "Read" doubleTickImageView.image = UIImage(named: "message-read") @@ -930,103 +973,114 @@ class StatusInfoView: UIView { } } ``` + + -```swift Swift + + +```swift lines var allTemplates = CometChatUIKit.getDataSource().getAllMessageTemplates() - for (index, template) in allTemplates.enumerated() { - var template = template - template.statusInfoView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> UIView? in - if let baseMessage = baseMessage { - return CustomStatusView(baseMessage: baseMessage) - } - return nil + +for (index, template) in allTemplates.enumerated() { + var template = template + template.statusInfoView = { (baseMessage: BaseMessage?, bubbleAlignment: MessageBubbleAlignment, viewController: UIViewController?) -> UIView? in + if let baseMessage = baseMessage { + return CustomStatusView(baseMessage: baseMessage) } + return nil + } allTemplates[index] = template } let cometChatMessages = CometChatMessages() cometChatMessages.set(templates: allTemplates) ``` + + - Ensure to pass and present `cometChatMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- ### New Template -You can create an entirely new template for custom messages is one of the powerful features of CometChat's MessageTemplate. To add a new template, you can create a new one and then add it to the list of existing templates. +Creating an entirely new template for custom messages is one of the powerful features of CometChat's MessageTemplate. To add a new template, you can create a new one and then add it to the list of existing templates. First, let's see how to send a custom message: -```swift Swift -//Creating a text template -let textTemplate = CometChatUIKit.getDataSource() - .getTextMessageTemplate() + + +```swift lines +// Creating a text template +let textTemplate = CometChatUIKit.getDataSource().getTextMessageTemplate() -// set content view for TextMessage template +// Set content view for TextMessage template textTemplate.contentView = { message, alignment, controller in - // Create your own content view and return - return UIView() + // Create your own content view and return + return UIView() } -// set bubble view for TextMessage template +// Set bubble view for TextMessage template textTemplate.bubbleView = { message, alignment, controller in - // Create your own bubble view and return - return UIView() + // Create your own bubble view and return + return UIView() } -//Creating an audio template -let audioTemplate = CometChatUIKit.getDataSource() - .getAudioMessageTemplate() +// Creating an audio template +let audioTemplate = CometChatUIKit.getDataSource().getAudioMessageTemplate() -// set content view for AudioMessage template +// Set content view for AudioMessage template audioTemplate.contentView = { message, alignment, controller in - // Create your own content view and return - return UIView() + // Create your own content view and return + return UIView() } -// set bubble view for AudioMessage template +// Set bubble view for AudioMessage template audioTemplate.bubbleView = { message, alignment, controller in - // Create your own bubble view and return - return UIView() + // Create your own bubble view and return + return UIView() } +let type = "custom_template" // Replace with your own custom type +let category = "custom_category" // Replace with your own category + +// Creating a custom message template +// You can also set UI for bubbleView, headerView and footerView instead of nil +let customMessageTemplate = CometChatMessageTemplate( + category: category, + type: type, + contentView: { message, alignment, controller in + return UIView() // Replace with your own UI for message list + }, + bubbleView: nil, + headerView: nil, + footerView: nil +) { message, alignment, controller in + return UIView() // Replace with your own UI for message composer +} options: { message, group, controller in + return [CometChatMessageOption]() // Replace with your own options +} -let type = "custom_template"//replace this with your own custom type -let category = "custom_category"//replace this with your own category - -//Creating a custom message template -//You can also set UI for bubbleView, headerView and footerView instead of nil -let customMessageTemplate = - CometChatMessageTemplate(category: category, type: type, contentView: { message, alignment, controller in - return UIView() //replace this with your own UI for message list - - }, bubbleView: nil, headerView: nil, footerView: nil) { message, alignment, controller in - return UIView() //replace this with your own UI for message composer - } options: { message, group, controller in - return [CometChatMessageOption]() //replace this with your own options - } - -//custom list of templates +// Custom list of templates let messageTypes = [ - textTemplate, - audioTemplate, - customMessageTemplate - ] + textTemplate, + audioTemplate, + customMessageTemplate +] var templates = [(type: String, template: CometChatMessageTemplate)]() for template in messageTypes { - templates.append((type: template.type, template: template)) + templates.append((type: template.type, template: template)) } -//passing template list to cometchatMessages - let messageList = CometChatMessageList() - messageList.set(templates: templates) +// Passing template list to message list +let messageList = CometChatMessageList() +messageList.set(templates: templates) ``` + + Find the example below: @@ -1034,7 +1088,9 @@ Find the example below: -```swift Swift + + +```swift lines import UIKit class CustomBubbleView: UIView { @@ -1044,9 +1100,9 @@ class CustomBubbleView: UIView { let imageView = UIImageView() imageView.contentMode = .scaleAspectFill imageView.clipsToBounds = true - imageView.layer.cornerRadius = 25 // Half of width/height to make it circular + imageView.layer.cornerRadius = 25 imageView.translatesAutoresizingMaskIntoConstraints = false - imageView.image = UIImage(named: "profile_placeholder") // Replace with your image + imageView.image = UIImage(named: "profile_placeholder") return imageView }() @@ -1072,7 +1128,7 @@ class CustomBubbleView: UIView { let imageView = UIImageView() imageView.contentMode = .scaleAspectFit imageView.translatesAutoresizingMaskIntoConstraints = false - imageView.image = UIImage(named: "double_tick") // Replace with your double-tick image + imageView.image = UIImage(named: "double_tick") return imageView }() @@ -1200,9 +1256,19 @@ class CustomBubbleView: UIView { } } ``` + + +Make sure to set new type and category in the message Request builder in order to fetch those respective messages as shown in the example above. + -Make sure to set new type and category in to the message Request builder in order to fetch those respective messages as shown in the example below. +--- - +## Next Steps + +- [Message List](/ui-kit/ios/message-list) — Display and customize the message list +- [Message Bubble Styling](/ui-kit/ios/message-bubble-styling) — Customize message bubble appearance +- [Message Composer](/ui-kit/ios/message-composer) — Customize the message input component + +--- diff --git a/ui-kit/ios/methods.mdx b/ui-kit/ios/methods.mdx index 9e57c6f5d..d59caae27 100644 --- a/ui-kit/ios/methods.mdx +++ b/ui-kit/ios/methods.mdx @@ -1,32 +1,71 @@ --- title: "Methods" +description: "Reference for CometChat iOS UI Kit methods including init, login, logout, and message-sending wrappers." --- + +```json +{ + "category": "methods", + "wrapperClass": "CometChatUIKit", + "methodCategories": [ + { + "name": "initialization", + "methods": [ + {"name": "init", "signature": "CometChatUIKit.init(uiKitSettings: UIKitSettings, completion:)", "description": "Initialize UI Kit with settings"} + ] + }, + { + "name": "authentication", + "methods": [ + {"name": "loginWithUID", "signature": "CometChatUIKit.login(uid: String, completion:)", "description": "Login using UID and Auth Key"}, + {"name": "loginWithToken", "signature": "CometChatUIKit.login(authToken: String, completion:)", "description": "Login using Auth Token"}, + {"name": "logout", "signature": "CometChatUIKit.logout(user: User, completion:)", "description": "Logout current user"}, + {"name": "createUser", "signature": "CometChatUIKit.create(user: User, completion:)", "description": "Create new user"} + ] + }, + { + "name": "messaging", + "methods": [ + {"name": "sendTextMessage", "signature": "CometChatUIKit.sendTextMessage(message: TextMessage)", "description": "Send text message"}, + {"name": "sendMediaMessage", "signature": "CometChatUIKit.sendMediaMessage(message: MediaMessage)", "description": "Send media message"}, + {"name": "sendCustomMessage", "signature": "CometChatUIKit.sendCustomMessage(message: CustomMessage)", "description": "Send custom message"} + ] + }, + { + "name": "interactiveMessages", + "methods": [ + {"name": "sendFormMessage", "signature": "CometChatUIKit.sendFormMessage(formMessage: FormMessage, completion:)", "description": "Send form message"}, + {"name": "sendCardMessage", "signature": "CometChatUIKit.sendCardMessage(cardMessage: CardMessage, completion:)", "description": "Send card message"}, + {"name": "sendSchedulerMessage", "signature": "CometChatUIKit.sendSchedulerMessage(schedulerMessage: SchedulerMessage, completion:)", "description": "Send scheduler message"} + ] + } + ] +} +``` + + ## Overview -The UI Kit's core function is to extend the [CometChat SDK](/sdk/ios/overview), essentially translating the raw data and functionality provided by the underlying methods into visually appealing and easy-to-use UI components. +The UI Kit's core function is to extend the [CometChat SDK](/sdk/ios/overview), translating raw data and functionality into visually appealing, easy-to-use UI components. -To effectively manage and synchronize the UI elements and data across all components in the UI Kit, we utilize internal events. These internal events enable us to keep track of changes in real-time and ensure that the UI reflects the most current state of data. +To effectively manage and synchronize UI elements and data across all components, the UI Kit uses internal events. These events enable real-time change tracking and ensure the UI reflects the most current state of data. -The CometChat UI Kit has thoughtfully encapsulated the critical [CometChat SDK](/sdk/ios/overview) methods within its wrapper to efficiently manage internal eventing. This layer of abstraction simplifies interaction with the underlying CometChat SDK, making it more user-friendly for developers. +The CometChat UI Kit encapsulates critical [CometChat SDK](/sdk/ios/overview) methods within its wrapper to efficiently manage internal eventing. This abstraction layer simplifies interaction with the underlying SDK, making it more developer-friendly. ## Methods -You can access the methods using the `CometChatUIKit` class. This class provides access to all the public methods exposed by the CometChat UI Kit. +Access all public methods exposed by the CometChat UI Kit through the `CometChatUIKit` class. ### Init -As a developer, you need to invoke this method every time before you use any other methods provided by the UI Kit. - -This initialization is a critical step that ensures the UI Kit and Chat SDK function correctly and as intended in your application. Typical practice is to make this one of the first lines of code executed in your application's lifecycle when it comes to implementing CometChat. +You must invoke this method before using any other UI Kit methods. This initialization ensures the UI Kit and Chat SDK function correctly in your application. Best practice is to make this one of the first lines of code executed in your application's lifecycle. - -Make sure you replace the **APP\_ID**, **REGION** and **AUTH\_KEY** with your CometChat App ID, Region and Auth Key in the below code. The `Auth Key` is an optional property of the `UIKitSettings` Class. It is intended for use primarily during proof-of-concept (POC) development or in the early stages of application development. You can use the [Auth Token](#login-using-auth-token) to log in securely. - +Replace **APP_ID**, **REGION**, and **AUTH_KEY** with your CometChat App ID, Region, and Auth Key. The `Auth Key` is an optional property of the `UIKitSettings` class, intended primarily for proof-of-concept (POC) development or early stages of application development. For production, use [Auth Token](#login-using-auth-token) instead. -Here's the table format for the properties available in `UIKitSettings`: +#### UIKitSettings Properties | Method | Type | Description | | ------------------------------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | @@ -40,13 +79,11 @@ Here's the table format for the properties available in `UIKitSettings`: | **setAIFeatures** | `List` | Sets the AI Features that need to be added in UI Kit | | **setExtensions** | `List` | Sets the list of extension that need to be added in UI Kit | -*** - -The concluding code block: +#### Example -```swift +```swift lines let uiKitSettings = UIKitSettings() .set(region: "your_region") .set(appID: "your_appId") @@ -63,22 +100,18 @@ CometChatUIKit.init(uiKitSettings: uikitSettings) { result in } } ``` - - -*** +--- ### Login using Auth Key -Only the `UID` of a user is needed to log in. This simple authentication procedure is useful when you are creating a POC or if you are in the development phase. For production apps, we suggest you use [AuthToken](#login-using-auth-token) instead of Auth Key. - -The concluding code block: +Only the `UID` of a user is needed to log in. This simple authentication procedure is useful for POC or development phases. For production apps, use [AuthToken](#login-using-auth-token) instead. -```swift +```swift lines CometChatUIKit.login(uid: "uid") { (result) in switch result { case .success(let user): @@ -88,26 +121,22 @@ CometChatUIKit.login(uid: "uid") { (result) in } } ``` - - -*** +--- ### Login using Auth Token -This advanced authentication procedure does not use the Auth Key directly in your client code thus ensuring safety. +This advanced authentication procedure does not use the Auth Key directly in your client code, ensuring better security. 1. [Create a User](https://api-explorer.cometchat.com/reference/creates-user) via the CometChat API when the user signs up in your app. 2. [Create an Auth Token](https://api-explorer.cometchat.com/reference/create-authtoken) via the CometChat API for the new user and save the token in your database. 3. Load the Auth Token in your client and pass it to the `login(authToken:)` method. -The concluding code block: - -```swift +```swift lines CometChatUIKit.login(authToken: "your_authToken") { (result) in switch result { case .success(let user): @@ -117,22 +146,18 @@ CometChatUIKit.login(authToken: "your_authToken") { (result) in } } ``` - - -*** +--- ### Logout -The CometChat UI Kit and Chat SDK effectively handle the session of the logged-in user within the framework. Before a new user logs in, it is crucial to clean this data to avoid potential conflicts or unexpected behavior. This can be achieved by invoking the `.logout(user:)` function. - -The concluding code block: +The CometChat UI Kit and Chat SDK handle the session of the logged-in user within the framework. Before a new user logs in, clean this data to avoid potential conflicts or unexpected behavior by invoking the `.logout(user:)` function. -```swift +```swift lines let user = User(uid: "uid", name: "user_name") CometChatUIKit.logout(user: user) { (result) in @@ -144,22 +169,18 @@ CometChatUIKit.logout(user: user) { (result) in } } ``` - - -*** +--- ### Create User -As a developer, you can dynamically create users on CometChat using the `.create(user:)` function. This can be extremely useful for situations where users are registered or authenticated by your system and then need to be created on CometChat. - -The concluding code block: +Dynamically create users on CometChat using the `.create(user:)` function. This is useful when users are registered or authenticated by your system and need to be created on CometChat. -```swift +```swift lines let user = User(uid: "uid", name: "user_name") CometChatUIKit.create(user: user) { result in @@ -171,24 +192,20 @@ CometChatUIKit.create(user: user) { result in } } ``` - - -*** +--- ### Base Message #### Text Message -As a developer, if you need to send a text message to a single user or a group, you'll need to utilize the `sendTextMessage()` function. This function requires a `TextMessage` object as its argument, which contains the necessary information for delivering the message. - -The concluding code block: +To send a text message to a single user or a group, use the `sendTextMessage()` function. This function requires a `TextMessage` object containing the necessary information for delivering the message. -```swift +```swift lines let textMessage = TextMessage(receiverUid: "uid", text: message, receiverType: .user) textMessage.muid = "\(NSDate().timeIntervalSince1970)" textMessage.sentAt = Int(Date().timeIntervalSince1970) @@ -198,24 +215,22 @@ textMessage.parentMessageId = parentMessageId CometChatUIKit.sendTextMessage(message: textMessage) ``` - - -> It's essential to understand the difference between `CometChatUIKit.sendTextMessage()` and `CometChat.sendTextMessage()`. When you use `CometChatUIKit.sendTextMessage()`, it automatically adds the message to the [MessagesComponent](/ui-kit/android/message-header) and [ConversationsComponent](/ui-kit/android/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendTextMessage()` only sends the message and doesn't automatically update these components in the UI Kit. + +`CometChatUIKit.sendTextMessage()` automatically adds the message to the [MessagesComponent](/ui-kit/ios/message-list) and [ConversationsComponent](/ui-kit/ios/conversations), handling all related cases for you. In contrast, `CometChat.sendTextMessage()` only sends the message without updating these UI Kit components. + -*** +--- #### Media Message -As a developer, if you need to send a media message to a single user or a group, you'll need to utilize the `sendMediaMessage()` function. This function requires a `MediaMessage` object as its argument, which contains the necessary information for delivering the message. - -The concluding code block: +To send a media message to a single user or a group, use the `sendMediaMessage()` function. This function requires a `MediaMessage` object containing the necessary information for delivering the message. -```swift +```swift lines let mediaMessage = MediaMessage(receiverUid: "uid", fileurl: url, messageType: type, receiverType: .user) mediaMessage.muid = "\(NSDate().timeIntervalSince1970)" mediaMessage.sentAt = Int(Date().timeIntervalSince1970) @@ -226,24 +241,22 @@ mediaMessage.parentMessageId = parentMessageId CometChatUIKit.sendMediaMessage(message: MediaMessage) ``` - - -> It's essential to understand the difference between `CometChatUIKit.sendMediaMessage()` and `CometChat.sendMediaMessage()`. When you use `CometChatUIKit.sendMediaMessage()`, it automatically adds the message to the [MessagesComponent](/ui-kit/ios/message-header) and [ConversationsComponent](/ui-kit/ios/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendMediaMessage()` only sends the message and doesn't automatically update these components in the UI Kit. + +`CometChatUIKit.sendMediaMessage()` automatically adds the message to the [MessagesComponent](/ui-kit/ios/message-list) and [ConversationsComponent](/ui-kit/ios/conversations), handling all related cases for you. In contrast, `CometChat.sendMediaMessage()` only sends the message without updating these UI Kit components. + -*** +--- #### Custom Message -As a developer, if you need to send a custom message to a single user or a group, you'll need to utilize the `sendCustomMessage()` function. This function requires a `CustomMessage` object as its argument, which contains the necessary information for delivering the message. - -The concluding code block: +To send a custom message to a single user or a group, use the `sendCustomMessage()` function. This function requires a `CustomMessage` object containing the necessary information for delivering the message. -```swift +```swift lines var customData = [String: Any]() customData["key"] = "value" @@ -254,26 +267,24 @@ customMessage.sender = CometChat.getLoggedInUser() CometChatUIKit.sendCustomMessage(message: CustomMessage) ``` - - -> It's essential to understand the difference between `CometChatUIKit.sendCustomMessage()` and `CometChat.sendCustomMessage()`. When you use `CometChatUIKit.sendCustomMessage()`, it automatically adds the message to the [MessagesComponent](/ui-kit/ios/message-header) and [ConversationsComponent](/ui-kit/ios/conversations), taking care of all related cases for you. On the other hand, `CometChat.sendCustomMessage()` only sends the message and doesn't automatically update these components in the UI Kit. + +`CometChatUIKit.sendCustomMessage()` automatically adds the message to the [MessagesComponent](/ui-kit/ios/message-list) and [ConversationsComponent](/ui-kit/ios/conversations), handling all related cases for you. In contrast, `CometChat.sendCustomMessage()` only sends the message without updating these UI Kit components. + -*** +--- ### Interactive Message #### Form Message -As a developer, if you need to send a Form message to a single user or a group, you'll need to utilize the `sendFormMessage()` function. This function requires a `FormMessage` object as its argument, which contains the necessary information to create a form bubble for that messages - -The concluding code block: +To send a Form message to a single user or a group, use the `sendFormMessage()` function. This function requires a `FormMessage` object containing the necessary information to create a form bubble for that message. -```swift +```swift lines let apiAction = APIAction() apiAction.url = "https://example.com/api" apiAction.method = .POST @@ -295,22 +306,18 @@ CometChatUIKit.sendFormMessage(formMessage) { form in print("CometChat exception: \(error)") } ``` - - -*** +--- #### Card Message -As a developer, if you need to send a Card message to a single user or a group, you'll need to utilize the `sendCardMessage()` function. This function requires a `CardMessage` object as its argument, which contains the necessary information to create a card bubble for the messages. - -The concluding code block: +To send a Card message to a single user or a group, use the `sendCardMessage()` function. This function requires a `CardMessage` object containing the necessary information to create a card bubble for the message. -```swift +```swift lines let apiAction = APIAction() apiAction.url = "https://example.com/api" apiAction.method = .POST @@ -328,22 +335,18 @@ CometChatUIKit.sendCardMessage(cardMessage) { success in print("CometChat exception: \(error)") } ``` - - -*** +--- #### Scheduler Message -As a developer, if you need to send a Scheduler message to a single user or a group, you'll need to utilize the `sendSchedulerMessage()` function. This function requires a `SchedulerMessage` object as its argument, which contains the necessary information to create a SchedulerMessage bubble for the messages. - -The concluding code block: +To send a Scheduler message to a single user or a group, use the `sendSchedulerMessage()` function. This function requires a `SchedulerMessage` object containing the necessary information to create a scheduler bubble for the message. -```swift +```swift lines var interactiveData = [String: Any]() interactiveData["key"] = "value" @@ -355,9 +358,26 @@ CometChatUIKit.sendSchedulerMessage(schedulerMessage: schedulerMessage) { schedu print("CometChat exception: \(error)") } ``` - - -*** +--- + +## Next Steps + + + + Listen and respond to UI Kit events. + + + Set up CometChat iOS UI Kit. + + + Display and customize chat messages. + + + Manage conversation lists. + + + +--- diff --git a/ui-kit/ios/ongoing-call.mdx b/ui-kit/ios/ongoing-call.mdx index f7715039e..3d5ecef29 100644 --- a/ui-kit/ios/ongoing-call.mdx +++ b/ui-kit/ios/ongoing-call.mdx @@ -1,26 +1,66 @@ --- title: "Ongoing Call" +description: "Displays active call interface with video, controls, and participant management" --- -## Overview - -The `Ongoing Call` is a [Component](/ui-kit/ios/components-overview#components) that provides users with a dedicated interface for managing real-time voice or video conversations. It includes features like a video display area for video calls, call controls for mic and camera management, participant information, call status indicators, and options for call recording and screen-sharing. +The `CometChatOngoingCall` component provides users with a dedicated interface for managing real-time voice or video conversations. It includes features like a video display area for video calls, call controls for mic and camera management, participant information, call status indicators, and options for call recording and screen-sharing. -*** + +```json +{ + "component": "CometChatOngoingCall", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatCallsSDK", + "description": "Displays active call interface with video, controls, and participant management", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onCallEnded", + "type": "(Call) -> Void" + }, + "props": { + "data": { + "sessionID": { "type": "String", "required": true }, + "callSettingsBuilder": { "type": "CallSettingsBuilder?", "default": "nil" } + }, + "callbacks": { + "onCallEnded": "(Call) -> Void", + "onError": "(CometChatException) -> Void" + } + }, + "events": [ + { "name": "onCallEnded", "payload": "Call", "description": "Fires when call ends" } + ], + "sdkListeners": [], + "compositionExample": { + "description": "OngoingCall is presented during an active call", + "components": ["CometChatIncomingCall", "CometChatOutgoingCall", "CometChatOngoingCall"], + "flow": "Call accepted → OngoingCall shown → Call ends → Returns to previous screen" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatOngoingCall` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | + +--- ## Usage ### Integration -`CometChatOngoingCall` being a custom **view controller**, offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application. +`CometChatOngoingCall` is a custom view controller that offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application. -```swift +```swift lines // The sessionID should be received from CometChat SDK when the call was initiated or received let sessionID = "your_session_id" @@ -29,50 +69,43 @@ cometChatOngoingCall.set(sessionID: sessionID) cometChatOngoingCall.modalPresentationStyle = .fullScreen self.present(cometChatOngoingCall, animated: true) ``` - - - If you are already using a navigation controller, you can use the `pushViewController` function instead of presenting the view controller. - ### Actions [Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. -##### 1. SetOnCallEnded +#### 1. SetOnCallEnded -The `setOnCallEnded` action is typically triggered when the call is ended, carrying out default actions. However, with the following code snippet, you can effortlessly customize or override this default behavior to meet your specific needs. +The `setOnCallEnded` action is typically triggered when the call ends, carrying out default actions. You can customize or override this default behavior using the following code snippet: -```swift +```swift lines let cometChatOngoingCall = CometChatOngoingCall() .setOnCallEnded { call in - //Perform Your Action - + // Perform your action } ``` - - -*** +--- ### Filters -**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK. +Filters allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria for a more customized experience. Filters can be applied using RequestBuilders of the Chat SDK. -You can adjust the `callSettingsBuilder` in the `OnGoing Call` Component to customize the OnGoing Call. Numerous options are available to alter the builder to meet your specific needs. For additional details on `CallSettingsBuilder`, please visit [CallSettingsBuilder](/sdk/ios/direct-calling). +You can adjust the `callSettingsBuilder` in the OnGoing Call Component to customize the call. Numerous options are available to alter the builder to meet your specific needs. For additional details on `CallSettingsBuilder`, visit [CallSettingsBuilder](/sdk/ios/direct-calling). -##### 1. CallSettingsBuilder +#### 1. CallSettingsBuilder -The [CallSettingsBuilder](/sdk/ios/direct-calling) enables you to filter and customize the call list based on available parameters in CallSettingsBuilder. This feature allows you to create more specific and targeted queries during the call. The following are the parameters available in [CallSettingsBuilder](/sdk/ios/direct-calling) +The [CallSettingsBuilder](/sdk/ios/direct-calling) enables you to filter and customize the call list based on available parameters. This feature allows you to create more specific and targeted queries during the call. | Methods | Description | Code | | -------------------------------- | -------------------------------------------- | ----------------------------------------- | @@ -98,13 +131,13 @@ The [CallSettingsBuilder](/sdk/ios/direct-calling) enables you to filter and cus | **setVideoContainer** | Set the video container | `.setVideoContainer(NSMutableDictionary)` | | **setVideoSettings** | Set the video settings | `.setVideoSettings(NSMutableDictionary)` | -**Example** +#### Example -In the example below, we are applying a filter to the calls. +In the example below, we are applying a filter to the calls: -```swift +```swift lines let callBuilder = CallSettingsBuilder() .setAudioModeButtonDisable(true) .setEndCallButtonDisable(false) @@ -116,24 +149,18 @@ let cometChatOngoingCall = CometChatOngoingCall() cometChatOngoingCall.modalPresentationStyle = .fullScreen self.present(cometChatOngoingCall, animated: true) ``` - - - -Ensure to include an `NSMicrophoneUsageDescription` key with a descriptive string value in the app's Info.plist - +Ensure to include an `NSMicrophoneUsageDescription` key with a descriptive string value in the app's Info.plist. -*** +--- ### Events -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. - -Events emitted by the Ongoing Call component is as follows. +[Events](/ui-kit/ios/components-overview#events) are emitted by a Component. By using events, you can extend existing functionality. Being global events, they can be applied in multiple locations and can be added or removed as needed. | Event | Description | | --------------- | ------------------------------------------------ | @@ -141,72 +168,66 @@ Events emitted by the Ongoing Call component is as follows. -```swift -// View controller from your project where you want to listen events. +```swift lines +// View controller from your project where you want to listen to events public class ViewController: UIViewController { public override func viewDidLoad() { super.viewDidLoad() - // Subscribing for the listener to listen events from user module + // Subscribe to the listener for call events CometChatCallEvents.addListener("UNIQUE_ID", self as CometChatCallEventListener) } - } - // Listener events from user module -extension ViewController: CometChatCallEventListener { + +// Listener for call events +extension ViewController: CometChatCallEventListener { func onCallEnded(call: Call) { - // Do Stuff + // Handle call ended } } ``` -```swift Emitting Group Events -//emit this when logged in user cancels a call +```swift Emitting Call Events +// Emit this when logged in user ends a call CometChatCallEvents.emitOnCallEnded(call: Call) ``` - - -*** - -```swift View Controller +```swift lines public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module + // Unsubscribe from the listener CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") } ``` - - -*** +--- ## Customization -To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. +To fit your app's design requirements, you can customize the appearance of the component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. ### Style -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +Using Style, you can customize the look and feel of the component in your app. These parameters typically control elements such as the color, size, shape, and fonts used within the component. The OngoingCall component does not have any exposed Styles. -*** +--- ### Functionality -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. +These are small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. -```swift +```swift lines let cometChatOngoingCall = CometChatOngoingCall() .set(sessionId: "Your Session ID") .set(callWorkFlow: .defaultCalling) @@ -214,28 +235,121 @@ let cometChatOngoingCall = CometChatOngoingCall() cometChatOngoingCall.modalPresentationStyle = .fullScreen self.present(cometChatOngoingCall, animated: true) ``` - - - -If you are already using a navigation controller, you can use the pushViewController function instead of presenting the view controller. - +If you are already using a navigation controller, you can use the `pushViewController` function instead of presenting the view controller. -Below is a list of customizations along with corresponding code snippets - | Property | Description | Code | | ---------------- | ---------------------------------------------- | ------------------------- | -| **CallWorkFlow** | Sets the call type to default and direct. | `CallWorkFlow` | -| **Session Id** | Sets the user object for CometChatOngoingCall. | `.set(sessionId: String)` | +| **CallWorkFlow** | Sets the call type to default or direct. | `CallWorkFlow` | +| **Session Id** | Sets the session ID for CometChatOngoingCall. | `.set(sessionId: String)` | ### Advanced -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. +For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your own views, layouts, and UI elements and then incorporate those into the component. The `OngoingCall` component does not provide additional functionalities beyond this level of customization. -*** +--- + +## Common Patterns + +### Present Ongoing Call After Acceptance + +Show the ongoing call screen after a call is accepted: + + + +```swift lines +func presentOngoingCall(sessionId: String) { + let ongoingCall = CometChatOngoingCall() + ongoingCall.set(sessionId: sessionId) + ongoingCall.modalPresentationStyle = .fullScreen + + self.present(ongoingCall, animated: true) +} +``` + + + +### Configure Call Settings for Video Call + +Customize video call settings before starting: + + + +```swift lines +let callSettingsBuilder = CallSettingsBuilder() + .setIsAudioOnly(false) + .setDefaultAudioMode("SPEAKER") + .setShowSwitchToVideoCall(false) + .setShowRecordingButton(true) + .setStartVideoMuted(false) + .setStartAudioMuted(false) + +let ongoingCall = CometChatOngoingCall() +ongoingCall.set(sessionId: sessionId) +ongoingCall.set(callSettingsBuilder: callSettingsBuilder) +``` + + + +### Audio-Only Call Configuration + +Set up an audio-only call with speaker mode: + + + +```swift lines +let audioCallSettings = CallSettingsBuilder() + .setIsAudioOnly(true) + .setDefaultAudioMode("SPEAKER") + .setMuteAudioButtonDisable(false) + .setEndCallButtonDisable(false) + +let ongoingCall = CometChatOngoingCall() +ongoingCall.set(sessionId: sessionId) +ongoingCall.set(callSettingsBuilder: audioCallSettings) +ongoingCall.modalPresentationStyle = .fullScreen +self.present(ongoingCall, animated: true) +``` + + + +### Listen for Call End Events + +Use CometChatCallEvents to handle call end: + + + +```swift lines +// Subscribe to call events +CometChatCallEvents.addListener("ongoing_call_listener", self as CometChatCallEventListener) + +// In CometChatCallEventListener extension +func onCallEnded(call: Call) { + DispatchQueue.main.async { [weak self] in + self?.dismiss(animated: true) { + // Show call summary + let duration = call.duration ?? 0 + let minutes = duration / 60 + let seconds = duration % 60 + + let alert = UIAlertController( + title: "Call Ended", + message: "Duration: \(minutes)m \(seconds)s", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + self?.present(alert, animated: true) + } + } +} +``` + + + +--- diff --git a/ui-kit/ios/outgoing-call.mdx b/ui-kit/ios/outgoing-call.mdx index 11519e75e..1d1a0cdc1 100644 --- a/ui-kit/ios/outgoing-call.mdx +++ b/ui-kit/ios/outgoing-call.mdx @@ -1,100 +1,137 @@ --- title: "Outgoing Call" +description: "Displays outgoing call interface while waiting for recipient to answer" --- -## Overview - -The `Outgoing Call` [Component](/ui-kit/ios/components-overview#components) is a visual representation of a user-initiated call, whether it's a voice or video call. It serves as an interface for managing outgoing calls, providing users with essential options to control the call experience. This component typically includes information about the call recipient, call controls for canceling the call, and feedback on the call status, such as indicating when the call is in progress. +The `CometChatOutgoingCall` component is a visual representation of a user-initiated call, whether voice or video. It serves as an interface for managing outgoing calls, providing users with essential options to control the call experience. - + CometChatOutgoingCall showing outgoing call interface with recipient avatar, name, and cancel button -*** + +```json +{ + "component": "CometChatOutgoingCall", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays outgoing call interface while waiting for recipient to answer", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onCancelClick", + "type": "(Call, UIViewController) -> Void" + }, + "props": { + "data": { + "call": { "type": "Call", "required": true } + }, + "callbacks": { + "onCancelClick": "(Call, UIViewController) -> Void", + "onError": "(CometChatException) -> Void" + }, + "sound": { + "disableSoundForCalls": { "type": "Bool", "default": false }, + "customSoundForCalls": { "type": "URL?", "default": "nil" } + }, + "viewSlots": { + "listItemView": "(Call) -> UIView", + "leadingView": "(Call) -> UIView", + "titleView": "(Call) -> UIView" + } + }, + "events": [ + { "name": "onOutgoingCallAccepted", "payload": "Call", "description": "Fires when outgoing call is accepted" }, + { "name": "onOutgoingCallRejected", "payload": "Call", "description": "Fires when outgoing call is rejected" } + ], + "sdkListeners": [], + "compositionExample": { + "description": "OutgoingCall is presented when user initiates a call", + "components": ["CometChatCallButtons", "CometChatOutgoingCall", "CometChatOngoingCall"], + "flow": "User taps call → OutgoingCall shown → Recipient answers → OngoingCall starts" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatOutgoingCall` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | + +--- ## Usage ### Integration -`CometChatOutgoingCall` being a custom **view controller**, offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application. +`CometChatOutgoingCall` is a custom view controller that offers versatility in its integration. It can be seamlessly launched via button clicks or any user-triggered action, enhancing the overall user experience and facilitating smoother interactions within the application. -```swift +```swift lines let cometChatOutgoingCall = CometChatOutgoingCall() cometChatOutgoingCall.set(call: call) cometChatOutgoingCall.modalPresentationStyle = .fullScreen self.present(cometChatOutgoingCall, animated: true) ``` - - - If you are already using a navigation controller, you can use the `pushViewController` function instead of presenting the view controller. - ### Actions [Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. -##### 1. SetOnCancelClick +#### 1. SetOnCancelClick -The `setOnCancelClick` action is typically triggered when the call is ended, carrying out default actions. However, with the following code snippet, you can effortlessly customize or override this default behavior to meet your specific needs. +The `setOnCancelClick` action is typically triggered when the call is canceled, carrying out default actions. You can customize or override this default behavior using the following code snippet: -```swift +```swift lines let cometChatOutgoingCall = CometChatOutgoingCall() cometChatOutgoingCall.set(onCancelClick: { call, controller in -//Perform Your Action + // Perform your action }) ``` - - -*** +--- -##### 2. OnError +#### 2. OnError -You can customize this behavior by using the provided code snippet to override the `On Error` and improve error handling. +You can customize error handling behavior by using the provided code snippet to override the `onError` callback: -```swift - +```swift lines let incomingCallConfiguration = CometChatOutgoingCall() -.set(onError:{ error in -//Perform Your Action - +.set(onError: { error in + // Perform your action }) ``` - - -*** +--- ### Filters -**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK. +Filters allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria for a more customized experience. Filters can be applied using RequestBuilders of the Chat SDK. The OutgoingCall component does not have any exposed filters. -*** +--- ### Events -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. - -Events emitted by the Outgoing call component is as follows. +[Events](/ui-kit/ios/components-overview#events) are emitted by a Component. By using events, you can extend existing functionality. Being global events, they can be applied in multiple locations and can be added or removed as needed. | Event | Description | | -------------------------- | -------------------------------------------- | @@ -103,77 +140,71 @@ Events emitted by the Outgoing call component is as follows. -```swift -// View controller from your project where you want to listen events. +```swift lines +// View controller from your project where you want to listen to events public class ViewController: UIViewController { public override func viewDidLoad() { super.viewDidLoad() - // Subscribing for the listener to listen events from user module + // Subscribe to the listener for call events CometChatCallEvents.addListener("UNIQUE_ID", self as CometChatCallEventListener) } - } - // Listener events from user module -extension ViewController: CometChatCallEventListener { + +// Listener for call events +extension ViewController: CometChatCallEventListener { func onOutgoingCallAccepted(call: Call) { - // Do Stuff + // Handle call accepted } - func onOutgoingCallRejected(call: Call){ - // Do Stuff + func onOutgoingCallRejected(call: Call) { + // Handle call rejected } } ``` -```swift Emitting Group Events -//emit this when the other user accepts the call +```swift Emitting Call Events +// Emit this when the other user accepts the call CometChatCallEvents.emitOnOutgoingCallAccepted(call: Call) -//emit this when the other user rejects a call +// Emit this when the other user rejects a call CometChatCallEvents.emitOnOutgoingCallRejected(call: Call) ``` - - -*** - -```swift View Controller +```swift lines public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module + // Unsubscribe from the listener CometChatCallEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") } ``` - - -*** +--- ## Customization -To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. +To fit your app's design requirements, you can customize the appearance of the component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. ### Style -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +Using Style, you can customize the look and feel of the component in your app. These parameters typically control elements such as the color, size, shape, and fonts used within the component. -##### 1. OutgoingCall Style +#### 1. OutgoingCall Style -You can customize the appearance of the `OutgoingCall` Component by applying the `OutgoingCallStyle` to it using the following code snippet. +You can customize the appearance of the `OutgoingCall` Component by applying the `OutgoingCallStyle` to it. **Global level styling** -```swift +```swift lines let customAvatarStyle = AvatarStyle() customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) @@ -183,16 +214,14 @@ CometChatOutgoingCall.style.callLabelFont = UIFont(name: "Times-New-Roman", size CometChatOutgoingCall.style.declineButtonCornerRadius = .init(cornerRadius: 8) CometChatOutgoingCall.avatarStyle = customAvatarStyle ``` - - **Instance level styling** -```swift +```swift lines let customAvatarStyle = AvatarStyle() customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) @@ -206,16 +235,14 @@ let outgoingCall = CometChatOutgoingCall() outgoingCall.style = outgoingCallStyle outgoingCall.avatarStyle = customAvatarStyle ``` - - - + CometChatOutgoingCall with custom styling showing custom fonts and rounded decline button -List of properties exposed by OutgoingCallStyle +#### OutgoingCallStyle Properties | Property | Description | Code | | ------------------------------ | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | @@ -230,15 +257,15 @@ List of properties exposed by OutgoingCallStyle | `declineButtonBackgroundColor` | Sets the background color for the decline button in the outgoing call view. | `CometChatOutgoingCall.style.declineButtonBackgroundColor = UIColor()` | | `declineButtonIconTint` | Sets the tint color for the decline button icon. | `CometChatOutgoingCall.style.declineButtonIconTint = UIColor()` | | `declineButtonIcon` | Sets the icon for the decline button. | `CometChatOutgoingCall.style.declineButtonIcon = UIImage(systemName: "phone.down.fill")` | -| `declineButtonCornerRadius` | Sets the corner radius for decline button. | `CometChatOutgoingCall.style.declineButtonCornerRadius: CometChatCornerStyle?` | -| `declineButtonBorderColor` | Sets the border color for decline button. | `CometChatOutgoingCall.style.declineButtonBorderColor: UIColor?` | -| `declineButtonBorderWidth` | Sets the border width for decline button. | `CometChatOutgoingCall.style.declineButtonBorderWidth: CGFloat?` | +| `declineButtonCornerRadius` | Sets the corner radius for the decline button. | `CometChatOutgoingCall.style.declineButtonCornerRadius: CometChatCornerStyle?` | +| `declineButtonBorderColor` | Sets the border color for the decline button. | `CometChatOutgoingCall.style.declineButtonBorderColor: UIColor?` | +| `declineButtonBorderWidth` | Sets the border width for the decline button. | `CometChatOutgoingCall.style.declineButtonBorderWidth: CGFloat?` | -*** +--- ### Functionality -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. +These are small functional customizations that allow you to fine-tune the overall experience of the component. | Property | Description | Code | | ---------------------- | --------------------------------------- | ------------------------------- | @@ -247,34 +274,34 @@ These are a set of small functional customizations that allow you to fine-tune t ### Advanced -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. +For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your own views, layouts, and UI elements and then incorporate those into the component. -#### SetAvatarVieww +#### SetAvatarView -With this function, you can assign a custom view to the avatar of OutgoingCall Component. +With this function, you can assign a custom view to the avatar of the OutgoingCall Component. -```swift +```swift lines cometChatOutgoingCall.set(avatarView: { call in let customView = CustomAvatarView() return customView }) ``` - - -Demonstration +**Demonstration** - + CometChatOutgoingCall with custom avatar view showing profile image with star badge overlay -You can create a CustomAvatarView as a custom `UIView`. +You can create a `CustomAvatarView` as a custom `UIView`: -```swift swift + + +```swift lines import UIKit class CustomAvatarView: UIView { @@ -339,37 +366,37 @@ class CustomAvatarView: UIView { } } ``` + + -*** +--- #### SetCancelView -You can modify the cancel call view of a Outgoing call component using the property below. +You can modify the cancel call view of the Outgoing call component using the property below: -```swift +```swift lines cometChatOutgoingCall.set(cancelView: { call in let view = CustomCancelView() return view }) ``` - - -Demonstration +**Demonstration** - + CometChatOutgoingCall with custom cancel view showing red End Call button with phone icon -You can create a CustomCancelView as a custom `UIView`. +You can create a `CustomCancelView` as a custom `UIView`: -```swift +```swift lines import UIKit class EndCallButton: UIButton { @@ -420,42 +447,38 @@ class EndCallButton: UIButton { } } ``` - - -*** +--- #### SetTitleView -You can customize the title view of a outgoing call component using the property below. +You can customize the title view of the outgoing call component using the property below: -```swift +```swift lines cometChatOutgoingCall.set(titleView: { call in let view = CustomTitleView() - view.configure(call:call) + view.configure(call: call) return view }) ``` - - -Demonstration +**Demonstration** - + CometChatOutgoingCall with custom title view showing call initiator and receiver names -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +You can create a `CustomTitleView` as a custom `UIView`: -```swift +```swift lines import UIKit class CustomTitleView: UILabel { @@ -471,52 +494,47 @@ class CustomTitleView: UILabel { } private func setupView() { - font = UIFont.boldSystemFont(ofSize: 22) textAlignment = .center translatesAutoresizingMaskIntoConstraints = false } - func configure(call:Call){ - text = "\(call.callInitiator <> \(call.receiver))" + func configure(call: Call) { + text = "\(call.callInitiator) <> \(call.receiver)" } } ``` - - -*** +--- #### SetSubtitleView -You can modify the subtitle view of a outgoing call component using the property below. +You can modify the subtitle view of the outgoing call component using the property below: -```swift +```swift lines cometChatOutgoingCall.set(subtitleView: { call in let view = CustomSubtitleView() return view }) ``` - - -Demonstration +**Demonstration** - + CometChatOutgoingCall with custom subtitle view showing phone icon and Calling status text -You can create a CustomSubtitleView as a custom `UIView`. +You can create a `CustomSubtitleView` as a custom `UIView`: -```swift +```swift lines import UIKit class CustomSubtitleView: UIStackView { @@ -558,9 +576,221 @@ class CustomSubtitleView: UIStackView { } } ``` + + + +--- + + +## Props + +All props are optional unless noted. + +--- + +### call + +The outgoing call object to display. + +| | | +|---|---| +| Type | `Call` | +| Default | `undefined` | + +--- + +### disableSoundForCalls + +Disables the outgoing call ringtone. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +--- + +### customSoundForCalls + +Custom sound file URL for outgoing calls. + +| | | +|---|---| +| Type | `URL?` | +| Default | `nil` | + +--- + +### avatarStyle + +Customizes the appearance of the recipient's avatar. + +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | + +```swift lines +import CometChatUIKitSwift + +let customAvatarStyle = AvatarStyle() +customAvatarStyle.backgroundColor = UIColor.systemOrange +customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) + +let outgoingCall = CometChatOutgoingCall() +outgoingCall.avatarStyle = customAvatarStyle +``` + +--- + +## Events + +Events emitted by the Outgoing Call component: + +| Event | Description | +|-------|-------------| +| `onOutgoingCallAccepted` | Triggers when the outgoing call is accepted by the recipient | +| `onOutgoingCallRejected` | Triggers when the outgoing call is rejected by the recipient | + +--- + +## View Slots + +| Slot | Signature | Replaces | +|------|-----------|----------| +| `avatarView` | `(Call) -> UIView` | Recipient avatar | +| `cancelView` | `(Call) -> UIView` | Cancel call button | +| `titleView` | `(Call) -> UIView` | Recipient name | +| `subtitleView` | `(Call) -> UIView` | "Calling..." text | +| `leadingView` | `(Call) -> UIView` | Left section | +| `trailingView` | `(Call) -> UIView` | Right section | + +### leadingView + +You can customize the leading view of an outgoing call component using the property below. + + + +```swift lines +cometChatOutgoingCall.set(leadingView: { call in + let view = CustomLeadingView() + return view +}) +``` + + + +### trailingView + +You can customize the trailing view of an outgoing call component using the property below. + + + +```swift lines +cometChatOutgoingCall.set(trailingView: { call in + let view = CustomTrailingView() + return view +}) +``` + + + +--- + +## Common Patterns + +### Initiate Call and Present Outgoing Screen + +Start a call and show the outgoing call interface: + + + +```swift lines +func initiateCall(to user: User, callType: CometChat.CallType) { + let call = Call(receiverId: user.uid ?? "", callType: callType, receiverType: .user) + + CometChat.initiateCall(call: call) { [weak self] initiatedCall in + guard let initiatedCall = initiatedCall else { return } + DispatchQueue.main.async { + let outgoingCall = CometChatOutgoingCall() + outgoingCall.set(call: initiatedCall) + outgoingCall.modalPresentationStyle = .fullScreen + self?.present(outgoingCall, animated: true) + } + } onError: { error in + print("Call initiation failed: \(error?.errorDescription ?? "")") + } +} +``` + + +### Handle Call Acceptance and Transition to Ongoing Call + +Navigate to ongoing call when the recipient accepts: + + + +```swift lines +// Subscribe to call events +CometChatCallEvents.addListener("outgoing_call_listener", self as CometChatCallEventListener) + +// In CometChatCallEventListener extension +func onOutgoingCallAccepted(call: Call) { + DispatchQueue.main.async { [weak self] in + self?.dismiss(animated: false) { + let ongoingCall = CometChatOngoingCall() + ongoingCall.set(sessionId: call.sessionId ?? "") + ongoingCall.modalPresentationStyle = .fullScreen + self?.present(ongoingCall, animated: true) + } + } +} +``` + + +### Custom Cancel Action with Confirmation +Show confirmation before canceling an outgoing call: + + + +```swift lines +let outgoingCall = CometChatOutgoingCall() +outgoingCall.set(call: call) +outgoingCall.set(onCancelClick: { [weak self] call, controller in + let alert = UIAlertController( + title: "Cancel Call", + message: "Are you sure you want to cancel this call?", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "No", style: .cancel)) + alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { _ in + CometChat.rejectCall(sessionID: call.sessionId ?? "", status: .cancelled) { _ in + controller.dismiss(animated: true) + } onError: { error in + print("Failed to cancel: \(error?.errorDescription ?? "")") + } + }) + controller.present(alert, animated: true) +}) +``` + -*** +--- + +## Related Components + + + + Display incoming call interface + + + Display active call interface + + + Display call history + + diff --git a/ui-kit/ios/overview.mdx b/ui-kit/ios/overview.mdx index aa00a339f..dc56ca772 100644 --- a/ui-kit/ios/overview.mdx +++ b/ui-kit/ios/overview.mdx @@ -1,100 +1,135 @@ --- title: "CometChat UI Kit For iOS" sidebarTitle: "Overview" +description: "Integrate chat functionality into iOS applications with prebuilt, modular, and customizable UI components" --- -The **CometChat UI Kit** for iOS provides a seamless solution to integrate chat functionality into your iOS applications. With prebuilt, modular, and customizable UI components, it accelerates development and ensures your chat application is robust, scalable, and tailored to your needs. + +```json +{ + "platform": "iOS UI Kit", + "package": "CometChatUIKitSwift", + "version": "5.0.0", + "description": "Pre-built UI components for iOS chat applications using SwiftUI", + "metadata": { + "peerDependencies": { + "CometChatSDK": ">= 4.0.0" + }, + "supportedPlatforms": ["iOS 13.0+", "iPadOS 13.0+", "Mac Catalyst 13.0+"], + "language": "Swift 5.0+", + "license": "MIT" + }, + "quickLinks": { + "documentation": "https://www.cometchat.com/docs/ui-kit/ios/overview", + "repository": "https://github.com/cometchat/cometchat-uikit-ios", + "demo": "https://demo.cometchat.com" + } +} +``` + + +| Property | Value | +|----------|-------| +| Package | CometChatUIKitSwift | +| Version | 5.0.0 | +| Peer Dependencies | CometChatSDK >= 4.0.0 | +| Platforms | iOS 13.0+, iPadOS 13.0+, Mac Catalyst 13.0+ | +| Language | Swift 5.0+ | +| License | MIT | -*** +--- -## **Why Choose CometChat UI Kit?** +## Introduction -* **Effortless Integration** – Ready-to-use SwiftUI components for rapid implementation. -* **Highly Customizable** – Adapt UI components easily to match your brand and user experience requirements. -* **Built on Core SDK** – Leverages the powerful [CometChat iOS SDK](/sdk/ios/overview) for reliable performance. -* **Scalable & Reliable** – Optimized for enterprise-grade applications. +The CometChat UI Kit for iOS provides a seamless solution to integrate chat functionality into your iOS applications. With prebuilt, modular, and customizable UI components, it accelerates development and ensures your chat application is robust, scalable, and tailored to your needs. -*** +### Key Features -## **User Interface Preview** +- Effortless Integration: Ready-to-use SwiftUI components for rapid implementation +- Highly Customizable: Adapt UI components to match your brand and user experience requirements +- Built on Core SDK: Leverages the powerful [CometChat iOS SDK](/sdk/ios/overview) for reliable performance +- Scalable & Reliable: Optimized for enterprise-grade applications - - - +--- -*** +## Try It -## **Download the CometChat Demo App** + + + Experience the UI Kit in action with our interactive demo + + + Explore the complete source code on GitHub + + -Get started with the **CometChat UI Kit** on your mobile device: +--- -**Download from the App Store** +## Get Started -[](https://link.cometchat.com/ios-demo-app) +Before integrating the CometChat UI Kit, familiarize yourself with the key concepts and features offered by CometChat's platform: -**Or Scan the QR Code** +- Review the [Key Concepts](/fundamentals/key-concepts) to understand essential terminology and features +- Follow the [Getting Started Guide](/ui-kit/ios/getting-started) for detailed steps on initial setup and integration - + - -**Tip:** On iOS, simply open the camera app and scan the QR code to install directly. - - - -*** - -## **Getting Started** - -Before integrating the CometChat UI Kit, familiarize yourself with the key concepts and features offered by CometChat’s platform. - -* Review the [Key Concepts](/fundamentals/key-concepts) to understand essential terminology and features. -* Follow the [Getting Started Guide](/ui-kit/ios/getting-started) for detailed steps on initial setup and integration. - -*** - -## **Integration and Customization** - -The CometChat UI Kit consists of modular SwiftUI components that can be integrated effortlessly into your app, offering flexible customization: - -* **Prebuilt UI Components:** Ready-to-use chat UI elements. -* **Modular Structure:** Easy to integrate and modify. -* **Customization Options:** Highly configurable to fit your brand and UI requirements. - -Explore more about UI customization in the [Customization Guide](/ui-kit/ios/theme-introduction). - -*** - -## **Helpful Resources** - -Explore these essential resources to gain a deeper understanding of **CometChat UI Kits** and streamline your integration process. - -#### 🚀 iOS Sample App - -Fully functional sample applications to accelerate your development. - -[View on GitHub](https://github.com/cometchat/cometchat-uikit-ios) - -#### 📦 UI Kit Source Code - -Access the complete UI Kit source code on GitHub. - -[View on GitHub](https://github.com/cometchat/cometchat-uikit-ios) - -#### 🎨 Figma Design File - -UI design resources for customization and prototyping. - -[View on Figma](https://www.figma.com/community/file/1444325479486807899/cometchat-ui-kit-for-ios) - -*** +--- -## **💡 Need Help?** +## Explore + + + + Pre-built UI components for conversations, messages, users, and groups + + + Core messaging, calling, and AI-powered features + + + Customize colors, typography, and styling to match your brand + + + Step-by-step guides for integrating the UI Kit + + + Complete SDK documentation and API details + + + Tutorials and how-to guides for common use cases + + -If you need assistance, check out: +--- -* 💬 [Developer Community](http://community.cometchat.com/) -* ❓ [Support Portal](https://help.cometchat.com/hc/en-us/requests/new) +## Resources + + + + Try the interactive demo on your iOS device + + + Complete sample application source code + + + Step-by-step integration tutorials + + + Browse all available UI components + + + Explore messaging, calling, and AI features + + + Customize the look and feel + + + Common issues and solutions + + + Get help from our support team + + -*** +--- diff --git a/ui-kit/ios/property-changes.mdx b/ui-kit/ios/property-changes.mdx deleted file mode 100644 index 42d568992..000000000 --- a/ui-kit/ios/property-changes.mdx +++ /dev/null @@ -1,1041 +0,0 @@ ---- -title: "Property Changes" ---- - - - -## Conversations - -### New Properties - -| Name | Type | Description | -| --------------------------- | ------------- | ----------------------------------------------------------------------------------- | -| hideNavigationBar | Bool | Hides or shows the navigation bar in the conversations screen. | -| hideSearch | Bool | Hides the search bar in the conversations screen. | -| hideLoadingState | Bool | Hides the loading state indicator. | -| hideDeleteConversationOption | Bool | Hides the option to delete a conversation. | -| hideGroupType | Bool | Hides the group type indicator (private/public). | -| backgroundDrawable | UIImage | Used to set a background image for the conversation screen. | -| separatorColor | UIColor | Used to set the color of separators in the conversation list. | -| separatorWidth | CGFloat | Used to set the width of separators in the conversation list. | -| errorTextColor | UIColor | Used to set the color of error messages in the conversation UI. | -| lastMessageTextColor | UIColor | Used to set the color of the last message text in the conversation list. | -| typingIndicatorColor | UIColor | Used to set the color of the typing indicator in the conversation UI. | -| lastMessageAppearance | UIFont | Used to customize the appearance of the last message text in the list. | -| threadIndicatorAppearance | UIFont | Used to customize the appearance of thread indicators in the list. | -| dateTimeFormatter.time | Closure | Called to format a timestamp as a standard time (e.g., "12:30 PM"). | -| dateTimeFormatter.today | Closure | Called when rendering messages sent today. | -| dateTimeFormatter.yesterday | Closure | Called for yesterday's messages. | -| dateTimeFormatter.lastweek | Closure | Called for messages within the last week. | -| dateTimeFormatter.otherDay | Closure | Called for dates older than last week. | -| dateTimeFormatter.minute | Closure | Called when referring to "a minute ago". | -| dateTimeFormatter.minutes | Closure | Called for "x minutes ago". | -| dateTimeFormatter.hour | Closure | Called for "an hour ago". | -| dateTimeFormatter.hours | Closure | Called for "x hours ago". | -| set(OnItemLongClick:) | Method | Triggered when you long press on a ListItem of the Conversations component. | -| set(onEmpty:) | Method | Triggered when the conversations list is empty. | - -### Renamed Properties - -| v4 Name | v5 Name | Type | Description | -| ----------------------- | ------------------ | -------- | ------------------------------------------------------------------------------------ | -| hide(error: Bool) | hideErrorView | Bool | Hides the error state view. | -| show(backButton: Bool) | hideBackButton | Bool | Controls visibility of the back button (logic inverted). | -| hide(receipt: Bool) | hideReceipts | Bool | Hides message read/delivery receipts. | -| disable(userPresence: Bool) | hideUserStatus | Bool | Hides the online/offline status of users. | -| setOnItemClick | set(OnItemClick:) | Method | Triggered when clicking on a ListItem. | -| setOnBack | set(onBack:) | Method | Override action when back button is pressed. | -| setOnSelection | set(onSelection:) | Method | Triggered upon completion of selection. | -| setOnError | set(onError:) | Method | Override action when an error occurs. | - -### Removed Properties - -| Name | Type | Description | -| -------------------- | ------------ | ----------------------------------------------------------------------------------- | -| hide(separator: Bool) | Bool | Used to control visibility of separators in the list view (replaced by style properties). | -| disable(typing: Bool) | Bool | Used to toggle visibility of typing indicator. | -| setDatePattern | Method | Method to set custom date pattern (replaced by dateTimeFormatter object). | -| protectedGroupIcon | UIImage | Icon shown for password protected groups. | -| sentIcon | UIImage | Receipt icon shown when message status is sent. | -| deliveredIcon | UIImage | Receipt icon shown when message status is delivered. | -| readIcon | UIImage | Receipt icon shown when message status is read. | - -## Users - -### New Properties - -| Name | Type | Description | -| -------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------- | -| set(options:) | (User) -> [CometChatUserOption] | Used to define custom options for each user. | -| add(options:) | [CometChatUserOption] | Used to dynamically add options to users. | -| set(leadingView:) | (User) -> UIView | Custom leading view to be rendered for each user in the fetched list. | -| set(titleView:) | (User) -> UIView | Custom title view to be rendered for each user in the fetched list. | -| set(trailView:) | (User) -> UIView | Custom trailing view to be rendered for each user in the fetched list. | -| set(onEmpty:) | () -> Void | Triggered when the users list is empty. | -| hideErrorView | Bool | Hides the error state view. | -| hideNavigationBar | Bool | Hides or shows the navigation bar. | -| hideBackButton | Bool | Hides the back button. | -| hideLoadingState | Bool | Hides the loading state indicator. | -| hideUserStatus | Bool | Hides the online/offline status of users. | -| hideSectionHeader | Bool | Hides the section header for table view indicating initials of users. | -| hideSearch | Bool | Hides the search bar. | -| set(searchKeyword:) | String | Sets a search keyword for filtering users. | -| set(userRequestBuilder:) | UsersRequest.UsersRequestBuilder | Sets a custom request builder for fetching users. | -| set(searchRequestBuilder:) | UsersRequest.UsersRequestBuilder | Sets a custom request builder for searching users. | -| listItemSelectedImage | UIImage | Image shown when a list item is selected. | -| listItemDeSelectedImage | UIImage | Image shown when a list item is deselected. | -| searchIconTintColor | UIColor | Tint color for the search icon in the search bar. | -| searchBarStyle | UISearchBar.Style | Style of the search bar (e.g., default, prominent). | -| searchTintColor | UIColor? | Tint color for the search bar elements. | -| searchBarTintColor | UIColor? | Background color for the search bar (excluding text input). | -| searchBarPlaceholderTextColor | UIColor? | Color of the placeholder text in the search bar. | -| searchBarPlaceholderTextFont | UIFont? | Font of the placeholder text in the search bar. | -| searchBarTextColor | UIColor? | Color of the entered text in the search bar. | -| searchBarTextFont | UIFont? | Font of the entered text in the search bar. | -| searchBarBackgroundColor | UIColor? | Background color of the search bar's text input area. | -| searchBarCancelIconTintColor | UIColor? | Tint color for the cancel button in the search bar. | -| searchBarCrossIconTintColor | UIColor? | Tint color for the clear (cross) button in the search bar. | -| backgroundColor | UIColor | Background color for the entire screen or view. | -| borderWidth | CGFloat | Border width for the search bar or container. | -| borderColor | UIColor | Color of the border. | -| cornerRadius | CometChatCornerStyle | Corner radius for search bar or other elements. | -| titleColor | UIColor | Text color for title elements within the list or navigation bar. | -| titleFont | UIFont | Font for title text. | -| largeTitleColor | UIColor | Text color for large titles. | -| largeTitleFont | UIFont? | Font for large titles. | -| navigationBarTintColor | UIColor | Tint color for the navigation bar background. | -| navigationBarItemsTintColor | UIColor | Tint color for navigation bar items (buttons, icons). | -| errorTitleTextFont | UIFont | Font for the error title displayed in UI. | -| errorTitleTextColor | UIColor | Text color for the error title. | -| errorSubTitleFont | UIFont | Font for the subtitle of error messages. | -| errorSubTitleTextColor | UIColor | Text color for the subtitle of error messages. | -| retryButtonTextColor | UIColor | Text color for the retry button in error states. | -| retryButtonTextFont | UIFont | Font for the retry button text. | -| retryButtonBackgroundColor | UIColor | Background color for the retry button. | -| retryButtonBorderColor | UIColor | Border color for the retry button. | -| retryButtonBorderWidth | CGFloat | Border width for the retry button. | -| retryButtonCornerRadius | CometChatCornerStyle? | Corner radius for the retry button. | -| emptyTitleTextFont | UIFont | Font for the empty state title (when no users/items are present). | -| emptyTitleTextColor | UIColor | Text color for the empty state title. | -| emptySubTitleFont | UIFont | Font for the subtitle in the empty state. | -| emptySubTitleTextColor | UIColor | Text color for the subtitle in the empty state. | -| tableViewSeparator | UIColor | Color for the table view separator. | -| listItemTitleTextColor | UIColor | Text color for list item titles. | -| listItemTitleFont | UIFont | Font for list item titles. | -| listItemSubTitleTextColor | UIColor | Text color for list item subtitles. | -| listItemSubTitleFont | UIFont | Font for list item subtitles. | -| listItemBackground | UIColor | Background color for individual list items. | -| listItemBorderWidth | CGFloat | Border width for individual list items. | -| listItemBorderColor | UIColor | Border color for individual list items. | -| listItemCornerRadius | CometChatCornerStyle | Corner radius for list items. | -| listItemSelectionImageTint | UIColor | Tint color for selection indicator in list items. | -| listItemSelectedBackground | UIColor | Background color for selected list items. | -| listItemDeSelectedImageTint | UIColor | Tint color for the deselected state image. | -| headerTitleColor | UIColor | Text color for section header titles in the list. | -| headerTitleFont | UIFont | Font for section header titles. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| ---------------------- | ------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------- | -| set(listItemView:) | (User) -> UIView | Custom list item view to be rendered for each user in the list. | setListItemView | -| set(subtitleView:) | (User) -> UIView | Custom subtitle view to be rendered for each user in the fetched list. | setSubtitleView | -| set(emptyView:) | UIView | Custom empty state view to be displayed when the user list is empty. | setEmptyStateView | -| set(errorView:) | UIView | Custom error state view to be displayed when an error occurs while fetching users. | setErrorStateView | -| set(onItemClick:) | (User) -> Void | Triggered when you click on a ListItem of the users component. | setOnItemClick | -| set(onItemLongClick:) | (User) -> Void | Triggered when you long press on a ListItem of the users component. | setOnItemLongClick | -| set(onBack:) | () -> Void | Triggered when the back button is pressed in the users component. | setOnBack | -| set(onSelection:) | ([User]) -> Void | Triggered on every selection when selection mode is set to multiple or single. | setOnSelection | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs in the users component. | setOnError | - -### Removed Properties - -| Name | Type | Description | -| ------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| set(loadingStateView:) | UIActivityIndicatorView.Style | Used to set size of loading view icon while fetching the list of users. | -| hide(errorText:) | Bool | Used to hide error text on fetching users. | -| show(backButton:) | Bool | Used to toggle visibility for back button. | -| set(searchIcon:) | UIImage? | Used to set search Icon in the search field. | -| hide(search:) | Bool | Used to toggle visibility for search box. | -| hide(separator:) | Bool | Used to hide the divider separating the user items. | -| disable(userPresence:) | Bool | Used to control visibility of user indicator shown if user is online. | -| set(emptyStateText:) | String | Used to set a custom text response when fetching the users has returned an empty list. | -| set(errorStateText:) | String | Used to set a custom text response when some error occurs on fetching the list of users. | -| set(searchPlaceholder:) | String | Used to set search placeholder text. | -| set(title:mode:) | String, UINavigationItem.LargeTitleDisplayMode | Used to set title in the app with display mode. | -| setOnLoad | ([User]) -> Void | Gets triggered when a user list is fully fetched and displayed on the screen. | - -## Groups - -### New Properties - -| Name | Type | Description | -| --------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| set(onSelection:) | Closure | Gets triggered when selection mode is set to multiple or single. Triggers on every selection and returns the list of selected groups. | -| set(onEmpty:) | Closure | Gets triggered when the groups list is empty in CometChatGroups. | -| setOnLoad | Closure | Gets triggered when a group list is fully fetched and going to be displayed on the screen. Returns the list of groups to be displayed. | -| listItemSelectedImage | UIImage | Check box image when a list item is selected. | -| listItemDeSelectedImage | UIImage | Check box image when a list item is deselected. | -| searchIconTintColor | UIColor | Tint color for the search icon, defaults to the secondary icon color from CometChatTheme. | -| searchBarStyle | UISearchBarStyle | Style of the search bar, defaulting to the standard style. | -| searchTintColor | UIColor | Tint color for the search bar, defaults to the primary color from CometChatTheme. | -| searchBarTintColor | UIColor | Background color of the search bar, defaulting to clear. | -| searchBarPlaceholderTextColor | UIColor | Placeholder text color for the search bar, defaults to the tertiary text color from CometChatTheme. | -| searchBarPlaceholderTextFont | UIFont | Font used for the placeholder text in the search bar, defaults to regular body font. | -| searchBarTextColor | UIColor | Color of the text entered in the search bar, defaults to the primary text color from CometChatTheme. | -| searchBarTextFont | UIFont | Font used for the text in the search bar, defaults to regular body font. | -| searchBarBackgroundColor | UIColor | Background color of the search bar, defaults to a specific background color from CometChatTheme. | -| searchBarCancelIconTintColor | UIColor | Tint color for the cancel icon in the search bar, defaults to the primary color from CometChatTheme. | -| searchBarCrossIconTintColor | UIColor | Tint color for the cross icon in the search bar, defaults to the secondary icon color from CometChatTheme. | -| backgroundColor | UIColor | Background color of the overall view, defaults to a specific background color from CometChatTheme. | -| borderWidth | CGFloat | Width of the border around the view, defaults to 0 (no border). | -| borderColor | UIColor | Color of the border around the view, defaults to clear. | -| cornerRadius | CometChatCornerStyle | Corner radius settings for the view, defaults to no corner radius. | -| titleColor | UIColor | Color for the title text, defaults to the primary text color from CometChatTheme. | -| titleFont | UIFont | Font used for the title text, defaults to nil (not set). | -| largeTitleColor | UIColor | Color for the large title text, defaults to the primary text color from CometChatTheme. | -| largeTitleFont | UIFont | Font used for the large title text, defaults to nil (not set). | -| navigationBarTintColor | UIColor | Background color of the navigation bar, defaults to a specific background color from CometChatTheme. | -| navigationBarItemsTintColor | UIColor | Tint color for items in the navigation bar, defaults to the highlight color from CometChatTheme. | -| errorTitleTextFont | UIFont | Font used for the error title text, defaults to a bold heading 3 font from CometChatTypography. | -| errorTitleTextColor | UIColor | Color of the error title text, defaults to the primary text color from CometChatTheme. | -| errorSubTitleFont | UIFont | Font used for the error subtitle text, defaults to regular body font. | -| errorSubTitleTextColor | UIColor | Color of the error subtitle text, defaults to the secondary text color from CometChatTheme. | -| retryButtonTextColor | UIColor | Color for the retry button text, defaults to button text color from CometChatTheme. | -| retryButtonTextFont | UIFont | Font used for the retry button text, defaults to medium button font from CometChatTypography. | -| retryButtonBackgroundColor | UIColor | Background color for the retry button, defaults to the primary color from CometChatTheme. | -| retryButtonBorderColor | UIColor | Border color for the retry button, defaults to clear. | -| retryButtonBorderWidth | CGFloat | Width of the border around the retry button, defaults to 0 (no border). | -| retryButtonCornerRadius | CometChatCornerStyle | Corner radius settings for the retry button, defaults to a specific corner radius from CometChatSpacing. | -| emptyTitleTextFont | UIFont | Font used for the empty state title text, defaults to a bold heading 3 font from CometChatTypography. | -| emptyTitleTextColor | UIColor | Color of the empty state title text, defaults to the primary text color from CometChatTheme. | -| emptySubTitleFont | UIFont | Font used for the empty state subtitle text, defaults to regular body font. | -| emptySubTitleTextColor | UIColor | Color of the empty state subtitle text, defaults to the secondary text color from CometChatTheme. | -| tableViewSeparator | UIColor | Color of the table view separator, defaults to clear. | -| listItemTitleTextColor | UIColor | Color of the title text in list items, defaults to the primary text color from CometChatTheme. | -| listItemTitleFont | UIFont | Font used for the title text in list items, defaults to medium heading 4 font from CometChatTypography. | -| listItemSubTitleTextColor | UIColor | Color of the subtitle text in list items, defaults to the secondary text color from CometChatTheme. | -| listItemSubTitleFont | UIFont | Font used for the subtitle text in list items, defaults to regular body font. | -| listItemBackground | UIColor | Background color for list items, defaults to clear. | -| listItemSelectedBackground | UIColor | Background color for list items if selected, defaults to clear. | -| listItemBorderWidth | CGFloat | Width of the border around list items, defaults to 0 (no border). | -| listItemBorderColor | UIColor | Color of the border around list items, defaults to the light border color from CometChatTheme. | -| listItemCornerRadius | CometChatCornerStyle | Corner radius settings for list items, defaults to no corner radius. | -| listItemSelectionImageTint | UIColor | Tint color for the selection image in list items, defaults to the highlight color from CometChatTheme. | -| listItemDeSelectedImageTint | UIColor | Tint color for the deselected image in list items. | -| passwordGroupImageTintColor | UIColor | Tint color for the password group image, defaults to the background color from CometChatTheme. | -| passwordGroupImageBackgroundColor | UIColor | Background color for the password group image, defaults to the warning color from CometChatTheme. | -| privateGroupImageTintColor | UIColor | Tint color for the private group image, defaults to the background color from CometChatTheme. | -| privateGroupImageBackgroundColor | UIColor | Background color for the private group image, defaults to the success color from CometChatTheme. | -| privateGroupIcon | UIImage | Image for a private group icon. | -| protectedGroupIcon | UIImage | Image for a protected group icon. | -| set(groupsRequestBuilder:) | GroupsRequest.GroupsRequestBuilder | Sets the request builder for fetching groups. | -| set(searchRequestBuilder:) | GroupsRequest.GroupsRequestBuilder | Sets the request builder for searching groups. | -| set(searchKeyword:) | String | Sets the search keyword to filter groups. | -| hideErrorView | Bool | Hides the error state view. | -| hideNavigationBar | Bool | Hides or shows the navigation bar. | -| hideSearch | Bool | Hides the search bar. | -| hideBackButton | Bool | Hides the back button. | -| hideLoadingState | Bool | Hides the loading state indicator. | -| hideReceipts | Bool | Hides message read/delivery receipts. | -| hideDeleteConversationOption | Bool | Hides the option to delete a conversation. | -| hideUserStatus | Bool | Hides the online/offline status of users. | -| hideGroupType | Bool | Hides the group type (private/public). | -| set(options:) | (Group?) -> [CometChatGroupOption] | Allows you to define custom options for each group. Returns an array of CometChatGroupOption based on the group object. | -| add(options:) | (Group?) -> [CometChatGroupOption] | Dynamically adds options to groups. Returns additional CometChatGroupOption elements. | -| set(leadingView:) | (Group?) -> UIView | Allows you to modify the leading view of a group cell. | -| set(titleView:) | (Group?) -> UIView | Allows you to customize the title view of a group cell. | -| set(trailView:) | (Group?) -> UIView | Allows you to modify the trailing view of a group cell. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| --------------------- | --------------------- | ------------------------------------------------------------------- | --------------------- | -| set(onItemClick:) | Closure | Triggered when you click on a ListItem of the groups component. | SetOnItemClick | -| set(OnItemLongClick:) | Closure | Triggered when you long press on a ListItem of the groups component. | SetOnItemLongClick | -| set(onError:) | Closure | Triggered when an error occurs in CometChatGroups. | SetOnError | -| set(onBack:) | Closure | Triggered when the back button is pressed in CometChatGroups. | SetOnBack | -| SetListItemView | (Group?) -> UIView | Assigns a custom ListItem to the Groups Component. | setListItemView | -| SetSubTitleView | (Group?) -> UIView | Allows you to customize the subtitle view for each group item. | setSubtitleView | - -### Removed Properties - -No properties were removed in v5. All v4 properties have been retained (with some renamed) and additional functionality has been added. - -## Group Members - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | ---------------------- | -------------------------------------------------------------------- | -| retryButtonTextColor | UIColor | Sets the text color for the retry button. | -| retryButtonTextFont | UIFont | Sets the text font for the retry button. | -| retryButtonBackgroundColor | UIColor | Sets the background color for the retry button. | -| retryButtonBorderColor | UIColor | Sets the border color for the retry button. | -| retryButtonBorderWidth | CGFloat | Sets the border width for the retry button. | -| retryButtonCornerRadius | CometChatCornerStyle | Sets the corner radius for the retry button. | -| listItemSelectedBackground | UIColor | Sets the background color for selected list items. | -| listItemDeSelectedImageTint | UIColor | Sets the tint color for deselected list item images. | -| listItemSelectionImageTint | UIColor | Sets the tint color for selected list item images. | -| listItemSelectedImage | UIImage | Sets the image for selected list items. | -| listItemDeSelectedImage | UIImage | Sets the image for deselected list items. | -| largeTitleColor | UIColor? | Sets the color for the large title text. | -| navigationBarTintColor | UIColor? | Sets the tint color for the navigation bar. | -| navigationBarItemsTintColor | UIColor? | Sets the tint color for navigation bar items. | -| errorTitleTextFont | UIFont | Sets the font for the error title text. | -| errorTitleTextColor | UIColor | Sets the color for the error title text. | -| errorSubTitleFont | UIFont | Sets the font for the error subtitle text. | -| errorSubTitleTextColor | UIColor | Sets the color for the error subtitle text. | -| emptyTitleTextFont | UIFont | Sets the font for the empty state title text. | -| emptyTitleTextColor | UIColor | Sets the color for the empty state title text. | -| emptySubTitleFont | UIFont | Sets the font for the empty state subtitle text. | -| emptySubTitleTextColor | UIColor | Sets the color for the empty state subtitle text. | -| tableViewSeparator | UIColor | Sets the color for the table view separator. | -| listItemTitleTextColor | UIColor | Sets the text color for list item titles. | -| listItemTitleFont | UIFont | Sets the font for list item titles. | -| listItemSubTitleTextColor | UIColor | Sets the text color for list item subtitles. | -| listItemSubTitleFont | UIFont | Sets the font for list item subtitles. | -| listItemBackground | UIColor | Sets the background color for list items. | -| listItemBorderWidth | CGFloat | Sets the border width for list items. | -| listItemBorderColor | UIColor | Sets the border color for list items. | -| listItemCornerRadius | CometChatCornerStyle | Sets the corner radius for list items. | -| messageTypeImageTint | UIColor | Sets the tint color for message type icons. | -| passwordGroupImageTintColor | UIColor | Sets the tint color for password group icons. | -| passwordGroupImageBackgroundColor | UIColor | Sets the background color for password group icons. | -| privateGroupImageTintColor | UIColor | Sets the tint color for private group icons. | -| privateGroupImageBackgroundColor | UIColor | Sets the background color for private group icons. | -| backgroundColor | UIColor | Sets the background color for the component. | -| set(groupMembersRequestBuilder:) | GroupMembersRequest.GroupMembersRequestBuilder | Sets the request builder for fetching group members. | -| set(searchRequestBuilder:) | GroupMembersRequest.GroupMembersRequestBuilder | Sets the request builder for searching group members. | -| set(searchKeyword:) | String | Sets the search keyword to filter group members. | -| hideError | Bool | Hides the error state view. | -| hideUserStatus | Bool | Hides the online/offline status of users. | -| hideNavigationBar | Bool | Hides or shows the navigation bar. | -| hideLoadingState | Bool | Hides the loading state indicator. | -| hideBackIcon | Bool | Hides the back button/icon. | -| hideKickMemberOption | Bool | Hides the option to kick a member from the group. | -| hideBanMemberOption | Bool | Hides the option to ban a member from the group. | -| hideScopeChangeOption | Bool | Hides the option to change a member's scope (role). | -| hideSearch | Bool | Hides the search bar. | -| set(onSelection:) | ([GroupMember]) -> Void | Triggers on every selection and returns the list of selected group members. | -| set(onEmpty:) | () -> Void | Triggers when the groups list is empty. | -| set(onLoad:) | ([GroupMember]) -> Void | Triggers when group members list is fully fetched and displayed. | -| set(onItemClick:) | (GroupMember, IndexPath) -> Void | Triggered when you click on a ListItem. | -| set(onItemLongClick:) | (GroupMember, IndexPath) -> Void | Triggered when you long press on a ListItem. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(onBack:) | () -> Void | Triggered when back button is pressed. | -| set(leadingView:) | (GroupMember?) -> UIView | Sets a custom leading view for group member cells. | -| set(titleView:) | (GroupMember?) -> UIView | Sets a custom title view for group member cells. | -| set(loadingView:) | UIView | Sets a custom loading view displayed while data is being fetched. | -| set(errorView:) | UIView | Sets a custom error view that appears when an error occurs. | -| set(emptyView:) | UIView | Sets a custom empty state view when no group members are available. | -| setListItemView | (GroupMember?) -> UIView | Assigns a custom ListItem to the GroupMembers component. | -| setSubtitleView | (GroupMember?) -> UIView | Sets a custom subtitle view for each GroupMembers item. | -| setTailView | (GroupMember?) -> UIView | Sets a custom tail view for group member cells. | -| setOptions | [CometChatGroupMemberOption] | Sets custom options for swipe actions. | -| set(menus:) | UIView | Sets custom menus to add more options. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| backgroundColor | UIColor | Sets the background color for the component. | background | -| hideUserStatus | Bool | Hides/disables the online/offline status of users. | disable(userPresence:) | -| hideSearch | Bool | Hides the search bar. | hide(search:) | -| hideUserStatus | Bool | Hide user presence. If set to true, the status indicator is not displayed. | disableUsersPresence | -| set(onItemClick:) | (GroupMember, IndexPath) -> Void | Triggered when you click on a ListItem. | setOnItemClick | -| set(onItemLongClick:) | (GroupMember, IndexPath) -> Void | Triggered when you long press on a ListItem. | setOnItemLongClick | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | setOnError | -| set(onBack:) | () -> Void | Triggered when back button is pressed. | setOnBack | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| backIconTint | UIColor | Sets the back button tint color. | -| searchIconTint | UIColor | Sets the search icon tint color. | -| searchTextFont | UIFont | Sets the search text font. | -| searchTextColor | UIColor | Sets the search text color. | -| searchCancelButtonTint | UIColor | Sets the search cancel icon tint. | -| searchPlaceholderFont | UIFont | Sets the search placeholder font. | -| searchPlaceholderColor | UIColor | Sets the search placeholder color. | -| addButtonTint | UIColor | Sets add button color. | -| addButtonFont | UIFont | Sets add button font. | -| avatarStyle | AvatarStyle | Styles to apply to the avatar component of the default list item view. | -| statusIndicatorStyle | CSSProperties | Styles to apply to the status indicator component of the default list item view. | -| listItemStyle | ListItemStyle | Styles to apply to the default list item view. | -| groupScopeStyle | ChangeScopeStyle | Styles to apply to the change scope component. | -| groupMembersStyle | GroupMembersStyle | Styles to apply to this component. | -| set(title:mode:) | String, UINavigationItem.LargeTitleDisplayMode | Custom title for the component. | -| set(backButtonTitle:) | String? | Custom text for the back button. | -| set(searchPlaceholder:) | String | Custom placeholder text for search field. | -| show(backButton:) | Bool | Whether to show the back button. | -| set(errorStateText:) | String | Custom error state text. | -| set(backButtonIcon:) | UIImage | Custom back button icon. | -| set(passwordPlaceholderText:) | String | Custom placeholder text for password. | -| hide(continueButton:) | Bool | Whether to hide the continue button. | -| set(searchIcon:) | UIImage | Sets the icon for the search bar. | -| set(searchClearIcon:) | UIImage | Sets the clear icon for the search bar. | -| set(searchBarHeight:) | CGFloat | Set the height for the search bar. | -| selectionMode(mode:) | SelectionMode | Enables selection mode (.single, .multiple). | -| hide(separator:) | Bool | Hide/unhide the separator. | -| clearList() | - | Clears the users locally. | -| update(groupMember:) | GroupMember | Updates member object locally. | -| remove(groupMember:) | GroupMember | Removes member object locally. | -| size() | - | Returns the count of members displayed. | -| title | String | Title of the component. | -| searchPlaceholder | String | Text to be displayed when the search input has no value. | -| fetchTimeOut | any | Timeout reference for fetching users. | -| userPresencePlacement | UserPresencePlacement | Placement of user presence information within the user interface. | -| backButtonIconURL | String | Image URL for the back button. | -| showBackButton | Bool | Show back button. | -| closeButtonIconURL | String | Image URL for the close button. | -| dropDownIconURL | String | Image URL for the change scope component's arrowIconURL prop. | -| emptyStateText | String | Text to display in the default empty view. | -| errorStateText | String | Text to display in the default error view. | -| loadingIconURL | String | Image URL for the default loading view. | -| hideSeparator | Bool | Hide the separator at the bottom of the default list item view. | -| titleAlignment | TitleAlignment | Alignment of the title text. | -| searchIconURL | String | Image URL for the search icon to use in the search bar. | -| fetchingUsers | Bool | Flag to indicate whether users are currently being fetched. | -| onClose | () -> Void | Function to call when the close button is clicked. | -| headerView | UIView | Custom header view which will replace the title as well. | - - -## Message Header - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| titleTextColor | UIColor | Used to set the text color of the header title. | -| titleTextFont | UIFont | Used to set the font style of the header title. | -| subtitleTextColor | UIColor | Used to set the text color of the subtitle in the header. | -| subtitleTextFont | UIFont | Used to set the font style of the subtitle in the header. | -| backButtonImageTintColor | UIColor | Used to set the tint color of the back button image in the header. | -| privateGroupBadgeImageTintColor | UIColor | Used to set the tint color of the private group badge in the header. | -| passwordProtectedGroupBadgeImageTintColor | UIColor | Used to set the tint color of the password-protected group badge in the header. | -| privateGroupImageBackgroundColor | UIColor | Used to set the background color of the private group badge. | -| passwordGroupImageBackgroundColor | UIColor | Used to set the background color of the password-protected group badge. | -| groupImageBackgroundColor | UIColor | Used to set the background color for group icons in the header. | -| avatarStyle | AvatarStyle | Used to customize the appearance of the avatar in the header. | -| backgroundColor | UIColor | Used to set the background color of the header. | -| cornerRadius | CometChatCornerStyle | Used to set the corner radius of the header. | -| borderWidth | CGFloat | Used to set the border width of the header. | -| borderColor | UIColor | Used to set the border color of the header. | -| backButtonIcon | UIImage | Used to set a custom icon for the back button. | -| privateGroupIcon | UIImage | Used to set a custom icon for private groups. | -| protectedGroupIcon | UIImage | Used to set a custom icon for password-protected groups. | -| backgroundImage | UIImage | Used to set a background image for the header. | -| hideBackButton | Bool | Hides the back button of message header. | -| hideUserStatus | Bool | Hides or shows the user status of user (online/offline/last active at). | -| hideVideoCallButton | Bool | Hides the video call button. | -| hideVoiceCallButton | Bool | Hides the voice call button. | -| set(onBack:) | () -> Void | Triggered when back button is pressed. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(listItemView:) | (User?, Group?) -> UIView | Assigns a custom ListItem to the message header component. | -| set(leadingView:) | (User?, Group?) -> UIView | Sets a custom leading view for message header. | -| set(titleView:) | (User?, Group?) -> UIView | Sets a custom title view for message header. | -| set(trailView:) | (User?, Group?) -> UIView | Sets a custom trailing view for message header. | -| set(subtitleView:) | (User?, Group?) -> UIView | Sets a custom subtitle view for message header. | -| dateTimeFormatter | CometChatDateTimeFormatter | Supports full customization of how date and time are displayed. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| backgroundColor | UIColor | Sets the background color for the component. | background | -| backButtonImageTintColor | UIColor | Sets the tint color of the back button image in the header. | backIconTint | -| hideBackButton | Bool | Hides the back button of message header. | hide(backButton:) | -| hideUserStatus | Bool | Hides or shows the user status of user. | set(disableUsersPresence:) | -| set(menus:) | (User?, Group?) -> UIView | Sets custom menus to add more options. | setMenus | -| set(subtitleView:) | (User?, Group?) -> UIView | Sets a custom subtitle view for message header. | setSubtitleView | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| typingIndicatorTextFont | UIFont | Sets the typing indicator text font. | -| typingIndicatorTextColor | UIColor | Sets the typing indicator text color. | -| detailIconTint | UIColor | Sets the tint color for detail icon for message header. | -| onlineStatusColor | UIColor | Sets the online status color for message header. | -| privateGroupIconBackgroundColor | UIColor | Sets the private group background color for message header (replaced by privateGroupImageBackgroundColor). | -| protectedGroupIconBackgroundColor | UIColor | Sets the protected group background color for message header (replaced by passwordGroupImageBackgroundColor). | -| set(protectedGroupIcon:) | UIImage | Used to set custom protected group icon. | -| set(privateGroupIcon:) | UIImage | Used to set custom private group icon. | -| disable(typing:) | Bool | Used to enable/disable typing indicators. | - -## Message List - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| hideAvatar | Bool | Hides the avatar of the sender. | -| hideGroupActionMessages | Bool | Hides group action messages (like join/leave notifications). | -| hideReplyInThreadOption | Bool | Hides the reply in thread option. | -| hideTranslateMessageOption | Bool | Hides the message translation option. | -| hideEditMessageOption | Bool | Hides the edit message option. | -| hideDeleteMessageOption | Bool | Hides the delete message option. | -| hideReactionOption | Bool | Hides the reaction option on messages. | -| hideMessagePrivatelyOption | Bool | Hides the option to message privately. | -| hideCopyMessageOption | Bool | Hides the option to copy a message. | -| hideMessageInfoOption | Bool | Hides the message info option. | -| hideHeaderView | Bool | Hides the header view of the message list. | -| hideFooterView | Bool | Hides the footer view of the message list. | -| hideDateSeparator | Bool | Hides the date separator between messages. | -| scrollToBottomOnNewMessages | Bool | Scrolls to the bottom when new messages arrive. | -| hideReceipts | Bool | Hides the message read receipts (ticks). | -| disableSoundForMessages | Bool | Disables the sound when a new message arrives. | -| hideEmptyView | Bool | Hides the empty state view when no messages are available. | -| hideErrorView | Bool | Hides the error view when an error occurs. | -| hideLoadingView | Bool | Hides the loading view when fetching messages. | -| hideNewMessageIndicator | Bool | Hides the "new message" indicator. | -| backgroundColor | UIColor | Background color with dynamic support for light and dark mode. | -| borderWidth | CGFloat | Border width for the component. | -| borderColor | UIColor | Border color for the component. | -| cornerRadius | CometChatCornerStyle | Corner radius for the component. | -| shimmerGradientColor1 | UIColor | First color of the shimmer gradient. | -| shimmerGradientColor2 | UIColor | Second color of the shimmer gradient. | -| emptyStateTitleColor | UIColor | Text color for the title in the empty state. | -| emptyStateTitleFont | UIFont | Font for the title in the empty state. | -| emptyStateSubtitleColor | UIColor | Text color for the subtitle in the empty state. | -| emptyStateSubtitleFont | UIFont | Font for the subtitle in the empty state. | -| errorStateTitleColor | UIColor | Text color for the title in the error state. | -| errorStateTitleFont | UIFont | Font for the title in the error state. | -| errorStateSubtitleColor | UIColor | Text color for the subtitle in the error state. | -| errorStateSubtitleFont | UIFont | Font for the subtitle in the error state. | -| threadedMessageImage | UIImage | Icon image for threaded messages. | -| errorImage | UIImage | Icon image for error state. | -| emptyImage | UIImage | Icon image for empty state. | -| newMessageIndicatorImage | UIImage | Icon image for new message indicator. | -| backgroundImage | UIImage | Background image for the component. | -| scrollToBottom(isAnimated:) | Bool | Scrolls to the bottom of the message list. | -| set(messageAlignment:) | MessageListAlignment | Sets the alignment of messages in the list. | -| set(smartRepliesKeywords:) | [String] | Sets keywords for smart replies. | -| set(smartRepliesDelayDuration:) | Int | Sets the delay duration for smart replies. | -| set(user:parentMessage:) | User, BaseMessage? | Sets the user and an optional parent message. | -| set(group:parentMessage:) | Group, BaseMessage? | Sets the group and an optional parent message. | -| set(messagesRequestBuilder:) | MessagesRequest.MessageRequestBuilder | Sets the message request builder. | -| set(reactionsRequestBuilder:) | ReactionsRequest.ReactionsRequestBuilder | Sets the reactions request builder. | -| set(parentMessageId:) | Int | Sets the parent message ID. | -| set(onThreadRepliesClick:) | (BaseMessage, CometChatMessageTemplate) -> Void | Triggered when you click on the thread indicator of message bubble. | -| set(onReactionClick:) | (CometChat.ReactionCount, BaseMessage) -> Void | Triggered when you click on a reaction on a message bubble. | -| set(onReactionListItemClick:) | (CometChat.Reaction, BaseMessage) -> Void | Triggered when you click on the list item of CometChatReactionList. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(onEmpty:) | () -> Void | Triggers when the message list is empty. | -| set(onLoad:) | ([BaseMessage]) -> Void | Triggers when message list is fully fetched and displayed. | -| set(headerView:) | UIView | Sets a custom header view for message list. | -| set(footerView:) | UIView | Sets a custom footer view for message list. | -| set(dateSeparatorPattern:) | (Int?) -> String | Sets the date separator pattern using a closure. | -| set(datePattern:) | (Int?) -> String | Sets the date pattern using a closure. | -| set(timePattern:) | (Int?) -> String | Sets the time pattern using a closure. | -| set(textFormatter:) | [CometChatTextFormatter] | Sets the list of text formatters. | -| set(loadingView:) | UIView | Sets a custom loading view displayed while data is being fetched. | -| set(errorView:) | UIView | Sets a custom error view that appears when an error occurs. | -| set(emptyView:) | UIView | Sets a custom empty state view when no messages are available. | -| set(templates:) | [CometChatMessageTemplate] | Sets message templates to MessageList. | -| dateTimeFormatter | CometChatDateTimeFormatter | Supports full customization of how date and time are displayed. | -| set(controller:) | UIViewController | Sets the controller (mandatory for proper configuration). | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| hideReceipts | Bool | Hides the message read receipts. | hide(receipt:) | -| hideAvatar | Bool | Shows/hides the avatar of the sender. | show(avatar:) | -| backgroundColor | UIColor | Sets the background color for the component. | background | -| set(messageAlignment:) | MessageListAlignment | Sets the alignment of messages in the list. | alignment | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| loadingIconTint | UIColor | Used to set loading icon tint. | -| emptyTextFont | UIFont | Used to set empty state text font. | -| errorTextFont | UIFont | Used to set error text font. | -| emptyTextColor | UIColor | Used to set empty state text color. | -| errorTextColor | UIColor | Used to set error state text color. | -| nameTextColor | UIColor | Used to set sender/receiver name text color on a message bubble. | -| nameTextFont | UIFont | Used to set sender/receiver name text appearance on a message bubble. | -| timestampTextColor | UIColor | Used to set time stamp text color. | -| threadReplySeperatorColor | UIColor | Used to set thread reply separator color. | -| threadReplyTextColor | UIColor | Used to set thread reply text color. | -| threadReplyTextFont | UIFont | Used to set thread reply text appearance. | -| hide(error:) | Bool | Used to hide the error view. | -| messageInformationConfiguration | MessageInformationConfiguration | Configuration for message information component. | -| reactionsConfiguration | ReactionsConfiguration | Configuration for reactions component. | -| setDateSeparatorPattern | (Int?) -> String | Used to modify the date pattern of the message list date separator. | -| setDatePattern | (Int?) -> String | Used to modify the date pattern. | -| setHeaderView | UIView | Used to set custom header view (now set(headerView:)). | -| setFooterView | UIView | Used to set custom footer view (now set(footerView:)). | -| setTextFormatters | [CometChatTextFormatter] | Used to set text formatters (now set(textFormatter:)). | -| setMentionsFormatters | [CometChatTextFormatter] | Used to set mentions formatters (merged into set(textFormatter:)). | -| setErrorStateView | UIView | Used to set custom error view (now set(errorView:)). | -| setEmptyStateView | UIView | Used to set custom empty state view (now set(emptyView:)). | -| setOnThreadRepliesClick | Closure | Callback for thread replies click (now set(onThreadRepliesClick:)). | - -## Message Composer - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| placeHolderTextFont | UIFont | Font for the placeholder text in the input field. | -| placeHolderTextColor | UIColor | Color for the placeholder text in the input field. | -| textFiledColor | UIColor | Text color for the input field. | -| textFiledFont | UIFont | Font for the input field text. | -| backgroundColor | UIColor | Background color with dynamic support for light and dark mode. | -| cornerRadius | CometChatCornerStyle | Corner radius for the composer. | -| borderWidth | CGFloat | Border width for the composer. | -| borderColor | UIColor | Border color for the composer. | -| sendButtonImage | UIImage | Icon for the send button. | -| sendButtonImageTint | UIColor | Tint color for the send button image. | -| activeSendButtonImageBackgroundColor | UIColor | Background color for the send button when active. | -| inactiveSendButtonImageBackgroundColor | UIColor | Background color for the send button when inactive. | -| composeBoxBackgroundColor | UIColor | Background color for the compose box. | -| composeBoxBorderColor | UIColor | Border color for the compose box. | -| composeBoxBorderWidth | CGFloat | Border width for the compose box. | -| composerBoxCornerRadius | CometChatCornerStyle | Corner radius for the compose box. | -| composerSeparatorColor | UIColor | Color for the separator in the compose box. | -| attachmentImage | UIImage | Icon for the attachment button. | -| attachmentImageTint | UIColor | Tint color for the attachment image. | -| voiceRecordingImage | UIImage | Icon for the voice recording button. | -| voiceRecordingImageTint | UIColor | Tint color for the voice recording image. | -| aiImage | UIImage | Icon for the AI button. | -| aiImageTint | UIColor | Tint color for the AI image. | -| stickerImage | UIImage | Icon for the sticker button. | -| stickerTint | UIColor | Tint color for the sticker image. | -| editPreviewTitleTextFont | UIFont | Font for the title in the edit preview. | -| editPreviewMessageTextFont | UIFont | Font for the message text in the edit preview. | -| editPreviewTitleTextColor | UIColor | Text color for the title in the edit preview. | -| editPreviewMessageTextColor | UIColor | Text color for the message in the edit preview. | -| editPreviewBackgroundColor | UIColor | Background color for the edit preview. | -| editPreviewCornerRadius | CometChatCornerStyle | Corner radius for the edit preview. | -| editPreviewBorderColor | UIColor | Border color for the edit preview. | -| editPreviewBorderWidth | CGFloat | Border width for the edit preview. | -| editPreviewCloseIcon | UIImage | Icon for closing the edit preview. | -| editPreviewCloseIconTint | UIColor | Tint color for the close icon in the edit preview. | -| infoIcon | UIImage | Icon for the info button. | -| infoIconTint | UIColor | Tint color for the info icon. | -| infoTextColor | UIColor | Text color for the info text. | -| infoTextFont | UIFont | Font for the info text. | -| infoSeparatorColor | UIColor | Color for the separator in the info section. | -| infoBackgroundColor | UIColor | Background color for the info section. | -| infoCornerRadius | CometChatCornerStyle | Corner radius for the info section. | -| infoBorderColor | UIColor | Border color for the info section. | -| infoBorderWidth | CGFloat | Border width for the info section. | -| setInitialComposerText | String | Sets the initial text in the composer when it loads. | -| disableTypingEvents | Bool | Disables sending typing indicators when the user types. | -| disableMentions | Bool | Disables the mention feature in the composer. | -| hideImageAttachmentOption | Bool | Hides the option to attach images. | -| hideVideoAttachmentOption | Bool | Hides the option to attach videos. | -| hideAudioAttachmentOption | Bool | Hides the option to attach audio files. | -| hideFileAttachmentOption | Bool | Hides the option to attach files. | -| hidePollsOption | Bool | Hides the option to create polls. | -| hideCollaborativeDocumentOption | Bool | Hides the option for collaborative documents. | -| hideCollaborativeWhiteboardOption | Bool | Hides the option for collaborative whiteboards. | -| hideAttachmentButton | Bool | Hides the attachment button in the composer. | -| hideVoiceRecordingButton | Bool | Hides the voice recording button. | -| hideStickersButton | Bool | Hides the stickers button. | -| hideSendButton | Bool | Hides the send button. | -| set(user:) | User | Sets the user for direct messaging. | -| set(group:) | Group | Sets the group for group messaging. | -| set(parentMessageId:) | Int | Sets the parent message ID for replying in a thread. | -| set(maxLine:) | Int | Sets the maximum number of lines for the composer input. | -| set(customSoundForMessages:) | URL? | Sets a custom sound for sending messages. | -| disableSoundForMessages | Bool | Disables sound while sending messages. | -| set(onSendButtonClick:) | (BaseMessage) -> Void | Override the action triggered upon pressing the send button. | -| set(onTextChanged:) | (String) -> Void | Gets activated when the user starts typing in message composer. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(attachmentOptions:) | (User?, Group?, UIViewController?) -> [CometChatMessageComposerAction] | Sets a list of custom MessageComposerActions. | -| set(sendButtonView:) | (User?, Group?) -> UIView | Sets a custom send button for the MessageComposer Component. | -| set(headerView:) | (User?, Group?) -> UIView | Sets a custom header view for the MessageComposer Component. | -| set(footerView:) | (User?, Group?) -> UIView | Sets a custom footer view for the MessageComposer Component. | -| set(textFormatter:) | [CometChatTextFormatter] | Assigns the list of text formatters. | -| set(controller:) | UIViewController | Sets the controller (mandatory for proper configuration). | -| mediaRecorderStyle | MediaRecorderStyle | Customizes the media recording styling. | -| aiOptionsStyle | AIOptionsStyle | Customizes the AI options styling. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| backgroundColor | UIColor | Sets the background color for the component. | background | -| hideVoiceRecordingButton | Bool | Hides the voice recording button. | hide(voiceRecording:) | -| disableTypingEvents | Bool | Disables sending typing indicators when the user types. | disable(disableTypingEvents:) | -| disableSoundForMessages | Bool | Disables sound while sending messages. | disable(disableSoundForMessages:) | -| set(textFormatter:) | [CometChatTextFormatter] | Assigns the list of text formatters. | setMentionsFormatters | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| inputBackground | UIColor | Sets the input background color of message composer. | -| textFont | UIFont | Sets the input text font of message composer. | -| inputBoxPlaceholderFont | UIFont | Sets the placeholder text font for message composer input field. | -| placeHolderTextColor | UIColor | Sets the placeholder text color for message composer input field (renamed with different casing). | -| attachmentIconTint | UIColor | Sets the attachment icon tint color. | -| sendIconTint | UIColor | Sets send button icon tint color. | -| separatorTint | UIColor | Sets the separator color for message composer. | -| inputBorderWidth | CGFloat | Sets the border width for message composer input view. | -| inputBorderColor | UIColor | Sets the border color for message composer input view. | -| actionSheetTitleColor | UIColor | Sets the title color for action sheet of message composer. | -| actionSheetTitleFont | UIFont | Sets the title font for action sheet of message composer. | -| actionSheetLayoutModelIconTint | UIColor | Sets action sheet layout mode icon tint color for message composer. | -| actionSheetCancelButtonIconTint | UIColor | Sets action sheet cancel button icon tint color for message composer. | -| actionSheetCancelButtonIconFont | UIFont | Sets the action sheet cancel button icon font color for message composer. | -| actionSheetSeparatorTint | UIColor | Sets the separator color for action sheet items. | -| actionSheetBackground | UIColor | Sets the background color of action sheet. | -| voiceRecordingIconTint | UIColor | Sets the voice recorder icon tint color. | -| aiIconTint | UIColor | Sets the ai icon tint color. | -| infoTextColor | UIColor | Sets the text color for info message displayed (now part of style). | -| infoIconTintColor | UIColor | Sets the tint color for info icon. | -| infoBackgroundColor | UIColor | Sets the background color for info message view (now part of style). | -| infoSeparatorColor | UIColor | Sets the separator color for info view (now part of style). | -| set(background:) | UIColor | Sets background color for message composer. | -| set(placeholderText:) | String | Sets message composer's placeholder text. | -| set(maxLines:) | Int | Sets limit for lines of text to be displayed in input field. | -| set(auxiliaryButtonAlignment:) | AuxiliaryButtonAlignment | Sets position for auxiliary buttons view. | -| set(customSoundForMessage:) | URL | Sets custom sounds for outgoing messages. | -| set(liveReactionIconURL:) | UIImage | Sets custom live reaction icon. | -| set(disableMentions:) | Bool | Enables/Disables user mentions in message composer input field. | -| set(infoIcon:) | UIImage | Sets image for info icon (now part of style). | -| set(attachmentIcon:) | UIImage | Sets image for attachment button on message composer. | -| set(aiAuxiliaryIcon:) | UIImage | Sets image for ai auxillary button. | -| setOnSendButtonClick | Closure | Sets custom actions for send button click. | -| hide(liveReaction:) | Bool | Toggles visibility for live reaction component. | -| hide(footerView:) | Bool | Toggles visibility for footer view of message composer. | -| hide(headerView:) | Bool | Toggles visibility for header view of message composer. | -| hide(sendButton:) | Bool | Toggles visibility for send button. | -| setAttachmentOptions | Closure | Sets a list of custom MessageComposerActions. | -| setAuxilaryButtonView | Closure | Sets custom auxiliary button view. | -| setSecondaryButtonView | Closure | Sets custom secondary button view. | -| setSendButtonView | Closure | Sets custom send button view. | - -## Call Logs - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| listItemTitleTextColor | UIColor | Text color for the list item title. | -| listItemTitleFont | UIFont | Font for the list item title. | -| listItemSubTitleTextColor | UIColor | Text color for the list item subtitle. | -| listItemSubTitleFont | UIFont | Font for the list item subtitle. | -| listItemBackground | UIColor | Background color for the list item. | -| listItemSelectedBackground | UIColor | Background color for the selected list item. | -| listItemBorderWidth | CGFloat | Border width for the list item. | -| listItemBorderColor | UIColor | Border color for the list item. | -| listItemCornerRadius | CometChatCornerStyle | Corner radius for the list item. | -| listItemSelectionImageTint | UIColor | Tint color for the selection image. | -| listItemDeSelectedImageTint | UIColor | Tint color for the deselected image. | -| listItemSelectedImage | UIImage | Image for the selected list item. | -| listItemDeSelectedImage | UIImage | Image for the deselected list item. | -| backgroundColor | UIColor | Background color. | -| borderWidth | CGFloat | Border width. | -| borderColor | UIColor | Border color. | -| cornerRadius | CometChatCornerStyle | Corner radius. | -| titleColor | UIColor | Text color for the title. | -| titleFont | UIFont | Font for the title. | -| largeTitleColor | UIColor | Text color for large titles. | -| largeTitleFont | UIFont | Font for large titles. | -| navigationBarTintColor | UIColor | Background color for the navigation bar. | -| navigationBarItemsTintColor | UIColor | Tint color for navigation bar items. | -| errorTitleTextFont | UIFont | Font for the error title. | -| errorTitleTextColor | UIColor | Text color for the error title. | -| errorSubTitleFont | UIFont | Font for the error subtitle. | -| errorSubTitleTextColor | UIColor | Text color for the error subtitle. | -| retryButtonTextColor | UIColor | Text color for the retry button. | -| retryButtonTextFont | UIFont | Font for the retry button text. | -| retryButtonBackgroundColor | UIColor | Background color for the retry button. | -| retryButtonBorderColor | UIColor | Border color for the retry button. | -| retryButtonBorderWidth | CGFloat | Border width for the retry button. | -| retryButtonCornerRadius | CometChatCornerStyle | Corner radius for the retry button. | -| emptyTitleTextFont | UIFont | Font for the empty state title. | -| emptyTitleTextColor | UIColor | Text color for the empty state title. | -| emptySubTitleFont | UIFont | Font for the empty state subtitle. | -| emptySubTitleTextColor | UIColor | Text color for the empty state subtitle. | -| tableViewSeparator | UIColor | Color for the table view separator. | -| backIcon | UIImage | Icon for the back button. | -| backIconTint | UIColor | Tint color for the back icon. | -| incomingCallIcon | UIImage | Icon for incoming calls. | -| incomingCallIconTint | UIColor | Tint color for the incoming call icon. | -| outgoingCallIcon | UIImage | Icon for outgoing calls. | -| outgoingCallIconTint | UIColor | Tint color for the outgoing call icon. | -| missedCallTitleColor | UIColor | Text color for missed call titles. | -| missedCallIcon | UIImage | Icon for missed calls. | -| missedCallIconTint | UIColor | Tint color for the missed call icon. | -| audioCallIcon | UIImage | Icon for audio calls. | -| audioCallIconTint | UIColor | Tint color for the audio call icon. | -| videoCallIcon | UIImage | Icon for video calls. | -| videoCallIconTint | UIColor | Tint color for the video call icon. | -| separatorColor | UIColor | Color for separators. | -| set(callRequestBuilder:) | CallLogsRequest.CallLogsBuilder | Sets the CallLogsBuilder instance for call logs. | -| hideError | Bool | Hides the error state view. | -| hideNavigationBar | Bool | Hides the navigation bar. | -| hideLoadingState | Bool | Hides the loading state view. | -| hideBackIcon | Bool | Hides the back icon in the navigation bar. | -| set(onItemClick:) | (CallLog, IndexPath) -> Void | Triggered when you click on a ListItem. | -| set(onItemLongClick:) | (CallLog, IndexPath) -> Void | Triggered when you long press on a ListItem. | -| set(onBack:) | () -> Void | Triggered when back button is pressed. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(onEmpty:) | () -> Void | Triggers when the call logs list is empty. | -| set(onLoad:) | ([CallLog]) -> Void | Triggers when call logs are successfully loaded. | -| set(listItemView:) | (CallLog) -> UIView | Assigns a custom ListItem to the CallLogs component. | -| set(titleView:) | (CallLog) -> UIView | Sets a custom title view for call log cells. | -| set(leadingView:) | (CallLog) -> UIView | Sets a custom leading view for call log cells. | -| set(subtitleView:) | (CallLog) -> UIView | Sets a custom subtitle view for call log cells. | -| set(trailView:) | (CallLog) -> UIView | Sets a custom trailing view for call log cells. | -| set(emptyView:) | UIView | Sets a custom empty state view. | -| set(errorView:) | UIView | Sets a custom error view. | -| set(menus:) | [UIBarButtonItem] | Sets custom menus to add more options. | -| avatarStyle | AvatarStyle | Customizes the appearance of avatars. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| set(onItemClick:) | (CallLog, IndexPath) -> Void | Triggered when you click on a ListItem. | setOnItemClick | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | set(onError:) | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| backButtonFont | UIFont | Sets the font for the back button. | -| backButtonIcon | UIImage | Sets the icon for the back button. | -| backButtonTint | UIColor | Sets the tint for the back button. | -| backButtonTitle | String? | Sets the title for the back button. | -| backButtonTitleColor | UIColor | Sets the title color for the back button. | -| background | [CGColor]? | Sets the background. | -| corner | CometChatCornerStyle | Sets the corner style. | -| emptyStateText | String | Sets the text for empty state. | -| emptyStateTextFont | UIFont | Sets the font for empty state text. | -| errorStateText | String | Sets the text for error state. | -| errorStateTextColor | UIColor | Sets the text color for error state. | -| errorStateTextFont | UIFont | Sets the font for error state text. | -| searchBackground | UIColor | Sets the background for the search bar. | -| searchBarHeight | CGFloat | Sets the height for the search bar. | -| searchBorderColor | UIColor | Sets the border color for the search bar. | -| searchCancelButtonFont | UIFont | Sets the font for the search cancel button. | -| searchCancelButtonTint | UIColor | Sets the tint for the search cancel button. | -| searchClearIcon | UIImage | Sets the icon for the search clear button. | -| searchCornerRadius | CometChatCornerStyle | Sets the corner radius for the search bar. | -| searchIcon | UIImage? | Sets the icon for the search bar. | -| searchPlaceholder | String | Sets the placeholder for the search bar. | -| searchTextColor | UIColor | Sets the color for the search text. | -| searchTextFont | UIFont | Sets the font for the search text. | -| set(title:mode:) | String, UINavigationItem.LargeTitleDisplayMode | Sets the title for the title bar. | -| titleColor | UIColor | Sets the color for the title (now part of style). | -| titleFont | UIFont | Sets the font for the title (now part of style). | -| hide(errorText:) | Bool | Hides the error text. | -| hide(search:) | Bool | Hides the search bar. | -| hide(separator:) | Bool | Hides the separator. | -| callStatusTextFont | UIFont | Sets the call status font. | -| missedCallTitleTint | UIColor | Sets the missed call color. | -| callTimeTextFont | UIFont | Sets the call time font. | -| dateSeparatorTextFont | UIFont | Sets the date separator font. | -| emptyStateTextFont | UIFont | Sets the empty state font (now emptyTitleTextFont). | -| errorStateTextFont | UIFont | Sets the error state font (now errorTitleTextFont). | -| callStatusTextColor | UIColor | Sets the call status color. | -| callStatusIconTint | UIColor | Sets the call status icon tint. | -| callTimeTextColor | UIColor | Sets the call time color. | -| dateSeparatorTextColor | UIColor | Sets the date separator color. | -| infoIconTint | UIColor | Sets the info icon tint. | -| listItemStyle | ListItemStyle | Styles to apply to each call log item. | - -## Call Buttons - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| videoCallIconTint | UIColor | Tint color for the video call icon. | -| videoCallTextFont | UIFont | Font for the video call button text. | -| videoCallTextColor | UIColor | Color for the video call button text. | -| videoCallButtonBackground | UIColor | Background color for the video call button. | -| videoCallButtonCornerRadius | CometChatCornerStyle | Corner radius for the video call button. | -| videoCallButtonBorder | CGFloat | Border width for the video call button. | -| videoCallButtonBorderColor | UIColor | Border color for the video call button. | -| videoCallIcon | UIImage | Icon for the video call button. | -| audioCallIconTint | UIColor | Tint color for the audio call icon. | -| audioCallTextFont | UIFont | Font for the audio call button text. | -| audioCallTextColor | UIColor | Color for the audio call button text. | -| audioCallButtonBackground | UIColor | Background color for the audio call button. | -| audioCallButtonCornerRadius | CometChatCornerStyle | Corner radius for the audio call button. | -| audioCallButtonBorder | CGFloat | Border width for the audio call button. | -| audioCallButtonBorderColor | UIColor | Border color for the audio call button. | -| audioCallIcon | UIImage | Icon for the audio call button. | -| hideVideoCallButton | Bool | Hides the video call button. | -| hideVoiceCallButton | Bool | Hides the voice call button. | -| set(user:) | User | Sets the User object for CometChatCallButtons. | -| set(group:) | Group | Sets the Group object for CometChatCallButtons. | -| set(outgoingCallConfiguration:) | OutgoingCallConfiguration | Sets the configuration for outgoing calls. | -| set(customSoundForCalls:) | URL | Sets a custom sound for incoming and outgoing calls. | -| set(callSettingBuilder:) | (CallType, [CallUser]) -> CallSettings | Function to build call settings based on call type and participants. | -| set(onVoiceCallClick:) | (User?, Group?) -> Void | Override the action triggered upon pressing the voice call button. | -| set(onVideoCallClick:) | (User?, Group?) -> Void | Override the action triggered upon pressing the video call button. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(controller:) | UIViewController | Sets the controller (mandatory for proper configuration). | -| style | CallButtonStyle | Customizes the appearance of the CallButtons component. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| hideVideoCallButton | Bool | Hides the video call button. | hide(videoCall:) | -| hideVoiceCallButton | Bool | Hides the voice call button. | hide(voiceCall:) | -| set(onVoiceCallClick:) | (User?, Group?) -> Void | Override the action triggered upon pressing the voice call button. | setOnVoiceCallClick | -| set(onVideoCallClick:) | (User?, Group?) -> Void | Override the action triggered upon pressing the video call button. | setOnVideoCallClick | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | setOnError | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| set(background:) | UIColor | Sets the background color. | -| set(textFont:) | UIFont | Sets the font of the text. | -| set(textColor:) | UIColor | Sets the color of the text. | -| set(cornerRadius:) | CometChatCornerStyle | Sets the corner radius. | -| set(borderColor:) | UIColor | Sets the color of the border. | -| set(borderWidth:) | CGFloat | Sets the width of the border. | -| set(iconBackground:) | UIColor | Sets the background of the icon. | -| set(iconBorder:) | CGFloat | Sets the border of the icon. | -| set(iconCornerRadius:) | CGFloat | Sets the corner radius of the icon. | -| set(iconTint:) | UIColor | Sets the tint of the icon. | -| set(callButtonsStyle:) | ButtonStyle | Sets the button style for call buttons. | -| set(isCenterAligned:) | Bool | Sets the alignment of the buttons. | -| set(videoCallIcon:) | UIImage | Sets the icon for the video call button (now part of style). | -| set(videoCallIconText:) | String | Sets the text for the video call button. | -| set(voiceCallIcon:) | UIImage | Sets the icon for the voice call button (now part of style). | -| set(voiceCallIconText:) | String | Sets the text for the voice call button. | - -## Incoming Call - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| overlayBackgroundColor | UIColor | Background color for the overlay. | -| acceptButtonBackgroundColor | UIColor | Background color for the accept button. | -| rejectButtonBackgroundColor | UIColor | Background color for the reject button. | -| acceptButtonTintColor | UIColor | Tint color for the accept button. | -| rejectButtonTintColor | UIColor | Tint color for the reject button. | -| acceptButtonImage | UIImage | Icon image for the accept button. | -| rejectButtonImage | UIImage | Icon image for the reject button. | -| acceptButtonCornerRadius | CometChatCornerStyle | Sets corner radius for accept button. | -| rejectButtonCornerRadius | CometChatCornerStyle | Sets corner radius for reject button. | -| acceptButtonBorderWidth | CGFloat | Sets border width for accept button. | -| rejectButtonBorderWidth | CGFloat | Sets border width for reject button. | -| acceptButtonBorderColor | UIColor | Sets border color for accept button. | -| rejectButtonBorderColor | UIColor | Sets border color for reject button. | -| backgroundColor | UIColor | Background color for the call view. | -| cornerRadius | CometChatCornerStyle | Corner radius for the view. | -| borderColor | UIColor | Border color for the view. | -| borderWidth | CGFloat | Border width for the view. | -| callLabelColor | UIColor | Text color for the call label. | -| callLabelFont | UIFont | Font for the call label. | -| nameLabelColor | UIColor | Text color for the name label. | -| nameLabelFont | UIFont | Font for the name label. | -| disableSoundForCalls | Bool | Disables sound for incoming calls. | -| set(customSoundForCalls:) | URL | Sets a custom sound for incoming calls. | -| set(call:) | Call | Sets the call object for the incoming call. | -| set(onAcceptClick:) | (Call, UIViewController?) -> Void | Override the action triggered upon pressing the accept button. | -| set(onCancelClick:) | (Call, UIViewController?) -> Void | Override the action triggered upon pressing the reject button. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(listItemView:) | (Call) -> UIView | Assigns a custom view to the incoming call item view. | -| set(leadingView:) | (Call) -> UIView | Sets a custom leading view for incoming call. | -| set(titleView:) | (Call) -> UIView | Sets a custom title view for incoming call. | -| style | IncomingCallStyle | Customizes the appearance of the IncomingCall component. | -| avatarStyle | AvatarStyle | Customizes the appearance of avatars. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| set(onAcceptClick:) | (Call, UIViewController?) -> Void | Override the action triggered upon pressing the accept button. | setOnAcceptClick | -| set(onCancelClick:) | (Call, UIViewController?) -> Void | Override the action triggered upon pressing the reject button. | setOnCancelClick | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | setOnError | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| set(background:) | UIColor | Sets the background color for IncomingCall. | -| set(cornerRadius:) | CometChatCornerStyle | Sets the corner radius for IncomingCall. | -| set(borderWidth:) | CGFloat | Sets the border width for IncomingCall. | -| set(borderColor:) | UIColor | Sets the border color for IncomingCall. | -| set(titleColor:) | UIColor | Sets the title color for IncomingCall. | -| set(titleFont:) | UIFont | Sets the title font for IncomingCall. | -| set(subtitleColor:) | UIColor | Sets the subtitle color for IncomingCall. | -| set(subtitleFont:) | UIFont | Sets the subtitle font for IncomingCall. | -| set(incomingCallStyle:) | IncomingCallStyle | Sets the incoming call style. | -| set(avatarStyle:) | AvatarStyle | Sets the avatar style. | -| set(user:) | User | Sets the user object for the incoming call. | -| set(acceptButtonIcon:) | UIImage | Sets the icon for the accept button (now part of style). | -| set(declineButtonIcon:) | UIImage | Sets the icon for the decline button (now part of style). | - -## Outgoing Call - -### New Properties - -| Name | Type | Description | -| ---------------------------------------- | --------- | -------------------------------------------------------------------- | -| backgroundColor | UIColor | Sets the background color for the outgoing call view. | -| borderColor | UIColor | Sets the border color for the outgoing call view. | -| borderWidth | CGFloat | Sets the border width for the outgoing call view. | -| cornerRadius | CometChatCornerStyle | Sets the corner radius for the outgoing call view. | -| nameTextColor | UIColor | Sets the text color for the name label in the outgoing call view. | -| nameTextFont | UIFont | Sets the font for the name label in the outgoing call view. | -| callTextColor | UIColor | Sets the text color for the call label in the outgoing call view. | -| callTextFont | UIFont | Sets the font for the call label in the outgoing call view. | -| declineButtonBackgroundColor | UIColor | Sets the background color for the decline button in the outgoing call view. | -| declineButtonIconTint | UIColor | Sets the tint color for the decline button icon. | -| declineButtonIcon | UIImage | Sets the icon for the decline button. | -| declineButtonCornerRadius | CometChatCornerStyle | Sets the corner radius for decline button. | -| declineButtonBorderColor | UIColor | Sets the border color for decline button. | -| declineButtonBorderWidth | CGFloat | Sets the border width for decline button. | -| nameLabel | UIFont | Sets the font for the name label. | -| callingLabel | UIFont | Sets the font for the call label. | -| disableSoundForCalls | Bool | Disables sound for outgoing calls. | -| set(customSoundForCalls:) | URL | Sets a custom sound for outgoing calls. | -| set(call:) | Call | Sets the Call object for CometChatOutgoingCall. | -| set(onCancelClick:) | (Call, UIViewController?) -> Void | Override the action triggered upon pressing the cancel button. | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | -| set(avatarView:) | (Call) -> UIView | Sets a custom avatar view for outgoing call. | -| set(cancelView:) | (Call) -> UIView | Sets a custom cancel button view for outgoing call. | -| set(titleView:) | (Call) -> UIView | Sets a custom title view for outgoing call. | -| set(subtitleView:) | (Call) -> UIView | Sets a custom subtitle view for outgoing call. | -| style | OutgoingCallStyle | Customizes the appearance of the OutgoingCall component. | -| avatarStyle | AvatarStyle | Customizes the appearance of avatars. | - -### Renamed Properties - -| Name | Type | Description | Old Name | -| -------------------- | -------------- | ----------------------------------------------- | ----------- | -| set(onCancelClick:) | (Call, UIViewController?) -> Void | Override the action triggered upon pressing the cancel button. | setOnCancelClick | -| set(onError:) | (CometChatException) -> Void | Triggered when an error occurs. | setOnError | - -### Removed Properties - -| Name | Type | Description | -| ----------------------------- | ----------------------------------- | -------------------------------------------------- | -| set(background:) | UIColor | Sets the background color. | -| set(cornerRadius:) | CometChatCornerStyle | Sets the corner radius. | -| set(borderWidth:) | CGFloat | Sets the border width. | -| set(borderColor:) | UIColor | Sets the border color. | -| set(titleColor:) | UIColor | Sets the title color. | -| set(titleFont:) | UIFont | Sets the title font. | -| set(subtitleColor:) | UIColor | Sets the subtitle color. | -| set(subtitleFont:) | UIFont | Sets the subtitle font. | -| set(outgoingCallStyle:) | OutgoingCallStyle | Sets the outgoing call style. | -| set(avatarStyle:) | AvatarStyle | Sets the avatar style. | -| set(buttonStyle:) | ButtonStyle | Sets the button style for outgoing call. | -| disable(soundForCalls:) | Bool | Disables the default sound for calls. | -| set(declineButtonIcon:) | UIImage | Sets the icon for the decline button (now part of style). | -| set(user:) | User | Sets the User object for CometChatOutgoingCall. | ---- - - - diff --git a/ui-kit/ios/search.mdx b/ui-kit/ios/search.mdx index 4b6c58285..ad10e566b 100644 --- a/ui-kit/ios/search.mdx +++ b/ui-kit/ios/search.mdx @@ -1,176 +1,305 @@ --- title: "Search" +sidebarTitle: "Search" +description: "Search across conversations and messages with customizable filters in CometChat UI Kit for iOS" --- -## Overview - -The `CometChatSearch` component is a powerful and customizable search interface that allows users to search across conversations and messages in real time. It supports a wide variety of filters, scopes, and customization options. `CometChatSearch` helps users find messages, conversations, media, and more through an intuitive and filterable search experience. It can be embedded in multiple contexts — as part of the conversation list, message header, or as a full-screen search experience. +The `CometChatSearch` component is a powerful and customizable search interface that allows users to search across conversations and messages in real time. It supports a wide variety of filters, scopes, and customization options. - + CometChatSearch showing the search interface with search bar, filter options, and search results displaying conversations and messages -*** + +```json +{ + "component": "CometChatSearch", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Provides search functionality across conversations and messages", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onMessageClicked", + "type": "(BaseMessage) -> Void" + }, + "props": { + "data": { + "user": { "type": "User?", "default": "nil", "note": "Limits search to specific user" }, + "group": { "type": "Group?", "default": "nil", "note": "Limits search to specific group" }, + "conversationsRequestBuilder": { "type": "ConversationsRequest.ConversationsRequestBuilder", "default": "SDK default" }, + "messagesRequestBuilder": { "type": "MessagesRequest.MessageRequestBuilder", "default": "SDK default" } + }, + "callbacks": { + "onConversationClicked": "(Conversation, IndexPath) -> Void", + "onMessageClicked": "(BaseMessage) -> Void", + "onBack": "() -> Void", + "onError": "(CometChatException) -> Void", + "onEmpty": "() -> Void" + }, + "visibility": { + "hideNavigationBar": { "type": "Bool", "default": false }, + "hideBackButton": { "type": "Bool", "default": false }, + "hideUserStatus": { "type": "Bool", "default": false }, + "hideGroupType": { "type": "Bool", "default": false }, + "hideReceipts": { "type": "Bool", "default": false } + }, + "search": { + "searchFilters": { "type": "[SearchFilter]", "default": "All available filters" }, + "initialSearchFilter": { "type": "SearchFilter?", "default": "nil" }, + "searchIn": { "type": "[SearchScope]", "default": "[.conversations, .messages]" } + }, + "viewSlots": { + "listItemViewForConversation": "(Conversation) -> UIView", + "leadingViewForConversation": "(Conversation) -> UIView", + "titleViewForConversation": "(Conversation) -> UIView", + "subtitleViewForConversation": "(Conversation) -> UIView", + "tailViewForConversation": "(Conversation) -> UIView", + "listItemViewForMessage": "(BaseMessage) -> UIView", + "leadingViewForMessage": "(BaseMessage) -> UIView", + "titleViewForMessage": "(BaseMessage) -> UIView", + "subtitleViewForMessage": "(BaseMessage) -> UIView", + "trailingViewForMessage": "(BaseMessage) -> UIView", + "initialView": "UIView", + "loadingView": "UIView", + "emptyView": "UIView", + "errorView": "UIView" + } + }, + "events": [], + "sdkListeners": [], + "compositionExample": { + "description": "Search is typically accessed from conversation list or message header", + "components": ["CometChatConversations", "CometChatSearch", "CometChatMessages"], + "flow": "User taps search → enters query → taps result → navigates to conversation/message" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatSearch` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | + +--- ## Usage ### Integration -`CometChatSearch`, as a composite Component, offers flexible integration options, allowing it to be launched directly via button clicks or any user-triggered action. - -The following code snippet exemplifies how you can seamlessly integrate the CometChatSearch component into your application. +`CometChatSearch` is a composite component that offers flexible integration options. It can be launched directly via button clicks or any user-triggered action. -```swift +```swift lines +import CometChatUIKitSwift + let search = CometChatSearch() self.navigationController?.pushViewController(search, animated: true) ``` - - -*** +--- ### Actions +[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type to tailor the behavior to fit your specific needs. + #### 1. onConversationClicked -`onConversationClicked` is triggered when you click on a Conversation from the search result. The `onConversationClicked` action doesn't have a predefined behavior. You can override this action using the following code snippet. +Triggered when you click on a Conversation from the search result. This action doesn't have a predefined behavior—you can override it using the following code snippet: -```swift -search.onConversationClicked = { conversation in +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() +search.onConversationClicked = { conversation, indexPath in print("Conversation clicked:", conversation.conversationId) } ``` - -*** +--- #### 2. onMessageClicked -`onMessageClicked` is triggered when you click on a Message from the search result. The `onMessageClicked` action doesn't have a predefined behavior. You can override this action using the following code snippet. +Triggered when you click on a Message from the search result. This action doesn't have a predefined behavior—you can override it using the following code snippet: -```swift +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() search.onMessageClicked = { message in print("Message clicked:", message.id) } ``` - - -*** +--- #### 3. onBack -'onBack' is triggered when you click on the back button of the search component. +Triggered when you click on the back button of the search component. -```swift +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() search.onBack = { self.navigationController?.popViewController(animated: true) } ``` - - -*** +--- #### 4. onError -This action doesn't change the behavior of the component but rather listens for any errors that occur in the Search component. +Listens for any errors that occur in the Search component. This action doesn't change the component's behavior. -```swift +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() search.set(onError: { error in print("Search error:", error.localizedDescription) }) ``` - - -*** +--- #### 5. onEmpty -This action doesn't change the behavior of the component but rather listens for the empty state of the Search component. +Listens for the empty state of the Search component. This action doesn't change the component's behavior. -```swift +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() search.set(onEmpty: { print("No results found") }) ``` - - +--- + ### Filters +Filters allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria using RequestBuilders of the Chat SDK. + +#### SearchScope + +The `SearchScope` enum defines what types of content to search: + +| Value | Description | +|-------|-------------| +| `.conversations` | Search in conversations | +| `.messages` | Search in messages | + +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() + +// Search only in messages +search.set(searchIn: [.messages]) + +// Search in both conversations and messages (default) +search.set(searchIn: [.conversations, .messages]) +``` + +#### SearchFilter + +The `SearchFilter` enum defines available filter options: + +| Value | Description | +|-------|-------------| +| `.unread` | Filter by unread items | +| `.groups` | Filter by group conversations | +| `.photos` | Filter by photo messages | +| `.videos` | Filter by video messages | +| `.links` | Filter by link messages | +| `.documents` | Filter by document messages | +| `.audio` | Filter by audio messages | + +```swift lines +import CometChatUIKitSwift + +let search = CometChatSearch() + +// Set available filters with an initial selection +search.set(searchFilters: [.unread, .groups, .photos, .videos], initialFilter: .photos) +``` + #### 1. ConversationsRequestBuilder -You can set the `ConversationsRequestBuilder` in the Search Component to filter the search result. You can modify the builder as per your specific requirements with multiple options available to know more refer to [ConversationRequestBuilder](/sdk/ios/retrieve-conversations). +Set the `ConversationsRequestBuilder` in the Search Component to filter the search results. For more options, refer to [ConversationRequestBuilder](/sdk/ios/retrieve-conversations). -```swift +```swift lines +import CometChatUIKitSwift +import CometChatSDK + let convBuilder = ConversationsRequest.ConversationsRequestBuilder() - .set(limit:20) + .set(limit: 20) +let search = CometChatSearch() search.set(conversationsRequestBuilder: convBuilder) - ``` - - -*** +--- #### 2. MessagesRequestBuilder -You can set the `MessagesRequestBuilder` in the Search Component to filter the search result. You can modify the builder as per your specific requirements with multiple options available to know more refer to [MessagesRequestBuilder](/sdk/ios/additional-message-filtering). +Set the `MessagesRequestBuilder` in the Search Component to filter the search results. For more options, refer to [MessagesRequestBuilder](/sdk/ios/additional-message-filtering). -```swift +```swift lines +import CometChatUIKitSwift +import CometChatSDK + let msgBuilder = MessagesRequest.MessageRequestBuilder() .set(limit: 30) .hide(deletedMessages: true) +let search = CometChatSearch() search.set(messagesRequestBuilder: msgBuilder) - ``` - -*** +--- ### Events -[Events](/ui-kit/ios/components-overview) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in multiple locations and are capable of being added or removed. +[Events](/ui-kit/ios/components-overview#events) are emitted by a Component. By using events, you can extend existing functionality. Being global events, they can be applied in multiple locations and can be added or removed as needed. The `CometChatSearch` component does not produce any events. -*** +--- ## Customization @@ -178,30 +307,30 @@ To fit your app's design requirements, you can customize the appearance of the ` ### Style -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +Using Style, you can customize the look and feel of the component in your app. These parameters typically control elements such as the color, size, shape, and fonts used within the component. - + CometChatSearch with custom styling showing modified background color, list item styling, and custom fonts applied -```swift +```swift lines +import CometChatUIKitSwift -// component level styling +// Instance-level styling let style = SearchStyle() style.backgroundColor = UIColor(hex: "#EDEAFA") style.listItemBackground = UIColor(hex: "#EDEAFA") style.listItemTitleFont = UIFont(name: "TimesNewRomanPS-Regular", size: 16) style.titleFont = UIFont(name: "TimesNewRomanPS-Bold", size: 12) style.searchBarPlaceholderTextFont = UIFont(name: "TimesNewRomanPS-Regular", size: 12) - + let searchVC = CometChatSearch() searchVC.style = style self?.navigationController?.pushViewController(searchVC, animated: true) - - -// global level styling + +// Global-level styling CometChatSearch.style.backgroundColor = UIColor(hex: "#EDEAFA") CometChatSearch.style.listItemBackground = UIColor(hex: "#EDEAFA") CometChatSearch.style.listItemTitleFont = UIFont(name: "TimesNewRomanPS-Regular", size: 16) @@ -211,54 +340,64 @@ CometChatSearch.style.searchBarPlaceholderTextFont = UIFont(name: "TimesNewRoman -*** +--- ### Functionality -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can toggle the visibility of UI elements. +These are small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can toggle the visibility of UI elements. + +| Property | Description | Example | +|---------------------------|-------------------------------------------------------|----------------------------------------------------------------------| +| user | Restrict search to a specific user chat | `search.user = user` | +| group | Restrict search to a group | `search.group = group` | +| hideUserStatus | Hide online/offline indicator | `search.hideUserStatus = true` | +| hideGroupType | Hide group type icon | `search.hideGroupType = true` | +| hideBackButton | Hide the back button | `search.hideBackButton = true` | +| hideReceipts | Hide message read/delivery receipt indicators | `search.hideReceipts = true` | +| searchFilters | Filters like "Unread", "Groups", "Photos", etc. | `search.set(searchFilters: [.unread, .groups, .photos])` | +| initialSearchFilter | Default filter to apply on load | `search.set(searchFilters: [...], initialFilter: .photos)` | +| searchIn (searchScopes) | Restrict search: messages / conversations / both | `search.set(searchIn: [.messages, .conversations])` | +| loadingView | Custom loader view | `search.set(loadingView: spinner)` | +| emptyView | Custom empty result view | `search.set(emptyView: emptyView)` | +| errorView | Custom error UI | `search.set(errorView: errorView)` | +| initialView | Custom view before search query is entered | `search.set(initialView: initialView)` | +| disableTyping | Disable typing indicators | `search.disableTyping = true` | +| disableSoundForMessages | Disable message sounds | `search.disableSoundForMessages = true` | +| customSoundForMessages | Custom sound URL for messages | `search.customSoundForMessages = URL(string: "...")` | -Below is a list of customizations along with corresponding code snippets - -| Property | Description | Example | -|---------------------------|-------------------------------------------------------|----------------------------------------------| -| **user** | Restrict search to a specific user chat | `search.user = user` | -| **group** | Restrict search to a group | `search.group = group` | -| **hideUserStatus** | Hide online/offline indicator | `search.hideUserStatus = true` | -| **hideGroupType** | Hide group type icon | `search.hideGroupType = true` | -| **searchFilters** | Filters like "Messages", "Media" | `search.set(searchFilters: [SearchFilter] = [.unread, .groups, .photos])` | -| **initialSearchFilter** | Default tab/filter | `search.initialSearchFilter = .messages` | -| **searchIn** | Restrict search: messages / conversations / both | `search.set(searchIn: [SearchScope] = [.messages]) | -| **loadingStateView** | Custom loader | `search.set(loadingStateView: spinner)` | -| **emptyStateView** | Custom empty result view | `search.set(emptyStateView: emptyView)` | -| **errorStateView** | Custom error UI | `search.set(errorStateView: errorView)` | +--- ### Advanced -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. - -*** +For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your own views, layouts, and UI elements and then incorporate those into the component. -#### conversationListItemView +#### Conversation View Customization -With this function, you can assign a custom list item view to an conversation in the search result. For more information, refer to the [itemView](/ui-kit/ios/conversations) prop of the `CometChatConversations` component. +| Function | Description | +|---------------------------------|-------------------------------------------------------------| +| listItemViewForConversation | Assign a custom list item view to a conversation. | +| leadingViewForConversation | Assign a custom leading view to a conversation. | +| titleViewForConversation | Assign a custom title view to a conversation. | +| subtitleViewForConversation | Assign a custom subtitle view to a conversation. | +| tailViewForConversation | Assign a custom trailing view to a conversation. | -#### conversationLeadingView - -With this function, you can assign a custom leading view of an conversation in the search result. For more information, refer to the [leadingView](/ui-kit/ios/conversations) prop of the `CometChatConversations` component. - -#### conversationTitleView - -With this function, you can assign a custom title view to an conversation in the search result. For more information, refer to the [titleView](/ui-kit/ios/conversations) prop of the `CometChatConversations` component. - -#### conversationSubtitleView - -With this function, you can assign a custom subtitle view to an conversation in the search result. For more information, refer to the [subtitleView](/ui-kit/ios/conversations#subtitleview) prop of the `CometChatConversations` component. + + +```swift lines +import CometChatUIKitSwift -#### conversationTrailingView +let searchVC = CometChatSearch() -With this function, you can assign a custom trailing view to an conversation in the search result. For more information, refer to the [trailingView](/ui-kit/ios/conversations#trailingview) prop of the `CometChatConversations` component. +searchVC.set(listItemViewForConversation: { conversation in + let customView = UIView() + // Configure custom conversation view + return customView +}) +``` + + -#### messageListItemView +#### Message View Customization With message item view functions, you can assign custom views to different types of messages in the search result. For more information, refer to the [itemView](/ui-kit/ios/messages#itemview) prop of the `CometChatMessages` component. @@ -266,38 +405,40 @@ Here's how you can override the default message item view with a custom one for -```swift +```swift lines +import CometChatUIKitSwift + let searchVC = CometChatSearch() searchVC.set(listItemViewForMessage: { message in return SearchMessageItemView() }) ``` - -It should look like this in the app: - - + CometChatSearch with custom message item view showing sender name and message text in a customized layout with purple accent styling -- code for custom view: +Custom view implementation: + -```swift +```swift lines class SearchMessageItemView: UIView { + // MARK: - UI Components + private let containerView: UIView = { let view = UIView() - view.backgroundColor = UIColor(red: 0.95, green: 0.93, blue: 0.98, alpha: 1.0) // light purple + view.backgroundColor = UIColor(red: 0.95, green: 0.93, blue: 0.98, alpha: 1.0) return view }() private let senderLabel: UILabel = { let label = UILabel() label.font = UIFont.boldSystemFont(ofSize: 16) - label.textColor = UIColor(red: 0.37, green: 0.22, blue: 0.73, alpha: 1.0) // purple + label.textColor = UIColor(red: 0.37, green: 0.22, blue: 0.73, alpha: 1.0) return label }() @@ -312,7 +453,7 @@ class SearchMessageItemView: UIView { private let bottomLine: UIView = { let view = UIView() - view.backgroundColor = UIColor(red: 0.37, green: 0.22, blue: 0.73, alpha: 1.0) // purple border + view.backgroundColor = UIColor(red: 0.37, green: 0.22, blue: 0.73, alpha: 1.0) return view }() @@ -324,6 +465,7 @@ class SearchMessageItemView: UIView { return stack }() + // MARK: - Initialization override init(frame: CGRect) { super.init(frame: frame) @@ -335,6 +477,8 @@ class SearchMessageItemView: UIView { setupUI() } + // MARK: - Setup + private func setupUI() { addSubview(containerView) containerView.translatesAutoresizingMaskIntoConstraints = false @@ -365,50 +509,222 @@ class SearchMessageItemView: UIView { ]) } - /// Configure view with sender + message (with bold keyword) + // MARK: - Configuration + + /// Configure view with sender name and message text + /// - Parameters: + /// - sender: The sender's name + /// - message: The message content + /// - boldKeyword: Optional keyword to highlight in bold func configure(sender: String, message: String, boldKeyword: String?) { - senderLabel.text = sender + ":" if let keyword = boldKeyword, message.contains(keyword) { let attributed = NSMutableAttributedString(string: message) let range = (message as NSString).range(of: keyword) - attributed.addAttribute(.font, - value: UIFont.boldSystemFont(ofSize: 16), - range: range) + attributed.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 16), range: range) messageLabel.attributedText = attributed } else { messageLabel.text = message } } } +``` + + + +Available message item view functions for customization: + +| Function | Message Type | +|-----------------------------|----------------------| +| listItemViewForMessage | Text Message | +| listItemViewForImage | Image Message | +| listItemViewForVideo | Video Message | +| listItemViewForAudio | Audio Message | +| listItemViewForDocument | Document Message | +| listItemViewForLink | Link Message | + + + +```swift lines +import CometChatUIKitSwift + +let searchVC = CometChatSearch() + +// Custom view for image messages +searchVC.set(listItemViewForImage: { mediaMessage in + let customView = UIView() + // Configure custom image message view + return customView +}) + +// Custom view for video messages +searchVC.set(listItemViewForVideo: { mediaMessage in + let customView = UIView() + // Configure custom video message view + return customView +}) +// Custom view for audio messages +searchVC.set(listItemViewForAudio: { mediaMessage in + let customView = UIView() + // Configure custom audio message view + return customView +}) + +// Custom view for document messages +searchVC.set(listItemViewForDocument: { mediaMessage in + let customView = UIView() + // Configure custom document message view + return customView +}) + +// Custom view for link messages +searchVC.set(listItemViewForLink: { mediaMessage in + let customView = UIView() + // Configure custom link message view + return customView +}) ``` + + + +#### Message Granular View Customization + +For more granular control over message search results, you can customize individual parts of the message item: + +| Function | Description | +|-----------------------------|----------------------------------------------------------| +| leadingViewForMessage | Replaces the message avatar / left section | +| titleViewForMessage | Replaces the message title text | +| subtitleViewForMessage | Replaces the message subtitle text | +| trailingViewForMessage | Replaces the message trailing section | + + + +```swift lines +import CometChatUIKitSwift + +let searchVC = CometChatSearch() + +// Custom leading view for messages (avatar area) +searchVC.set(leadingViewForMessage: { message in + let customView = UIView() + customView.backgroundColor = .systemPurple + customView.layer.cornerRadius = 24 + // Configure custom leading view + return customView +}) + +// Custom title view for messages +searchVC.set(titleViewForMessage: { message in + let label = UILabel() + label.text = message.sender?.name ?? "Unknown" + label.font = .boldSystemFont(ofSize: 16) + return label +}) + +// Custom subtitle view for messages +searchVC.set(subtitleViewForMessage: { message in + let label = UILabel() + if let textMessage = message as? TextMessage { + label.text = textMessage.text + } else { + label.text = message.type + } + label.textColor = .secondaryLabel + return label +}) +// Custom trailing view for messages +searchVC.set(trailingViewForMessage: { message in + let label = UILabel() + let date = Date(timeIntervalSince1970: TimeInterval(message.sentAt)) + let formatter = DateFormatter() + formatter.dateFormat = "HH:mm" + label.text = formatter.string(from: date) + label.font = .systemFont(ofSize: 12) + label.textColor = .tertiaryLabel + return label +}) +``` +#### Initial View -Bellow is the list of message item view functions available for customization: +Customize the view displayed before the user enters a search query using the `initialView` property. -| Function | Message Type | -| -------------------------------- | ---------------------| -| **listItemViewForImage** | Image Message | -| **listItemViewForVideo** | Video Message | -| **listItemViewForAudio** | Audio Message | -| **listItemViewForDocument** | Document Message | -| **listItemViewForLink** | Link Message | + + +```swift lines +import CometChatUIKitSwift -#### DateTime Formatters +let searchVC = CometChatSearch() -#### 1. setDateTimeFormatter +// Create a custom initial view +let initialView = UIView() +let imageView = UIImageView(image: UIImage(systemName: "magnifyingglass")) +imageView.tintColor = .systemGray +imageView.contentMode = .scaleAspectFit +imageView.translatesAutoresizingMaskIntoConstraints = false + +let label = UILabel() +label.text = "Search for conversations and messages" +label.textColor = .secondaryLabel +label.textAlignment = .center +label.translatesAutoresizingMaskIntoConstraints = false + +initialView.addSubview(imageView) +initialView.addSubview(label) + +NSLayoutConstraint.activate([ + imageView.centerXAnchor.constraint(equalTo: initialView.centerXAnchor), + imageView.centerYAnchor.constraint(equalTo: initialView.centerYAnchor, constant: -20), + imageView.widthAnchor.constraint(equalToConstant: 60), + imageView.heightAnchor.constraint(equalToConstant: 60), + label.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 16), + label.leadingAnchor.constraint(equalTo: initialView.leadingAnchor, constant: 20), + label.trailingAnchor.constraint(equalTo: initialView.trailingAnchor, constant: -20) +]) + +searchVC.set(initialView: initialView) +``` + + + +--- + +#### Mention Configuration + +Configure how @all mentions appear in search results using the `setMentionAllLabel` method. + + + +```swift lines +import CometChatUIKitSwift + +let searchVC = CometChatSearch() + +// Set a custom label for @all mentions +searchVC.setMentionAllLabel("all", "Everyone") +``` + + + +--- + +#### DateTime Formatters By providing a custom implementation of the DateTimeFormatterCallback, you can configure how time and date values are displayed. This ensures consistent formatting for labels such as "Today", "Yesterday", "X minutes ago", and more. -```swift -let searchVC = CometChatSearch() +```swift lines +import CometChatUIKitSwift + +let searchVC = CometChatSearch() + searchVC.dateTimeFormatter.today = { timestamp in return "Today • \(formattedTime(timestamp))" } @@ -418,24 +734,150 @@ searchVC.dateTimeFormatter.otherDay = { timestamp in df.dateFormat = "dd MMM yyyy" return df.string(from: Date(timeIntervalSince1970: timestamp)) } +``` + + + +--- +#### Text Formatters + +The `setTextFormatters` method enables developers to define and apply text formatters that dynamically modify or transform message content before rendering it in the UI. Text formatters can be used for: + +- Automatically converting URLs into clickable links +- Applying Markdown or rich text styling +- Replacing certain words or patterns with emojis or predefined text +- Censoring specific words for moderation + +By utilizing this method, developers can enhance readability, usability, and compliance with content guidelines. See the [MentionsFormatter Guide](/ui-kit/ios/mentions-formatter-guide) for more details. + +--- + +## Common Patterns + +### Present Search from Conversations + +Open the search screen from a conversations list: + + + +```swift lines +@objc func openSearch() { + let searchVC = CometChatSearch() + + searchVC.onConversationClicked = { [weak self] conversation, indexPath in + // Navigate to messages for the selected conversation + let messagesVC = CometChatMessages() + if let user = conversation.conversationWith as? User { + messagesVC.user = user + } else if let group = conversation.conversationWith as? Group { + messagesVC.group = group + } + self?.navigationController?.pushViewController(messagesVC, animated: true) + } + + searchVC.onMessageClicked = { [weak self] message in + // Navigate to the message in context + let messagesVC = CometChatMessages() + if let user = message.sender { + messagesVC.user = user + } + self?.navigationController?.pushViewController(messagesVC, animated: true) + } + + navigationController?.pushViewController(searchVC, animated: true) +} ``` + + + +### Search Within a Specific Conversation + +Limit search to messages within a specific user or group chat: + + + +```swift lines +// Search within a specific user's conversation +let searchVC = CometChatSearch() +searchVC.user = user +searchVC.set(searchIn: [.messages]) // Only search messages, not conversations +// Or search within a group +let groupSearchVC = CometChatSearch() +groupSearchVC.group = group +groupSearchVC.set(searchIn: [.messages]) +``` + + +### Filter Search by Media Type + +Show only photo or video messages in search results: + + + +```swift lines +let searchVC = CometChatSearch() + +// Set available filters with photos as the initial selection +searchVC.set(searchFilters: [.photos, .videos, .documents, .audio], initialFilter: .photos) + +// Or programmatically filter messages +let msgBuilder = MessagesRequest.MessageRequestBuilder() + .set(categories: ["message"]) + .set(types: ["image", "video"]) +searchVC.set(messagesRequestBuilder: msgBuilder) +``` + -*** +### Custom Search Result Actions -#### Text Formatters +Handle search result selection with custom actions: -#### setTextFormatters + + +```swift lines +let searchVC = CometChatSearch() -This method enables developers to define and apply text formatters that dynamically modify or transform message content before rendering it in the UI. Text formatters can be used for purposes such as: +searchVC.onMessageClicked = { [weak self] message in + // Show action sheet for the selected message + let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + + alert.addAction(UIAlertAction(title: "Go to Message", style: .default) { _ in + self?.navigateToMessage(message) + }) + + alert.addAction(UIAlertAction(title: "Reply", style: .default) { _ in + self?.replyToMessage(message) + }) + + alert.addAction(UIAlertAction(title: "Forward", style: .default) { _ in + self?.forwardMessage(message) + }) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + + self?.present(alert, animated: true) +} +``` + + -* Automatically converting URLs into clickable links -* Applying Markdown or rich text styling -* Replacing certain words or patterns with emojis or predefined text -* Censoring specific words for moderation +--- -By utilizing this method, developers can enhance readability, usability, and compliance with content guidelines. [MentionsFormatter Guide](/ui-kit/ios/mentions-formatter-guide) \ No newline at end of file +## Related Components + + + + Display conversation list + + + Display chat messages + + + Display user list + + diff --git a/ui-kit/ios/shortcut-formatter-guide.mdx b/ui-kit/ios/shortcut-formatter-guide.mdx index e10d35e5c..c9797c250 100644 --- a/ui-kit/ios/shortcut-formatter-guide.mdx +++ b/ui-kit/ios/shortcut-formatter-guide.mdx @@ -1,250 +1,303 @@ --- title: "ShortCut Formatter" +sidebarTitle: "ShortCut Formatter" +description: "Implement message shortcuts using the ShortCutFormatter class in CometChat UI Kit for iOS" --- ## Introduction -The ShortCutFormatter class extends the CometChatTextFormatter class to provide a mechanism for handling shortcuts within messages. This guide will walk you through the process of using ShortCutFormatter to implement shortcut extensions in your CometChat application. +The `ShortCutFormatter` class extends the `CometChatTextFormatter` class to provide a mechanism for handling shortcuts within messages. This guide walks you through the process of using `ShortCutFormatter` to implement shortcut extensions in your CometChat application. + +--- ## Setup -1. **Create the ShortCutFormatter Class**: Define the `ShortCutFormatter` class by extending the `CometChatTextFormatter` class. +### 1. Create the ShortCutFormatter Class + +Define the `ShortCutFormatter` class by extending the `CometChatTextFormatter` class: -```swift +```swift lines class ShortcutFormatter: CometChatTextFormatter { - - private var messageShortcuts: [String: String] = [String: String]( ) + + // Store fetched shortcuts from the extension + private var messageShortcuts: [String: String] = [:] + + // Store suggestion items for display private var shortcuts: [CometChatUIKitSwift.SuggestionItem] = [] - } ``` - - -2. **initializer**: Sets the `trackingCharacter` to **'!'** in the initializer of the `ShortcutFormatter` class +### 2. Initialize with Tracking Character + +Set the `trackingCharacter` to `'!'` in the initializer: -```swift - override init(trackingCharacter: Character) { - super.init(trackingCharacter: "!") - } +```swift lines +override init(trackingCharacter: Character) { + super.init(trackingCharacter: "!") +} ``` - - -3. **Prepare Regex**: Set the regular expression for shortcut detection in the `getRegex()` method of `ShortcutFormatter` class. +### 3. Define the Regex Pattern + +Set the regular expression for shortcut detection in the `getRegex()` method: -```swift +```swift lines override func getRegex() -> String { - return "(^|\\s)!\\w+" + return "(^|\\s)!\\w+" } ``` - - -4. **Prepare TrackingCharacter**: Define the `getTrackingCharacter()` method to return **'!'** as the shortcut tracking character in `ShortcutFormatter` class. +### 4. Return the Tracking Character + +Define the `getTrackingCharacter()` method to return `'!'` as the shortcut tracking character: -```swift +```swift lines override func getTrackingCharacter() -> Character { - return "!" + return "!" } ``` - - -5. **Override Search Method**: Override the `search()` method to search for shortcuts based on the entered query. +### 5. Implement the Search Method + +Override the `search()` method to search for shortcuts based on the entered query: -```swift +```swift lines override func search(string: String, suggestedItems: (([CometChatUIKitSwift.SuggestionItem]) -> ())? = nil) { - - if messageShortcuts.isEmpty == true { - CometChat.callExtension(slug: "message-shortcuts", type: .get, endPoint: "v1/fetch", body: nil) { [weak self] extensionResponseData in - guard let this = self else { return } - if let shotCutData = extensionResponseData?["shortcuts"] as? [String: String] { - this.messageShortcuts = shotCutData - var suggestedItemsList = [CometChatUIKitSwift.SuggestionItem]() - this.messageShortcuts.forEach({ (key, value) in - if key.hasPrefix(string) { - suggestedItemsList.append(CometChatUIKitSwift.SuggestionItem(id: key, name: value, visibleText: value)) - } - }) - suggestedItems?(suggestedItemsList) - } - } onError: { error in - print("Error occured while fetcing shot cuts: \(error?.errorDescription)") + + // Fetch shortcuts from extension if not already cached + if messageShortcuts.isEmpty { + CometChat.callExtension( + slug: "message-shortcuts", + type: .get, + endPoint: "v1/fetch", + body: nil + ) { [weak self] extensionResponseData in + guard let self = self else { return } + + if let shortcutData = extensionResponseData?["shortcuts"] as? [String: String] { + self.messageShortcuts = shortcutData + + // Filter shortcuts matching the search string + let suggestedItemsList = self.messageShortcuts + .filter { $0.key.hasPrefix(string) } + .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) } + + suggestedItems?(suggestedItemsList) } - - } else { - var suggestedItemsList = [CometChatUIKitSwift.SuggestionItem]() - messageShortcuts.forEach({ (key, value) in - if key.hasPrefix(string) { - suggestedItemsList.append(CometChatUIKitSwift.SuggestionItem(id: key, name: value, visibleText: value)) - } - }) - suggestedItems?(suggestedItemsList) + } onError: { error in + print("Error occurred while fetching shortcuts: \(error?.errorDescription ?? "Unknown error")") + } + } else { + // Use cached shortcuts + let suggestedItemsList = messageShortcuts + .filter { $0.key.hasPrefix(string) } + .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) } + + suggestedItems?(suggestedItemsList) } - } ``` - - -6. **Handle prepareMessageString**: Implement the `prepareMessageString()` method to convert the base chat message into an attributed string for display in the `ShortcutFormatter` class. +### 6. Handle Message String Preparation + +Implement the `prepareMessageString()` method to convert the base chat message into an attributed string for display: -```swift -override func prepareMessageString(baseMessage: BaseMessage, regexString: String, alignment: MessageBubbleAlignment = .left, formattingType: FormattingType) -> NSAttributedString { -let message = (baseMessage as? TextMessage)?.text ?? "" -return NSAttributedString(string: message) +```swift lines +override func prepareMessageString( + baseMessage: BaseMessage, + regexString: String, + alignment: MessageBubbleAlignment = .left, + formattingType: FormattingType +) -> NSAttributedString { + let message = (baseMessage as? TextMessage)?.text ?? "" + return NSAttributedString(string: message) } ``` - - -7. **Handle onTextTapped**: Override the `onTextTapped()` method if needed. +### 7. Handle Text Tap Events + +Override the `onTextTapped()` method if you need to handle tap events on formatted text: -```swift +```swift lines override func onTextTapped(baseMessage: BaseMessage, tappedText: String, controller: UIViewController?) { - // Your code here + // Handle tap event on shortcut text } ``` - - -* Below is an example of how a `ShortcutFormatter` Swift file might look: +--- -```swift ShortcutFormatter.swift +## Complete Implementation + +Here's the complete `ShortcutFormatter` class: + + + +```swift lines import Foundation import CometChatSDK import CometChatUIKitSwift class ShortcutFormatter: CometChatTextFormatter { - - private var messageShortcuts: [String: String] = [String: String]() + + // MARK: - Properties + + private var messageShortcuts: [String: String] = [:] private var shortcuts: [CometChatUIKitSwift.SuggestionItem] = [] - + + // MARK: - Initialization + override init(trackingCharacter: Character) { super.init(trackingCharacter: "!") } - + + // MARK: - Override Methods + override func getRegex() -> String { return "(^|\\s)!\\w+" } - + override func getTrackingCharacter() -> Character { return "!" } - + override func search(string: String, suggestedItems: (([CometChatUIKitSwift.SuggestionItem]) -> ())? = nil) { - - if messageShortcuts.isEmpty == true { - CometChat.callExtension(slug: "message-shortcuts", type: .get, endPoint: "v1/fetch", body: nil) { [weak self] extensionResponseData in - guard let this = self else { return } - if let shotCutData = extensionResponseData?["shortcuts"] as? [String: String] { - this.messageShortcuts = shotCutData - var suggestedItemsList = [CometChatUIKitSwift.SuggestionItem]() - this.messageShortcuts.forEach({ (key, value) in - if key.hasPrefix(string) { - suggestedItemsList.append(CometChatUIKitSwift.SuggestionItem(id: key, name: value, visibleText: value)) - } - }) + + if messageShortcuts.isEmpty { + CometChat.callExtension( + slug: "message-shortcuts", + type: .get, + endPoint: "v1/fetch", + body: nil + ) { [weak self] extensionResponseData in + guard let self = self else { return } + + if let shortcutData = extensionResponseData?["shortcuts"] as? [String: String] { + self.messageShortcuts = shortcutData + + let suggestedItemsList = self.messageShortcuts + .filter { $0.key.hasPrefix(string) } + .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) } + suggestedItems?(suggestedItemsList) } - } onError: { error in - print("Error occured while fetcing shot cuts: \(error?.errorDescription)") + print("Error occurred while fetching shortcuts: \(error?.errorDescription ?? "Unknown error")") } - } else { - - var suggestedItemsList = [CometChatUIKitSwift.SuggestionItem]() - messageShortcuts.forEach({ (key, value) in - if key.hasPrefix(string) { - suggestedItemsList.append(CometChatUIKitSwift.SuggestionItem(id: key, name: value, visibleText: value)) - } - }) + let suggestedItemsList = messageShortcuts + .filter { $0.key.hasPrefix(string) } + .map { CometChatUIKitSwift.SuggestionItem(id: $0.key, name: $0.value, visibleText: $0.value) } + suggestedItems?(suggestedItemsList) - } - } - - override func prepareMessageString(baseMessage: BaseMessage, regexString: String, alignment: MessageBubbleAlignment = .left, formattingType: FormattingType) -> NSAttributedString { + + override func prepareMessageString( + baseMessage: BaseMessage, + regexString: String, + alignment: MessageBubbleAlignment = .left, + formattingType: FormattingType + ) -> NSAttributedString { let message = (baseMessage as? TextMessage)?.text ?? "" return NSAttributedString(string: message) } - + override func onTextTapped(baseMessage: BaseMessage, tappedText: String, controller: UIViewController?) { - // Your code here + // Handle tap event on shortcut text } } ``` + + + +--- ## Usage -1. **Initialization**: Initialize an instance of `ShortCutFormatter` in your application. +### 1. Initialize the Formatter + +Create an instance of `ShortCutFormatter`: -```swift +```swift lines let shortcutFormatter = ShortcutFormatter(trackingCharacter: "!") ``` - - -2. **Integration**: Integrating the `ShortCutFormatter` into your CometChat application involves incorporating it within your project to handle message shortcuts. If you're utilizing the [CometChatMessageComposer](/ui-kit/ios/message-composer) component, you can seamlessly integrate the ShortCutFormatter to manage shortcut functionalities within your application. +### 2. Integrate with Message Composer -* Your final integration code should look like this: +If you're using the [CometChatMessageComposer](/ui-kit/ios/message-composer) component, integrate the `ShortCutFormatter` to manage shortcut functionalities: -```swift +```swift lines let shortcutFormatter = ShortcutFormatter(trackingCharacter: "!") - + let cometChatMessageComposer = CometChatMessageComposer() cometChatMessageComposer.set(textFormatter: [shortcutFormatter]) ``` - - - - -Ensure to pass and present `cometChatConversationsWithMessages`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. + +Ensure to pass and present `cometChatConversationsWithMessages`. If a navigation controller is already in use, utilize the `pushViewController` function instead of directly presenting the view controller. + - +--- ## Example + +--- + +## Next Steps + + + + Add @mentions with styled tokens and click handling. + + + Customize the message input component. + + + Display and customize chat messages. + + + Define custom message bubble structures. + + + +--- diff --git a/ui-kit/ios/sound-manager.mdx b/ui-kit/ios/sound-manager.mdx index a9fdcd3cc..24ecdeaaf 100644 --- a/ui-kit/ios/sound-manager.mdx +++ b/ui-kit/ios/sound-manager.mdx @@ -1,42 +1,126 @@ --- title: "Sound Manager" +sidebarTitle: "Sound Manager" +description: "Manage and play audio for messages and calls in CometChat UI Kit for iOS" --- + + +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Class | `CometChatSoundManager` | +| Purpose | Manages audio playback for messages and calls | +| Play Method | `play(sound: Sound, customSound: URL?)` | +| Pause Method | `pause()` | +| Sound Types | `.incomingMessage`, `.outgoingMessage`, `.incomingCall`, `.outgoingCall` | +| Custom Sound | Pass `URL` to override default sounds | + + + ## Overview -The SoundManager is a helper class responsible for managing and playing various types of audio in the CometChat UI Kit. This includes sound events for incoming and outgoing messages and calls. +`CometChatSoundManager` is a helper class that manages audio playback in the CometChat UI Kit. It handles sound events for incoming and outgoing messages and calls, supporting both default sounds and custom audio files. + +--- ## Methods ### Play Sound -The SoundManager plays pre-defined or custom sounds based on user interactions with the chat interface. If no custom sound file is provided, the default sound is played. +The `play(sound:customSound:)` method triggers audio playback based on user interactions with the chat interface. If no custom sound file is provided, the default sound for that event type is played. -Here are the available methods for triggering sound playback: +```swift lines +play(sound: Sound, customSound: URL?) +``` -* `play(sound: Sound, customSound: URL?)`: This method plays different types of sounds for incoming and outgoing calls and messages.Moreover, it can play a customized sound for a specific URL when triggered. +| Parameter | Type | Description | +| ----------- | ------ | ------------------------------------------------------------------------------------------------ | +| sound | Sound | The type of sound event (e.g., `.incomingMessage`, `.outgoingMessage`, `.incomingCall`, `.outgoingCall`) | +| customSound | URL? | Optional URL to a custom sound file. If `nil`, the default sound is used. | ### Pause Sound -The SoundManager can pause different types of sounds for incoming and outgoing calls and messages using the following method: +The `pause()` method stops any sound currently being played by the SoundManager. -* `pause()`: This method pauses any sound currently being played. +```swift lines +pause() +``` + +--- ## Usage -Here is how to use CometChatSoundManager: +### Playing Default Sounds + +Play the default sound for an incoming message: -```php -// Play sound: + + +```swift lines +// Play the default incoming message sound CometChatSoundManager().play(sound: .incomingMessage) +``` + + + +### Playing Custom Sounds + +Provide a custom audio file URL to override the default sound: -// Play sound with custom sound: + + +```swift lines +// Play a custom sound for incoming messages if let customSoundURL = Bundle.main.url(forResource: "customSound", withExtension: "wav") { - CometChatSoundManager().play(sound: .incomingMessage, customSound: customSoundURL) + CometChatSoundManager().play(sound: .incomingMessage, customSound: customSoundURL) } +``` + + + +### Pausing Sounds -// Pause Sound: +Stop any currently playing sound: + + + +```swift lines +// Pause the currently playing sound CometChatSoundManager().pause() ``` + + + +--- + +## Sound Types + +The `Sound` enum provides the following options: + +| Sound Type | Description | +| ------------------ | ----------------------------------------- | +| `.incomingMessage` | Played when a new message is received | +| `.outgoingMessage` | Played when a message is sent | +| `.incomingCall` | Played when an incoming call is received | +| `.outgoingCall` | Played when initiating an outgoing call | + +--- + +By using `CometChatSoundManager`, you can enhance the user experience in your chat application by integrating audible cues for chat interactions. + +--- -By using the CometChatSoundManager, you can enhance the user experience in your chat application by integrating audible cues for chat interactions. +## Next Steps + + + + Customize the visual appearance + + + Adapt to different languages + + + Style individual components + + diff --git a/ui-kit/ios/theme-introduction.mdx b/ui-kit/ios/theme-introduction.mdx index 7a8559d15..b31bec8ee 100644 --- a/ui-kit/ios/theme-introduction.mdx +++ b/ui-kit/ios/theme-introduction.mdx @@ -1,24 +1,42 @@ --- title: "Introduction" +sidebarTitle: "Introduction" +description: "Create visually consistent and customizable user interfaces with CometChat theming for iOS" --- + + +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Package | `CometChatUIKitSwift` | +| Theme Class | `CometChatTheme` — Global theming system for all CometChat components | +| Primary Color | `CometChatTheme.primaryColor = UIColor` | +| Background Colors | `CometChatTheme.backgroundColor01`, `backgroundColor02`, `backgroundColor03` | +| Border Colors | `CometChatTheme.borderColorDefault`, `borderColorLight`, `borderColorDark` | +| Typography Class | `CometChatTypography` | +| Typography Properties | `Body.regular`, `Body.bold`, `Heading.regular` | +| Example | `CometChatTheme.primaryColor = UIColor(hex: "#F76808")` | + + + ## Overview -Theming in CometChat for iOS allows you to create visually consistent and customizable user interfaces that align with your application's branding. The CometChatTheme system enables global theming, customization of colors, typography, spacing, and component-specific styles to enhance the user experience across all CometChat components. +Theming in CometChat for iOS allows you to create visually consistent and customizable user interfaces that align with your application's branding. The `CometChatTheme` system enables global theming, customization of colors, typography, spacing, and component-specific styles to enhance the user experience across all CometChat components. With global styles and an easy-to-override architecture, you can seamlessly apply themes at both a global and component level. -## Using Theming in Your Project +--- -Global Theming +## Using Theming in Your Project -Set up the global theme for your application during the app launch. This ensures all CometChat components use the specified theme. +### Global Theming -Example in AppDelegate.swift +Set up the global theme for your application during app launch. This ensures all CometChat components use the specified theme. -```swift +```swift lines import UIKit import CometChatSDK @@ -26,7 +44,10 @@ import CometChatSDK class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { // Apply the global theme CometChatTheme.primaryColor = UIColor.systemBackground @@ -38,33 +59,46 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } ``` - - -## Customization +--- -Customizing Colors +## Customization -Override specific color attributes globally in CometChatTheme. This is equivalent to overriding attributes in Android's themes.xml. +### Customizing Colors -Example: Setting Primary Color +Override specific color attributes globally in `CometChatTheme`. This is equivalent to overriding attributes in Android's `themes.xml`. -```swift -CometChatTheme.primaryColor = UIColor(hex: "#F76808") // Custom primary color +```swift lines +// Set a custom primary color +CometChatTheme.primaryColor = UIColor(hex: "#F76808") ``` - - + +--- + +## Next Steps + + + + Customize theme colors and dark mode + + + Style individual components + + + Customize message bubbles + + diff --git a/ui-kit/ios/threaded-messages-header.mdx b/ui-kit/ios/threaded-messages-header.mdx index ac5a95af2..fdd01da71 100644 --- a/ui-kit/ios/threaded-messages-header.mdx +++ b/ui-kit/ios/threaded-messages-header.mdx @@ -1,112 +1,148 @@ --- title: "Threaded Messages Header" +sidebarTitle: "Threaded Messages Header" +description: "Display and customize the header for threaded message conversations in CometChat UI Kit for iOS" --- -## Overview - -ThreadedMessages is a [Composite Component](/ui-kit/ios/components-overview#composite-components) that displays all replies made to a particular message in a conversation. By default, the parent message will be displayed at the top, the message composer will be at the bottom and between them a message list will contain all replies. +The `CometChatThreadedMessageHeader` component displays the header for threaded message conversations showing parent message info. By default, the parent message appears at the top, the message composer is at the bottom, and a message list containing all replies is displayed between them. + +```json +{ + "component": "CometChatThreadedMessageHeader", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays the header for threaded message conversations showing parent message info", + "inherits": "UIView", + "primaryOutput": { + "callback": "onBack", + "type": "() -> Void" + }, + "props": { + "data": { + "parentMessage": { "type": "BaseMessage", "required": true } + }, + "callbacks": { + "onBack": "() -> Void" + } + }, + "events": [], + "sdkListeners": [], + "compositionExample": { + "description": "ThreadedMessageHeader is used within ThreadedMessages component", + "components": ["CometChatThreadedMessageHeader", "CometChatMessageList", "CometChatMessageComposer"], + "flow": "User opens thread → sees parent message in header → views/sends replies below" + } +} +``` + + +| Field | Value | +|-------|-------| +| Component | `CometChatThreadedMessageHeader` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIView` | + +--- + ThreadedMessages is composed of the following components: -| Component | Description | -| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| Component | Description | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | [MessageList](/ui-kit/ios/message-list) | CometChatMessageList is a component that displays a list of Messages | | [MessageComposer](/ui-kit/ios/message-composer) | CometChatMessageComposer is a component that helps in writing and editing of messages and also sending attachments | +--- + ## Usage ### Integration -As `CometChatThreadedMessageHeader` is a **view**, you can add it to your view controller by adding the following code snippet. +Since `CometChatThreadedMessageHeader` is a view, you can add it to your view controller using the following code snippet: -```swift +```swift lines let threadedMessage = CometChatThreadedMessageHeader() view.addSubview(threadedMessage) ``` - - - Ensure to pass and present `threadedMessage`. If a navigation controller is already in use, utilize the pushViewController function instead of directly presenting the view controller. - -*** +--- ### Filters -**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK. +Filters allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria for a more customized experience. Filters can be applied using RequestBuilders of Chat SDK. ThreadedMessages does not have its own Filters. However, you can filter the messages list in ThreadedMessages Component using [MessageListConfiguration](#configuration). **Example** -In this example, we are filtering messages and searching for messages that contain the keyword "payment". +In this example, we are filtering messages and searching for messages that contain the keyword "payment": -```swift -let messageRequestBuilder = MessagesRequest.MessageRequestBuilder() -.set(uid: "your UID") -.set(searchKeyword: "sure") +```swift lines +// MARK: - Filter messages by search keyword +let messageRequestBuilder = MessagesRequest.MessageRequestBuilder() + .set(uid: "your UID") + .set(searchKeyword: "sure") let messageList = CometChatMessageList() messageList.set(user: user) messageList.set(messagesRequestBuilder: messageRequestBuilder) ``` - - -*** +--- ### Events -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. +[Events](/ui-kit/ios/components-overview#events) are emitted by a Component. By using events, you can extend existing functionality. Being global events, they can be applied in multiple locations and are capable of being added or removed. The MessageList Component does not emit any events of its own. -*** +--- ## Customization To fit your app's design requirements, you can customize the appearance of the conversation component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. -*** +--- ### Style -`ThreadedMessagesStyle` contains various properties which can be used to customize the UI of `CometChatThreadedMessages`. +`ThreadedMessageHeaderStyle` contains various properties which can be used to customize the UI of `CometChatThreadedMessageHeader`. -**Global level styling** +**Global Level Styling** -```swift +```swift lines +// MARK: - Apply global styling CometChatThreadedMessageHeader.style.backgroundColor = UIColor(hex: "#F76808") CometChatThreadedMessageHeader.style.dividerTintColor = UIColor(hex: "#F76808") CometChatThreadedMessageHeader.style.bubbleContainerBackgroundColor = UIColor(hex: "#F76808") ``` - - -**Instance level styling** +**Instance Level Styling** -```swift +```swift lines +// MARK: - Apply instance-level styling let customThreadedHeaderStyle = ThreadedMessageHeaderStyle() customThreadedHeaderStyle.backgroundColor = UIColor(hex: "#F76808") customThreadedHeaderStyle.dividerTintColor = UIColor(hex: "#F76808") @@ -115,9 +151,7 @@ customThreadedHeaderStyle.bubbleContainerBackgroundColor = UIColor(hex: "#F76808 let threadedMessage = CometChatThreadedMessageHeader() threadedMessage.style = customThreadedHeaderStyle ``` - - @@ -126,25 +160,27 @@ threadedMessage.style = customThreadedHeaderStyle List of properties available for configuring in ThreadedMessagesStyle: -| **Property** | **Description** | **Code** | +| Property | Description | Code | | ------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------ | -| **Background Color** | Background color for the header. | `CometChatThreadedMessageHeader.style.backgroundColor = CometChatTheme.backgroundColor03` | -| **Border Color** | Border color for the header. | `CometChatThreadedMessageHeader.style.borderColor = UIColor.clear` | -| **Border Width** | Border width for the header. | `CometChatThreadedMessageHeader.style.borderWith = 0` | -| **Corner Radius** | Corner radius for the header. | `CometChatThreadedMessageHeader.style.cornerRadius = CometChatCornerStyle?` | -| **Bubble Container Background Color** | Background color for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerBackgroundColor = UIColor.clear` | -| **Bubble Container Border Color** | Border color for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerBorderColor = UIColor.clear` | -| **Bubble Container Border Width** | Border width for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerBorderWidth = 0` | -| **Bubble Container Corner Radius** | Corner radius for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerCornerRadius = CometChatCornerStyle?` | -| **Divider Tint Color** | Tint color for the divider. | `CometChatThreadedMessageHeader.style.dividerTintColor = CometChatTheme.extendedPrimaryColor100` | -| **Count Text Color** | Text color for the message count text. | `CometChatThreadedMessageHeader.style.countTextColor = CometChatTheme.textColorSecondary` | -| **Count Text Font** | Font for the message count text. | `CometChatThreadedMessageHeader.style.countTextFont = CometChatTypography.Body.regular` | +| Background Color | Background color for the header. | `CometChatThreadedMessageHeader.style.backgroundColor = CometChatTheme.backgroundColor03` | +| Border Color | Border color for the header. | `CometChatThreadedMessageHeader.style.borderColor = UIColor.clear` | +| Border Width | Border width for the header. | `CometChatThreadedMessageHeader.style.borderWith = 0` | +| Corner Radius | Corner radius for the header. | `CometChatThreadedMessageHeader.style.cornerRadius = CometChatCornerStyle?` | +| Bubble Container Background Color | Background color for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerBackgroundColor = UIColor.clear` | +| Bubble Container Border Color | Border color for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerBorderColor = UIColor.clear` | +| Bubble Container Border Width | Border width for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerBorderWidth = 0` | +| Bubble Container Corner Radius | Corner radius for the bubble container. | `CometChatThreadedMessageHeader.style.bubbleContainerCornerRadius = CometChatCornerStyle?` | +| Divider Tint Color | Tint color for the divider. | `CometChatThreadedMessageHeader.style.dividerTintColor = CometChatTheme.extendedPrimaryColor100` | +| Count Text Color | Text color for the message count text. | `CometChatThreadedMessageHeader.style.countTextColor = CometChatTheme.textColorSecondary` | +| Count Text Font | Font for the message count text. | `CometChatThreadedMessageHeader.style.countTextFont = CometChatTypography.Body.regular` | + +--- ### Functionality -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can set maximum lines text area will show before scrolling in the composer, edit a message, add header view and footer view to the composer, etc. +These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can set maximum lines the text area will show before scrolling in the composer, edit a message, add header view and footer view to the composer, and more. -Below is a list of customizations along with corresponding code snippets message composer offers +Below is a list of customizations along with corresponding code snippets: | Property | Description | Code | | ------------------- | ------------------------------------------------------ | --------------------------------- | @@ -156,36 +192,37 @@ Below is a list of customizations along with corresponding code snippets message | setMessageAlignment | Sets the alignment of messages (e.g., left or right). | `setMessageAlignment(.right)` | | setParentMessage | Sets the parent message for the threaded conversation. | `setParentMessage(parentMessage)` | +--- + ### Advanced For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. #### SetDatePattern -You can modify the date pattern to your requirement using .set(datePattern:). This method accepts a function with a return type String. Inside the function, you can create your own pattern and return it as a String. +You can modify the date pattern to your requirement using `.set(datePattern:)`. This method accepts a function with a return type String. Inside the function, you can create your own pattern and return it as a String. **Example** -```swift +```swift lines +// MARK: - Custom date pattern let threadedMessageHeader = CometChatThreadedMessageHeader() threadedMessageHeader.set(datePattern: { timestamp in guard let timestamp = timestamp else { - return "" + return "" } - let date = Date(timeIntervalSince1970: TimeInterval(timestamp/1000)) + let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000)) let formatter = DateFormatter() formatter.dateFormat = "dd-MM-yyyy" return formatter.string(from: date) }) ``` - - -*** +--- #### SetTextFormatters @@ -195,98 +232,213 @@ This functionality dynamically assigns a list of text formatters. If a custom li This code customizes a CometChat text formatter to identify and style the word "sure", with handling options for interactions like string search, scrolling, and item clicks. The custom formatter is then applied to CometChat messages. -```ruby Swift + + +```swift lines +// MARK: - Apply custom text formatter let myCustomTextFormatter = MyCustomTextFormatter(trackingCharacter: "#") -let threadedMessageHeader = CometChatThreadedMessageHeader() +let threadedMessageHeader = CometChatThreadedMessageHeader() .set(user: user) .set(textFormatter: [myCustomTextFormatter]) ``` + + -Demonstration: +**Demonstration:** -```swift +```swift lines import Foundation import CometChatSDK import CometChatUIKitSwift class MyCustomTextFormatter: CometChatTextFormatter { -override func getRegex() -> String { -return "(\\bsure\\b)" - + + // MARK: - Regex Pattern + override func getRegex() -> String { + return "(\\bsure\\b)" } + // MARK: - Tracking Character override func getTrackingCharacter() -> Character { return "#" } + // MARK: - Search override func search(string: String, suggestedItems: ((_: [SuggestionItem]) -> ())? = nil) { // This function would call an API or perform a local search // For now, it does nothing } + // MARK: - Pagination override func onScrollToBottom(suggestionItemList: [SuggestionItem], listItem: ((_: [SuggestionItem]) -> ())?) { // This function would call the next page of an API // For now, it does nothing } + // MARK: - Item Selection override func onItemClick(suggestedItem: SuggestionItem, user: User?, group: Group?) { // Do something with the clicked item } + // MARK: - Pre-Send Processing override func handlePreMessageSend(baseMessage: BaseMessage, suggestionItemList: [SuggestionItem]) { // This function would modify the message before it's sent // For now, it does nothing } + // MARK: - Message String Formatting override func prepareMessageString( - baseMessage: BaseMessage, - regexString: String, - alignment: MessageBubbleAlignment = .left, - formattingType: FormattingType + baseMessage: BaseMessage, + regexString: String, + alignment: MessageBubbleAlignment = .left, + formattingType: FormattingType ) -> NSAttributedString { let attrString = NSMutableAttributedString(string: "SURE") - if alignment == .left { // Received message + if alignment == .left { + // Received message styling attrString.addAttribute(.foregroundColor, value: UIColor.blue, range: NSRange(location: 0, length: attrString.length)) - } else { // Sent message + } else { + // Sent message styling attrString.addAttribute(.foregroundColor, value: UIColor.green, range: NSRange(location: 0, length: attrString.length)) } attrString.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: attrString.length)) return attrString } + // MARK: - Text Tap Handler override func onTextTapped(baseMessage: BaseMessage, tappedText: String, controller: UIViewController?) { // Your Action } - } ``` - - -*** +--- #### SetTemplate and AddTemplate [CometChatMessageTemplate](/ui-kit/ios/message-template) is a pre-defined structure for creating message views that can be used as a starting point or blueprint for creating message views often known as message bubbles. For more information, you can refer to [CometChatMessageTemplate](/ui-kit/ios/message-template). -*** +--- - +## Common Patterns -To ensure that the `ThreadedMessages` is properly configured, passing the controller is mandatory. +### Open Thread from Message List -* Swift +Present the threaded messages view when a user taps on a message's reply count: -```swift -let threadedMessageView = CometChatThreadedMessages() -threadedMessageView.set(controller: UIViewController) // Passing the controller is required + + +```swift lines +// In your message list delegate or action handler +func openThread(for parentMessage: BaseMessage) { + // Create a view controller to host the threaded messages + let threadVC = UIViewController() + threadVC.view.backgroundColor = .systemBackground + + // Create threaded message header + let threadedHeader = CometChatThreadedMessageHeader() + threadedHeader.set(parentMessage: parentMessage) + threadedHeader.set(controller: threadVC) + threadedHeader.translatesAutoresizingMaskIntoConstraints = false + + // Create message list for thread replies + let messageList = CometChatMessageList() + if let user = parentMessage.sender { + messageList.set(user: user) + } + messageList.set(parentMessage: parentMessage) + messageList.set(controller: threadVC) + messageList.translatesAutoresizingMaskIntoConstraints = false + + // Create composer for thread replies + let composer = CometChatMessageComposer() + if let user = parentMessage.sender { + composer.set(user: user) + } + composer.set(parentMessage: parentMessage) + composer.set(controller: threadVC) + composer.translatesAutoresizingMaskIntoConstraints = false + + // Add to view + threadVC.view.addSubview(threadedHeader) + threadVC.view.addSubview(messageList) + threadVC.view.addSubview(composer) + + // Layout constraints + NSLayoutConstraint.activate([ + threadedHeader.topAnchor.constraint(equalTo: threadVC.view.safeAreaLayoutGuide.topAnchor), + threadedHeader.leadingAnchor.constraint(equalTo: threadVC.view.leadingAnchor), + threadedHeader.trailingAnchor.constraint(equalTo: threadVC.view.trailingAnchor), + + messageList.topAnchor.constraint(equalTo: threadedHeader.bottomAnchor), + messageList.leadingAnchor.constraint(equalTo: threadVC.view.leadingAnchor), + messageList.trailingAnchor.constraint(equalTo: threadVC.view.trailingAnchor), + messageList.bottomAnchor.constraint(equalTo: composer.topAnchor), + + composer.leadingAnchor.constraint(equalTo: threadVC.view.leadingAnchor), + composer.trailingAnchor.constraint(equalTo: threadVC.view.trailingAnchor), + composer.bottomAnchor.constraint(equalTo: threadVC.view.safeAreaLayoutGuide.bottomAnchor) + ]) + + self.navigationController?.pushViewController(threadVC, animated: true) +} ``` + + - +### Customize Thread Header with Parent Message Info + +Display additional context about the parent message in the thread header: + + + +```swift lines +let threadedHeader = CometChatThreadedMessageHeader() +threadedHeader.set(parentMessage: parentMessage) + +// Custom date formatting +threadedHeader.set(datePattern: { timestamp in + guard let timestamp = timestamp else { return "" } + let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000)) + let formatter = DateFormatter() + formatter.dateFormat = "MMM d 'at' h:mm a" + return formatter.string(from: date) +}) +``` + + + +### Filter Thread Replies + +Show only specific types of messages in the thread: + + + +```swift lines +// Filter to show only text messages in thread +let messageRequestBuilder = MessagesRequest.MessageRequestBuilder() + .set(parentMessageId: parentMessage.id) + .set(types: ["text"]) + .set(limit: 30) + +let messageList = CometChatMessageList() +messageList.set(messagesRequestBuilder: messageRequestBuilder) +``` + + + +--- -*** + +To ensure that the `CometChatThreadedMessageHeader` is properly configured, passing the controller is mandatory. + +```swift lines +let threadedMessageHeader = CometChatThreadedMessageHeader() +threadedMessageHeader.set(controller: UIViewController) // Passing the controller is required +``` + diff --git a/ui-kit/ios/troubleshooting.mdx b/ui-kit/ios/troubleshooting.mdx new file mode 100644 index 000000000..0926b84b5 --- /dev/null +++ b/ui-kit/ios/troubleshooting.mdx @@ -0,0 +1,274 @@ +--- +title: "Troubleshooting" +sidebarTitle: "Troubleshooting" +description: "Common issues and solutions for CometChat iOS UI Kit" +--- + + + +| Field | Value | +| --- | --- | +| Platform | iOS UI Kit | +| Common Issues | Initialization, theming, real-time updates, permissions | +| Key Checks | SDK initialization, user login, CometChatUIKit.init() order | +| Permissions | Camera, microphone (Info.plist) | +| Debug | Check SDK connection status, verify dashboard settings | + + + +This guide covers common issues and solutions when working with the CometChat iOS UI Kit. + +--- + +## CocoaPods Issues + +| Issue | Solution | +|-------|----------| +| "Could not find compatible versions" | Run `pod install --repo-update` to refresh spec repos | +| Pod version not found | Verify the version exists on [CocoaPods](https://cocoapods.org/pods/CometChatUIKitSwift) | +| Repo clone failures | Clean repos with commands below, then retry | +| Build errors after pod install | Open `.xcworkspace` file, not `.xcodeproj` | + +### Clean and Retry + +```bash +rm -rf Pods Podfile.lock +pod cache clean --all +pod install --repo-update +``` + +### Reset CocoaPods Completely + +If repo errors persist: + +```bash +rm -rf ~/.cocoapods/repos +pod setup +pod install --repo-update +``` + +### Fallback to Swift Package Manager + +If CocoaPods continues to fail, use SPM instead: + +1. Remove Podfile and Pods folder +2. Open your `.xcodeproj` in Xcode +3. Go to **File → Add Package Dependencies** +4. Add `https://github.com/cometchat/cometchat-uikit-ios` with version `5.1.9` +5. Add `https://github.com/cometchat/chat-sdk-ios` with version `4.1.0` + +--- + +## Initialization Issues + +| Issue | Solution | +|-------|----------| +| SDK not initialized | Call `CometChat.init()` before any UI Kit operations | +| User not logged in | Ensure `CometChat.login()` completes successfully before showing UI | +| UIKit not initialized | Call `CometChatUIKit.init()` after SDK init and before using components | +| Credentials invalid | Verify App ID, Auth Key, and Region in CometChat Dashboard | + +--- + +## Theming & Styling + +| Issue | Solution | +|-------|----------| +| Colors not applying | Apply theme before `CometChatUIKit.init()` | +| Dark mode not working | Use `UIColor { traitCollection in }` for dynamic colors | +| Inconsistent colors | Set all related colors (text, background, border) together | +| Styles not applying | Apply global styles before `CometChatUIKit.init()` | +| Instance style overridden | Instance styles take precedence over global styles | +| Font not loading | Verify font name is correct and font is added to project | + +--- + +## Conversations + +| Issue | Solution | +|-------|----------| +| Empty conversation list | Ensure user is logged in and has existing conversations | +| Conversations not updating | Check SDK connection and real-time listeners | +| Navigation not working | Verify `navigationController` is not nil; embed in `UINavigationController` | +| Custom views not appearing | Ensure custom view has proper constraints and non-zero frame | +| Typing indicator not showing | Verify `disableTyping` is not set to true | + +--- + +## Users + +| Issue | Solution | +|-------|----------| +| Empty user list | Ensure SDK is initialized and user is logged in | +| Users not updating in real-time | Check SDK connection and presence listeners | +| Search not working | Verify `hideSearch` is not set to true | +| Status not showing | Check that `hideUserStatus` is not set to true | +| Custom views not appearing | Ensure custom view has proper constraints | + +--- + +## Groups + +| Issue | Solution | +|-------|----------| +| Empty group list | Ensure SDK is initialized and user is logged in | +| Groups not updating in real-time | Check SDK connection and group listeners | +| Search not working | Verify `hideSearch` is not set to true | +| Group type icons not showing | Check that `hideGroupType` is not set to true | +| Custom views not appearing | Ensure custom view has proper constraints | + +--- + +## Group Members + +| Issue | Solution | +|-------|----------| +| Empty member list | Ensure group object is valid and has members | +| Management options not showing | Check logged-in user's permissions (must be admin/owner) | +| Search not working | Verify `hideSearch` is not set to true | +| Status not showing | Check that `hideUserStatus` is not set to true | +| Custom views not appearing | Ensure custom view has proper constraints | + +--- + +## Message Header + +| Issue | Solution | +|-------|----------| +| Header not showing user info | Ensure user or group is set on the header | +| Status not updating | Check SDK connection and user presence listeners | +| Back button not working | Verify `onBack` callback is set and `hideBackButton` is false | +| Typing indicator not showing | Ensure typing events are enabled in SDK | +| Call buttons not appearing | Check that `hideVideoCallButton` and `hideVoiceCallButton` are false | + +--- + +## Message List + +| Issue | Solution | +|-------|----------| +| Messages not loading | Ensure user/group is set and SDK is initialized | +| Real-time updates not working | Check SDK connection status and listeners | +| Reactions not showing | Verify reactions are enabled in dashboard | +| Thread replies not working | Ensure `hideReplyInThreadOption` is not set to true | +| Custom views not appearing | Ensure custom view has proper constraints and non-zero frame | +| Scroll position issues | Check `scrollToBottomOnNewMessages` setting | + +--- + +## Message Composer + +| Issue | Solution | +|-------|----------| +| Send button not working | Ensure user or group is set on the composer | +| Attachments not showing | Check that attachment options are not hidden | +| Voice recording not working | Verify microphone permissions are granted in Info.plist | +| Mentions not working | Ensure `disableMentions` is not set to true | +| Typing indicators not sent | Check that `disableTypingEvents` is not set to true | + +--- + +## Calling + +| Issue | Solution | +|-------|----------| +| Call buttons not showing | Verify `CometChatCallsSDK` is in Podfile and run `pod install` | +| "Permission denied" error | Add camera/microphone permissions to Info.plist | +| Calls not connecting | Check network connection and CometChat credentials | +| No incoming call UI | Ensure `CometChatCallsSDK` is initialized before login | +| Audio not working | Check device is not on silent mode | + +--- + +## AI Features + +| Issue | Solution | +|-------|----------| +| AI features not appearing | Enable them in CometChat Dashboard → AI | +| Conversation starters not showing | Only appear for new conversations with no messages | +| Smart replies not appearing | Ensure feature is enabled and messages exist | +| Summary not generating | Need sufficient messages in conversation | +| AI Assistant empty | Verify user has AI chat history | +| Only loading indicator shows | Set `user` or `group` property | +| Styling not applied | Apply style before presenting view | +| Callbacks not firing | Set callbacks before pushing to navigation | +| AI not responding | Verify AI features are enabled in dashboard | +| Streaming not working | Check network connectivity | +| Agent not detected | Verify user has `isAgentic` property set to true | + +--- + +## Events + +| Issue | Solution | +|-------|----------| +| Events not firing | Verify listener is added before the action occurs | +| Duplicate events | Check you're not adding the same listener multiple times | +| Memory leaks | Ensure `removeListener` is called in `viewWillDisappear` | +| UI not updating | Dispatch UI updates to main thread with `DispatchQueue.main.async` | +| Listener ID conflicts | Use unique, descriptive IDs for each listener | + +--- + +## Permissions (Info.plist) + +Add these keys to your `Info.plist` for full functionality: + +```xml + +NSCameraUsageDescription +Camera access is required for video calls and capturing photos + + +NSMicrophoneUsageDescription +Microphone access is required for voice calls and audio messages + + +NSPhotoLibraryUsageDescription +Photo library access is required to send images +``` + +--- + +## Debug Checklist + +When troubleshooting issues, verify the following: + +1. **SDK Initialization** + - `CometChat.init()` called with correct App ID and Region + - `CometChatUIKit.init()` called after SDK init + +2. **User Authentication** + - User is logged in via `CometChat.login()` + - Auth token is valid and not expired + +3. **Dashboard Settings** + - Features are enabled (AI, Reactions, etc.) + - API keys have correct permissions + +4. **Network** + - Device has internet connectivity + - WebSocket connection is established + +5. **Permissions** + - Required permissions added to Info.plist + - User has granted permissions at runtime + +--- + +## Getting Help + + + + Complete implementation example + + + CometChat UIKit iOS repository + + + Complete list of error codes + + + Contact CometChat support + + diff --git a/ui-kit/ios/upgrading-from-v4.mdx b/ui-kit/ios/upgrading-from-v4.mdx index d4f8fc6f9..19ed98fae 100644 --- a/ui-kit/ios/upgrading-from-v4.mdx +++ b/ui-kit/ios/upgrading-from-v4.mdx @@ -1,55 +1,90 @@ --- -title: "Upgrading From V4" +title: "Upgrading from V4 to V5" +sidebarTitle: "Upgrading from V4" +description: "Migration guide for upgrading from CometChat iOS UI Kit v4 to v5 with breaking changes, property updates, and new patterns." --- -## Introduction + -The **CometChat v5 iOS UI Kit** streamlines the integration of in-app chat functionality into your iOS applications. Packed with prebuilt, modular UI components built natively in Swift, it supports essential messaging features for both one-to-one and group conversations. With built-in theming options, including light and dark modes, customizable fonts, colors, and extensive configuration possibilities, developers can create chat experiences tailored to their application's needs. +| Field | Value | +| --- | --- | +| Package | `CometChatUIKitSwift` | +| Architecture | Composite components replaced with modular components | +| Theming | Direct static property assignment on `CometChatTheme` and `CometChatTypography` | +| Key changes | `CometChatConversationsWithMessages` → Individual components (`CometChatConversations`, `CometChatMessageHeader`, `CometChatMessageList`, `CometChatMessageComposer`) | +| Style props | Removed — use native theming system with direct property access | +| Config props | Removed — direct control over each component | + + + +The CometChat v5 iOS UI Kit introduces a modular architecture with smaller, focused components replacing composite components. This guide outlines the key differences and provides migration steps from v4 to v5. + +--- + +## Overview of Changes + +| Feature | v4 | v5 | +| --- | --- | --- | +| Architecture | Composite components (e.g., `CometChatConversationsWithMessages`) | Modular components (`CometChatConversations`, `CometChatMessageList`, etc.) | +| Theming | `CometChatTheme` with `Palette` and `Typography` classes | Direct static property assignment | +| Customization | Complex configuration objects | Direct component properties and Swift APIs | +| Style Props | Inline style properties | Native theming system | +| Custom Views | `itemView`, `leadingView`, `trailingView`, `subtitleView`, `titleView` | Unified naming convention across components | + +--- ## Integration -In **v4**, integration was straightforward due to the availability of composite components like `CometChatConversationsWithMessages`. This single component provided end-to-end functionality, including listing conversations, handling conversation clicks, loading messages (message header, list, composer), displaying user or group details, and supporting threaded messages. Developers could achieve all these features with minimal setup. However, customization posed significant challenges. Customizing the UI or adding custom views required a deep understanding of the internal flow of the composite component. Additionally, configurations were a mix of custom view props, behavioral props, and style props, which often led to confusion. Styling deeply nested components also proved cumbersome, limiting the developer's ability to make meaningful changes. +In v4, integration was straightforward due to composite components like `CometChatConversationsWithMessages`. This single component provided end-to-end functionality including listing conversations, handling clicks, loading messages, and supporting threaded messages. However, customization required deep understanding of internal flows, and configurations mixed custom view props, behavioral props, and style props. -With **v5**, composite components have been replaced with smaller, modular components, such as `CometChatConversations`, `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer`. This modular approach makes integration more flexible and easier to understand. Each component has a well-defined purpose, allowing developers to use them in ways that suit their specific requirements. The need for complex configurations has been eliminated, as developers can now customize behavior and styling directly via component properties and Swift APIs. +With v5, composite components are replaced with smaller, modular components: +- `CometChatConversations` +- `CometChatMessageHeader` +- `CometChatMessageList` +- `CometChatMessageComposer` -To support the transition from v4 to v5, CometChat has built a [sample app](https://github.com/cometchat/cometchat-uikit-ios/tree/v5) that replicates the functionality of v4's composite components. This sample app serves as a reference for developers looking to build additional features such as user/group details, call log details, threaded messages, and advanced messaging capabilities. By following this approach, developers can take full advantage of v5's modular design while implementing complex functionality in an organized manner. +This modular approach makes integration more flexible. Each component has a well-defined purpose, and developers can customize behavior and styling directly via component properties and Swift APIs. -Learn how to build a complete messaging UI using the **v5 UI Kit** by following the step-by-step guide [here](/ui-kit/ios/getting-started). +Learn how to build a complete messaging UI using the v5 UI Kit by following the [Getting Started guide](/ui-kit/ios/getting-started). +--- + ## Components -The **v4** UI Kit provided composite components like `CometChatConversationsWithMessages`, which offered end-to-end functionality. These components integrated features such as conversation lists, message views (header, list, composer), user/group details, and threaded messages into a single unit. However, customization of deeply nested components through configuration was challenging and resulted in a suboptimal developer experience. +### v4 Components -| Components in v4 UI Kit: | | | -| ---------------------------------- | -------------------------- | --------------------------- | +| | | | +| --- | --- | --- | | CometChatConversationsWithMessages | CometChatUsersWithMessages | CometChatGroupsWithMessages | -| CometChatMessages | CometChatMessageHeader | CometChatMessageList | -| CometChatMessageComposer | CometChatThreadedMessages | CometChatConversations | -| CometChatUsers | CometChatGroups | CometChatContacts | -| CometChatDetails | CometChatGroupMembers | CometChatAddMembers | -| CometChatBannedMembers | CometChatTransferOwnership | CometChatMessageInformation | -| CometChatIncomingCall | CometChatOngoingCall | CometChatOutgoingCall | -| CometChatCallButtons | CometChatCallLogs | CometChatCallLogDetails | -| CometChatCallLogHistory | | | +| CometChatMessages | CometChatMessageHeader | CometChatMessageList | +| CometChatMessageComposer | CometChatThreadedMessages | CometChatConversations | +| CometChatUsers | CometChatGroups | CometChatContacts | +| CometChatDetails | CometChatGroupMembers | CometChatAddMembers | +| CometChatBannedMembers | CometChatTransferOwnership | CometChatMessageInformation | +| CometChatIncomingCall | CometChatOngoingCall | CometChatOutgoingCall | +| CometChatCallButtons | CometChatCallLogs | CometChatCallLogDetails | +| CometChatCallLogHistory | | | + +### v5 Components + +| | | | +| --- | --- | --- | +| CometChatConversations | CometChatUsers | CometChatGroups | +| CometChatGroupMembers | CometChatMessageHeader | CometChatMessageList | +| CometChatMessageComposer | CometChatThreadedMessageHeader | CometChatIncomingCall | +| CometChatOutgoingCall | CometChatCallButtons | CometChatCallLogs | - -In **v5**, the composite approach is replaced with smaller, modular components like `CometChatConversations`, `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer`. Developers now need to stitch these components together to build the desired functionality. This change allows for greater flexibility and easier customization via properties, significantly improving the developer experience while maintaining functionality. - -| Components in v5 UI Kit: | | | -| ------------------------ | ------------------------------- | --------------------- | -| CometChatConversations | CometChatUsers | CometChatGroups | -| CometChatGroupMembers | CometChatMessageHeader | CometChatMessageList | -| CometChatMessageComposer | CometChatThreadedMessageHeader | CometChatIncomingCall | -| CometChatOutgoingCall | CometChatCallButtons | CometChatCallLogs | +--- ## Theming -In **v4**, theming was managed using the `CometChatTheme` class along with the `Palette` and `Typography` classes. The `Palette` class provided methods like `set(background:)`, `set(accent:)`, `set(primary:)`, and similar setters for configuring colors and themes. While this approach worked, it required instantiating multiple objects and passing them through constructors, which added complexity to the theming process. Developers had to create palette and typography instances, configure them with various color and font settings, and then pass them to create a theme object. +### v4 Theming +In v4, theming required instantiating multiple objects and passing them through constructors: -```swift App.delegate +```swift title="V4 UI Kit" let palette = Palette() palette.set(background: .purple) palette.set(accent: .cyan) @@ -69,13 +104,11 @@ typography.overrideFont(family: family) let theme = CometChatTheme(typography: typography, palatte: palette) ``` -In **v5**, theming has been completely revamped for simplicity and directness. The complex theming classes and object instantiation have been replaced with direct static property assignment on `CometChatTheme` and `CometChatTypography`. This means every design token, such as colors and typography, can now be set directly as static properties. Changing the primary color, for instance, is as simple as assigning a value to `CometChatTheme.primaryColor` — no need to interact with complex theming logic or instantiate multiple objects. - -The new theming approach is declarative and lightweight, significantly enhancing both performance and developer experience. By providing direct access to theme properties, developers can now customize the look and feel of their application with minimal code and maximum clarity. - +### v5 Theming +In v5, theming uses direct static property assignment: -```swift App.delegate +```swift title="V5 UI Kit" // Apply the global theme - typically in AppDelegate or SceneDelegate CometChatTheme.primaryColor = UIColor.red CometChatTheme.backgroundColor01 = .brown @@ -85,25 +118,432 @@ CometChatTheme.backgroundColor02 = .green CometChatTypography.Body.regular = UIFont.systemFont(ofSize: 18, weight: .bold) ``` -This architectural redesign makes theming more intuitive and aligns with modern iOS development practices. Developers now have a more powerful and straightforward toolset to customize and manage themes effectively. - -For detailed guidance on theming and customizing colors in the CometChat iOS UI Kit, refer to the following resources: - -* **Theming Documentation:** [Guide to Theming](/ui-kit/ios/color-resources) -* **Color Customization:** [Customizing Colors](/ui-kit/ios/theme-introduction) +For detailed guidance on theming, refer to: +- [Theming Documentation](/ui-kit/ios/theme-introduction) +- [Color Customization](/ui-kit/ios/color-resources) +--- + ## Properties -In **v5**, the approach to properties has been significantly refined to improve clarity and ease of use. All style-related properties, previously used to customize components, have been replaced by a more efficient and native theming system based on **direct property access and configuration classes**. This change ensures a seamless and flexible styling process without requiring verbose or redundant setup within component properties. +In v5, the approach to properties has been refined: -Configuration properties, which were widely used in **v4**, have also been removed. With **v5’s modular architecture**, components are no longer deeply nested or dependent on complex configuration objects. Developers now have **direct control over each component**, reducing complexity and increasing flexibility in how components are customized, styled, and composed. +- **Style properties** — Replaced by a native theming system based on direct property access +- **Configuration properties** — Removed due to modular architecture; developers have direct control over each component +- **Custom view properties** — Restructured for consistency with unified naming: `itemView`, `leadingView`, `trailingView`, `subtitleView`, `titleView` -Custom view properties have been restructured to ensure **consistency and uniformity** across all components. For instance, components that represent list items or visual elements now share a unified set of customizable properties, allowing developers to adopt a standardized approach to component customization. These properties include `itemView`, `leadingView`, `trailingView`, `subtitleView`, and `titleView`. +--- + +## Property Changes + +### Conversations + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| hideNavigationBar | Bool | Hides or shows the navigation bar | +| hideSearch | Bool | Hides the search bar | +| hideLoadingState | Bool | Hides the loading state indicator | +| hideDeleteConversationOption | Bool | Hides the option to delete a conversation | +| hideGroupType | Bool | Hides the group type indicator | +| backgroundDrawable | UIImage | Sets a background image | +| separatorColor | UIColor | Sets the color of separators | +| separatorWidth | CGFloat | Sets the width of separators | +| errorTextColor | UIColor | Sets the color of error messages | +| lastMessageTextColor | UIColor | Sets the color of the last message text | +| typingIndicatorColor | UIColor | Sets the color of the typing indicator | +| dateTimeFormatter | CometChatDateTimeFormatter | Customizes date/time display | +| set(OnItemLongClick:) | Method | Triggered on long press | +| set(onEmpty:) | Method | Triggered when list is empty | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| hide(error: Bool) | hideErrorView | Hides the error state view | +| show(backButton: Bool) | hideBackButton | Controls back button visibility (logic inverted) | +| hide(receipt: Bool) | hideReceipts | Hides message receipts | +| disable(userPresence: Bool) | hideUserStatus | Hides online/offline status | +| setOnItemClick | set(OnItemClick:) | Triggered on click | +| setOnBack | set(onBack:) | Override back button action | +| setOnSelection | set(onSelection:) | Triggered on selection | +| setOnError | set(onError:) | Override error action | + +#### Removed Properties + +| Name | Description | +| --- | --- | +| hide(separator: Bool) | Replaced by style properties | +| disable(typing: Bool) | Toggled typing indicator visibility | +| setDatePattern | Replaced by dateTimeFormatter | +| protectedGroupIcon | Icon for password protected groups | +| sentIcon, deliveredIcon, readIcon | Receipt icons | + +--- + +### Users + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| set(options:) | (User) -> [CometChatUserOption] | Custom options for each user | +| set(leadingView:) | (User) -> UIView | Custom leading view | +| set(titleView:) | (User) -> UIView | Custom title view | +| set(trailView:) | (User) -> UIView | Custom trailing view | +| set(onEmpty:) | () -> Void | Triggered when list is empty | +| hideErrorView | Bool | Hides the error state view | +| hideNavigationBar | Bool | Hides the navigation bar | +| hideBackButton | Bool | Hides the back button | +| hideLoadingState | Bool | Hides loading indicator | +| hideUserStatus | Bool | Hides online/offline status | +| hideSectionHeader | Bool | Hides section headers | +| hideSearch | Bool | Hides the search bar | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| setListItemView | set(listItemView:) | Custom list item view | +| setSubtitleView | set(subtitleView:) | Custom subtitle view | +| setEmptyStateView | set(emptyView:) | Custom empty state view | +| setErrorStateView | set(errorView:) | Custom error state view | +| setOnItemClick | set(onItemClick:) | Triggered on click | +| setOnItemLongClick | set(onItemLongClick:) | Triggered on long press | +| setOnBack | set(onBack:) | Triggered on back press | +| setOnSelection | set(onSelection:) | Triggered on selection | +| setOnError | set(onError:) | Triggered on error | + +#### Removed Properties + +| Name | Description | +| --- | --- | +| set(loadingStateView:) | Set loading view icon size | +| hide(errorText:) | Hide error text | +| show(backButton:) | Toggle back button | +| set(searchIcon:) | Set search icon | +| hide(search:) | Toggle search box | +| hide(separator:) | Hide divider | +| disable(userPresence:) | Control online indicator | +| set(emptyStateText:) | Custom empty text | +| set(errorStateText:) | Custom error text | +| set(searchPlaceholder:) | Search placeholder | +| set(title:mode:) | Set title with display mode | +| setOnLoad | Triggered when list is fetched | -This consistent naming convention provides developers with a predictable customization model across multiple components, simplifying the development process and ensuring UI consistency throughout the app. +--- -For a comprehensive overview of newly added, renamed, and removed properties, refer to the [Property Changes](/ui-kit/ios/property-changes) documentation. +### Groups + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| set(onSelection:) | Closure | Returns selected groups | +| set(onEmpty:) | Closure | Triggered when list is empty | +| setOnLoad | Closure | Triggered when list is fetched | +| listItemSelectedImage | UIImage | Selected checkbox image | +| listItemDeSelectedImage | UIImage | Deselected checkbox image | +| hideErrorView | Bool | Hides error state view | +| hideNavigationBar | Bool | Hides navigation bar | +| hideSearch | Bool | Hides search bar | +| hideBackButton | Bool | Hides back button | +| hideLoadingState | Bool | Hides loading indicator | +| set(leadingView:) | (Group?) -> UIView | Custom leading view | +| set(titleView:) | (Group?) -> UIView | Custom title view | +| set(trailView:) | (Group?) -> UIView | Custom trailing view | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| SetOnItemClick | set(onItemClick:) | Triggered on click | +| SetOnItemLongClick | set(OnItemLongClick:) | Triggered on long press | +| SetOnError | set(onError:) | Triggered on error | +| SetOnBack | set(onBack:) | Triggered on back press | +| setListItemView | SetListItemView | Custom list item | +| setSubtitleView | SetSubTitleView | Custom subtitle view | --- + +### Group Members + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| hideError | Bool | Hides error state view | +| hideUserStatus | Bool | Hides online/offline status | +| hideNavigationBar | Bool | Hides navigation bar | +| hideLoadingState | Bool | Hides loading indicator | +| hideBackIcon | Bool | Hides back button | +| hideKickMemberOption | Bool | Hides kick member option | +| hideBanMemberOption | Bool | Hides ban member option | +| hideScopeChangeOption | Bool | Hides scope change option | +| hideSearch | Bool | Hides search bar | +| set(onSelection:) | ([GroupMember]) -> Void | Returns selected members | +| set(onEmpty:) | () -> Void | Triggered when list is empty | +| set(onLoad:) | ([GroupMember]) -> Void | Triggered when list is fetched | +| set(leadingView:) | (GroupMember?) -> UIView | Custom leading view | +| set(titleView:) | (GroupMember?) -> UIView | Custom title view | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| background | backgroundColor | Background color | +| disable(userPresence:) | hideUserStatus | Hides online/offline status | +| hide(search:) | hideSearch | Hides search bar | +| setOnItemClick | set(onItemClick:) | Triggered on click | +| setOnItemLongClick | set(onItemLongClick:) | Triggered on long press | +| setOnError | set(onError:) | Triggered on error | +| setOnBack | set(onBack:) | Triggered on back press | + +#### Removed Properties + +| Name | Description | +| --- | --- | +| backIconTint | Back button tint color | +| searchIconTint | Search icon tint color | +| avatarStyle | Avatar component styles | +| statusIndicatorStyle | Status indicator styles | +| listItemStyle | List item view styles | +| groupScopeStyle | Change scope component styles | +| groupMembersStyle | Component styles | +| set(title:mode:) | Custom title | +| set(backButtonTitle:) | Back button text | +| set(searchPlaceholder:) | Search placeholder | +| show(backButton:) | Show back button | +| set(errorStateText:) | Error state text | +| selectionMode(mode:) | Selection mode | +| hide(separator:) | Hide separator | + +--- + +### Message Header + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| titleTextColor | UIColor | Header title text color | +| titleTextFont | UIFont | Header title font | +| subtitleTextColor | UIColor | Subtitle text color | +| subtitleTextFont | UIFont | Subtitle font | +| backButtonImageTintColor | UIColor | Back button tint | +| hideBackButton | Bool | Hides back button | +| hideUserStatus | Bool | Hides user status | +| hideVideoCallButton | Bool | Hides video call button | +| hideVoiceCallButton | Bool | Hides voice call button | +| set(onBack:) | () -> Void | Triggered on back press | +| set(onError:) | (CometChatException) -> Void | Triggered on error | +| set(listItemView:) | (User?, Group?) -> UIView | Custom list item | +| set(leadingView:) | (User?, Group?) -> UIView | Custom leading view | +| set(titleView:) | (User?, Group?) -> UIView | Custom title view | +| set(trailView:) | (User?, Group?) -> UIView | Custom trailing view | +| set(subtitleView:) | (User?, Group?) -> UIView | Custom subtitle view | +| dateTimeFormatter | CometChatDateTimeFormatter | Date/time formatting | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| background | backgroundColor | Background color | +| backIconTint | backButtonImageTintColor | Back button tint | +| hide(backButton:) | hideBackButton | Hides back button | +| set(disableUsersPresence:) | hideUserStatus | Hides user status | +| setMenus | set(menus:) | Custom menus | +| setSubtitleView | set(subtitleView:) | Custom subtitle view | + +#### Removed Properties + +| Name | Description | +| --- | --- | +| typingIndicatorTextFont | Typing indicator font | +| typingIndicatorTextColor | Typing indicator color | +| detailIconTint | Detail icon tint | +| onlineStatusColor | Online status color | +| set(protectedGroupIcon:) | Protected group icon | +| set(privateGroupIcon:) | Private group icon | +| disable(typing:) | Enable/disable typing indicators | + +--- + +### Message List + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| hideAvatar | Bool | Hides sender avatar | +| hideGroupActionMessages | Bool | Hides group action messages | +| hideReplyInThreadOption | Bool | Hides reply in thread option | +| hideTranslateMessageOption | Bool | Hides translation option | +| hideEditMessageOption | Bool | Hides edit option | +| hideDeleteMessageOption | Bool | Hides delete option | +| hideReactionOption | Bool | Hides reaction option | +| hideMessagePrivatelyOption | Bool | Hides message privately option | +| hideCopyMessageOption | Bool | Hides copy option | +| hideMessageInfoOption | Bool | Hides message info option | +| hideHeaderView | Bool | Hides header view | +| hideFooterView | Bool | Hides footer view | +| hideDateSeparator | Bool | Hides date separator | +| scrollToBottomOnNewMessages | Bool | Scrolls to bottom on new messages | +| hideReceipts | Bool | Hides read receipts | +| disableSoundForMessages | Bool | Disables message sound | +| hideEmptyView | Bool | Hides empty state view | +| hideErrorView | Bool | Hides error view | +| hideLoadingView | Bool | Hides loading view | +| hideNewMessageIndicator | Bool | Hides new message indicator | +| set(onThreadRepliesClick:) | (BaseMessage, CometChatMessageTemplate) -> Void | Thread click callback | +| set(onReactionClick:) | (CometChat.ReactionCount, BaseMessage?) -> Void | Reaction click callback | +| set(onError:) | (CometChatException) -> Void | Error callback | +| set(onEmpty:) | () -> Void | Empty state callback | +| set(onLoad:) | ([BaseMessage]) -> Void | Load callback | +| set(headerView:) | UIView | Custom header view | +| set(footerView:) | UIView | Custom footer view | +| set(textFormatters:) | [CometChatTextFormatter] | Text formatters | +| dateTimeFormatter | CometChatDateTimeFormatter | Date/time formatting | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| hide(receipt:) | hideReceipts | Hides receipts | +| show(avatar:) | hideAvatar | Shows/hides avatar | +| background | backgroundColor | Background color | +| alignment | set(messageAlignment:) | Message alignment | + +#### Removed Properties + +| Name | Description | +| --- | --- | +| loadingIconTint | Loading icon tint | +| emptyTextFont | Empty state text font | +| errorTextFont | Error text font | +| emptyTextColor | Empty state text color | +| errorTextColor | Error state text color | +| nameTextColor | Sender name text color | +| nameTextFont | Sender name font | +| timestampTextColor | Timestamp text color | +| threadReplySeperatorColor | Thread reply separator color | +| threadReplyTextColor | Thread reply text color | +| threadReplyTextFont | Thread reply font | +| hide(error:) | Hide error view | +| messageInformationConfiguration | Message info configuration | +| reactionsConfiguration | Reactions configuration | +| setDateSeparatorPattern | Date separator pattern | +| setDatePattern | Date pattern | + +--- + +### Message Composer + +#### New Properties + +| Name | Type | Description | +| --- | --- | --- | +| placeHolderTextFont | UIFont | Placeholder font | +| placeHolderTextColor | UIColor | Placeholder color | +| textFiledColor | UIColor | Input text color | +| textFiledFont | UIFont | Input text font | +| sendButtonImage | UIImage | Send button icon | +| sendButtonImageTint | UIColor | Send button tint | +| activeSendButtonImageBackgroundColor | UIColor | Active send button background | +| inactiveSendButtonImageBackgroundColor | UIColor | Inactive send button background | +| attachmentImage | UIImage | Attachment button icon | +| attachmentImageTint | UIColor | Attachment button tint | +| voiceRecordingImage | UIImage | Voice recording icon | +| voiceRecordingImageTint | UIColor | Voice recording tint | +| aiImage | UIImage | AI button icon | +| aiImageTint | UIColor | AI button tint | +| stickerImage | UIImage | Sticker button icon | +| stickerTint | UIColor | Sticker button tint | +| disableTypingEvents | Bool | Disables typing indicators | +| disableMentions | Bool | Disables mentions | +| hideImageAttachmentOption | Bool | Hides image attachment | +| hideVideoAttachmentOption | Bool | Hides video attachment | +| hideAudioAttachmentOption | Bool | Hides audio attachment | +| hideFileAttachmentOption | Bool | Hides file attachment | +| hidePollsOption | Bool | Hides polls option | +| hideCollaborativeDocumentOption | Bool | Hides collaborative document | +| hideCollaborativeWhiteboardOption | Bool | Hides collaborative whiteboard | +| hideAttachmentButton | Bool | Hides attachment button | +| hideVoiceRecordingButton | Bool | Hides voice recording button | +| hideStickersButton | Bool | Hides stickers button | +| hideSendButton | Bool | Hides send button | +| set(onSendButtonClick:) | (BaseMessage) -> Void | Send button callback | +| set(onTextChangedListener:) | (String) -> Void | Text change callback | +| set(onError:) | (CometChatException) -> Void | Error callback | +| set(attachmentOptions:) | (User?, Group?, UIViewController?) -> [CometChatMessageComposerAction] | Custom attachment options | +| set(sendButtonView:) | (User?, Group?) -> UIView | Custom send button | +| set(headerView:) | (User?, Group?) -> UIView | Custom header view | +| set(footerView:) | (User?, Group?) -> UIView | Custom footer view | +| set(textFormatter:) | [CometChatTextFormatter] | Text formatters | +| mediaRecorderStyle | MediaRecorderStyle | Media recording styling | +| aiOptionsStyle | AIOptionsStyle | AI options styling | + +#### Renamed Properties + +| v4 Name | v5 Name | Description | +| --- | --- | --- | +| background | backgroundColor | Background color | +| hide(voiceRecording:) | hideVoiceRecordingButton | Hides voice recording | +| disable(disableTypingEvents:) | disableTypingEvents | Disables typing events | +| disable(disableSoundForMessages:) | disableSoundForMessages | Disables message sound | +| setMentionsFormatters | set(textFormatter:) | Text formatters | + +#### Removed Properties + +| Name | Description | +| --- | --- | +| inputBackground | Input background color | +| textFont | Input text font | +| inputBoxPlaceholderFont | Placeholder font | +| attachmentIconTint | Attachment icon tint | +| sendIconTint | Send icon tint | +| separatorTint | Separator color | +| inputBorderWidth | Input border width | +| inputBorderColor | Input border color | +| actionSheetTitleColor | Action sheet title color | +| actionSheetTitleFont | Action sheet title font | +| voiceRecordingIconTint | Voice recording icon tint | +| aiIconTint | AI icon tint | +| set(background:) | Background color | +| set(placeholderText:) | Placeholder text | +| set(maxLines:) | Max lines | +| set(auxiliaryButtonAlignment:) | Auxiliary button position | +| set(customSoundForMessage:) | Custom message sound | +| set(liveReactionIconURL:) | Live reaction icon | +| set(disableMentions:) | Disable mentions | +| setOnSendButtonClick | Send button callback | +| hide(liveReaction:) | Hide live reaction | +| hide(footerView:) | Hide footer view | +| hide(headerView:) | Hide header view | +| hide(sendButton:) | Hide send button | +| setAttachmentOptions | Attachment options | +| setAuxilaryButtonView | Auxiliary button view | +| setSecondaryButtonView | Secondary button view | +| setSendButtonView | Send button view | + +--- + +## Next Steps + + + + Fresh v5 setup guide for iOS + + + Explore all v5 prebuilt UI components + + + New direct property-based theming system + + + Customize colors and dark mode + + diff --git a/ui-kit/ios/users.mdx b/ui-kit/ios/users.mdx index 17f682101..28369c4ab 100644 --- a/ui-kit/ios/users.mdx +++ b/ui-kit/ios/users.mdx @@ -1,598 +1,480 @@ --- title: "Users" +description: "Display and manage a list of users with search functionality" --- -## Overview - -The Users is a [Component](/ui-kit/ios/components-overview#components), showcasing an accessible list of all available users. It provides an integral search functionality, allowing you to locate any specific user swiftly and easily. For each user listed, the widget displays the user's name by default, in conjunction with their avatar when available. Furthermore, it includes a status indicator, visually informing you whether a user is currently online or offline. +The `CometChatUsers` component displays a searchable list of all available users. It shows user names, avatars, and online/offline status indicators. Users can be filtered, searched, and selected for starting conversations. - + CometChatUsers showing a searchable list of users with avatars, names, and online/offline status indicators -The Users component is composed of the following BaseComponents: + +```json +{ + "component": "CometChatUsers", + "package": "CometChatUIKitSwift", + "import": "import CometChatUIKitSwift\nimport CometChatSDK", + "description": "Displays a searchable list of all available users with avatars, names, and online/offline status indicators.", + "inherits": "UIViewController", + "primaryOutput": { + "callback": "onItemClick", + "type": "(User, IndexPath) -> Void" + }, + "props": { + "data": { + "usersRequestBuilder": { + "type": "UsersRequest.UsersRequestBuilder?", + "default": "nil", + "note": "Custom request builder for filtering users" + }, + "searchRequestBuilder": { + "type": "UsersRequest.UsersRequestBuilder?", + "default": "nil", + "note": "Custom request builder for search" + } + }, + "callbacks": { + "onItemClick": "(User, IndexPath) -> Void", + "onItemLongClick": "(User, IndexPath) -> Void", + "onBack": "() -> Void", + "onSelection": "([User]) -> Void", + "onSelectedItemProceed": "([User]) -> Void", + "onError": "(CometChatException) -> Void", + "onEmpty": "() -> Void", + "onLoad": "([[User]]) -> Void" + }, + "visibility": { + "hideSearch": { "type": "Bool", "default": false }, + "hideNavigationBar": { "type": "Bool", "default": false }, + "hideBackButton": { "type": "Bool", "default": false }, + "hideUserStatus": { "type": "Bool", "default": false }, + "hideSectionHeader": { "type": "Bool", "default": false }, + "hideErrorView": { "type": "Bool", "default": false }, + "hideLoadingState": { "type": "Bool", "default": false } + }, + "selection": { + "selectionMode": { "type": "SelectionMode", "default": ".none" }, + "selectionLimit": { "type": "Int", "default": 0, "note": "0 means unlimited" }, + "selectedCellCount": { "type": "Int", "default": 0, "note": "Read-only count of selected users" } + }, + "styling": { + "avatarStyle": { "type": "AvatarStyle", "default": "AvatarStyle()" }, + "statusIndicatorStyle": { "type": "StatusIndicatorStyle", "default": "StatusIndicatorStyle()" } + }, + "viewSlots": { + "listItemView": "(User) -> UIView", + "leadingView": "(User) -> UIView", + "titleView": "(User?) -> UIView", + "subtitleView": "(User?) -> UIView", + "trailingView": "(User?) -> UIView", + "emptyStateView": "() -> UIView", + "errorStateView": "() -> UIView", + "loadingStateView": "() -> UIView" + } + }, + "methods": { + "swipeActions": { + "set(options:)": "((User?) -> [CometChatUserOption])? - Sets custom swipe actions", + "add(options:)": "((User?) -> [CometChatUserOption])? - Adds additional swipe actions" + }, + "dataManipulation": { + "add(user:)": "User - Adds a user to the list", + "update(user:)": "User - Updates a user in the list", + "remove(user:)": "User - Removes a user from the list", + "getSelectedUsers()": "[User] - Returns selected users" + } + }, + "events": [ + { + "name": "ccUserBlocked", + "payload": "User", + "description": "Fires when a user is blocked" + }, + { + "name": "ccUserUnblocked", + "payload": "User", + "description": "Fires when a user is unblocked" + } + ], + "sdkListeners": [ + "onUserOnline", + "onUserOffline" + ], + "compositionExample": { + "description": "Users list for starting new conversations", + "components": ["CometChatUsers", "CometChatMessages"], + "flow": "User taps on a user → onItemClick fires → Navigate to CometChatMessages with selected user" + }, + "types": { + "User": { + "uid": "String", + "name": "String", + "avatar": "String?", + "status": "UserStatus", + "role": "String?" + }, + "UserStatus": { + "online": "User is currently online", + "offline": "User is currently offline" + } + } +} +``` + -| Components | Description | -| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| [ListBase](/ui-kit/ios/list-base) | a reusable container component having title, search box, customisable background and a List View | -| [ListItem](/ui-kit/ios/list-item) | a component that renders data obtained from a User object on a Tile having a title, subtitle, leading and trailing view | +| Field | Value | +|-------|-------| +| Component | `CometChatUsers` | +| Package | `CometChatUIKitSwift` | +| Inherits | `UIViewController` | -*** +--- -## Usage +## Where It Fits -### Integration +`CometChatUsers` displays all available users for starting new conversations. It's typically used as a standalone screen or within a tab view controller. -As `CometChatUsers` is a custom **view controller**, it can be launched directly by user actions such as button clicks or other interactions. It's also possible to integrate it into a **tab view controller**. `CometChatUsers` offers several parameters and methods for UI customization. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - - -```swift -let cometChatUsers = CometChatUsers() -let naviVC = UINavigationController(rootViewController: cometChatUsers) -self.present(naviVC, animated: true) +class UsersViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + setupUsers() + } + + private func setupUsers() { + let usersController = CometChatUsers() + + // Handle user selection - start a conversation + usersController.set(onItemClick: { [weak self] user, indexPath in + self?.startConversation(with: user) + }) + + let navController = UINavigationController(rootViewController: usersController) + present(navController, animated: true) + } + + private func startConversation(with user: User) { + let messagesVC = CometChatMessages() + messagesVC.set(user: user) + navigationController?.pushViewController(messagesVC, animated: true) + } +} ``` - - - - -### Actions + + CometChatUsers displaying the user list within a navigation controller hierarchy + -[Actions](/ui-kit/ios/components-overview#actions) dictate how a component functions. They are divided into two types: Predefined and User-defined. You can override either type, allowing you to tailor the behavior of the component to fit your specific needs. +--- -1. ##### set(onItemClick:) +## Minimal Render -`set(OnItemClick:)` is triggered when you click on a ListItem of the users component. This `set(OnItemClick:)` method proves beneficial when a user intends to customize the on-click behavior in CometChatUsers. +```swift lines +import CometChatUIKitSwift - - -```swift -cometChatUsers.set(onItemClick: { user, indexPath in - // Override on item click -}) +let users = CometChatUsers() +let navController = UINavigationController(rootViewController: users) +present(navController, animated: true) ``` - - - - -*** + + CometChatUsers showing the minimal render with default configuration + -2. ##### set(OnItemLongClick:) +--- -`set(OnItemLongClick:)` is triggered when you long press on a ListItem of the users component. This `set(OnItemLongClick:)` method proves beneficial when a user intends to additional functionality on long press on list item in CometChatUsers. +## Filtering - - -```swift -cometChatUsers.set(onItemLongClick: { user, indexPath in - // Override on item click -}) -``` +Use `UsersRequest.UsersRequestBuilder` to filter which users appear in the list. The builder pattern allows chaining multiple filter conditions. - +```swift lines +import CometChatUIKitSwift +import CometChatSDK - +// Create a custom request builder +let usersRequestBuilder = UsersRequest.UsersRequestBuilder(limit: 30) + .friendsOnly(true) -*** +let users = CometChatUsers(usersRequestBuilder: usersRequestBuilder) +``` -##### 3. set(onBack:) +### Filter Recipes -This `set(onBack:)` method becomes valuable when a user needs to override the action triggered upon pressing the back button in CometChatUsers. +| Recipe | Code | +|--------|------| +| Friends only | `.friendsOnly(true)` | +| Online users only | `.set(status: .online)` | +| Search by name | `.set(searchKeyword: "John")` | +| Filter by role | `.set(roles: ["admin", "moderator"])` | +| Filter by tags | `.set(tags: ["premium"])` | +| Hide blocked users | `.hideBlockedUsers(true)` | +| Limit results | `UsersRequestBuilder(limit: 20)` | +| Specific UIDs | `.set(UIDs: ["user1", "user2"])` | - - -```swift -cometChatUsers.set(onBack: { - // Override on back -}) -``` +--- - +## Actions and Events - +### Callback Props -*** +#### onItemClick -##### 4. set(onSelection:) +Fires when a user taps on a user in the list. Use this to start a conversation. -The `set(onSelection:)` only gets trigger when selection mode is set to multiple of single. And this gets trigger on every selection, and returns the list of selected users. +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift +let users = CometChatUsers() -cometChatUsers.set(onSelection: { users in - //Handle action +users.set(onItemClick: { [weak self] user, indexPath in + guard let self = self else { return } + + let messagesVC = CometChatMessages() + messagesVC.set(user: user) + self.navigationController?.pushViewController(messagesVC, animated: true) }) ``` - - - +#### onItemLongClick -*** +Fires when a user long-presses on a user. Use this to show additional options. -##### 5. set(onError:) +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This method proves helpful when a user needs to customize the action taken upon encountering an error in CometChatUsers. +let users = CometChatUsers() - - -```swift -cometChatUsers.set(onError: { error in - // Override on error +users.set(onItemLongClick: { [weak self] user, indexPath in + guard let self = self else { return } + + let alert = UIAlertController(title: user.name, message: nil, preferredStyle: .actionSheet) + + alert.addAction(UIAlertAction(title: "View Profile", style: .default) { _ in + // View profile + }) + + alert.addAction(UIAlertAction(title: "Block User", style: .destructive) { _ in + // Block user + }) + + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) + self.present(alert, animated: true) }) ``` - +#### onBack - +Fires when the back button is pressed. -*** - -##### 6. set(onEmpty:) +```swift lines +import CometChatUIKitSwift -This `set(onEmpty:)` method is triggered when the users list is empty in CometChatUsers. +let users = CometChatUsers() - - -```swift -cometChatUsers.set(onEmpty: { - // Handle empty state +users.set(onBack: { [weak self] in + self?.navigationController?.popViewController(animated: true) }) ``` - +#### onSelection - +Fires when users are selected in selection mode. -*** - -##### 7. setOnLoad +```swift lines +import CometChatUIKitSwift +import CometChatSDK -This set(onLoad:) gets triggered when a user list is fully fetched and going to displayed on the screen, this return the list of users to get displayed on the screen. +let users = CometChatUsers() +users.selectionMode = .multiple - - -```swift -cometChatUsers.set(onLoad: { users in - // Handle loaded users +users.set(onSelection: { [weak self] selectedUsers in + print("Selected \(selectedUsers.count) users") }) ``` - - - +#### onError -*** +Fires when an error occurs while loading users. -### Filters - -**Filters** allow you to customize the data displayed in a list within a Component. You can filter the list based on your specific criteria, allowing for a more customized. Filters can be applied using RequestBuilders of Chat SDK. - -##### 1. UserRequestBuilder - -The [UserRequestBuilder](/sdk/ios/retrieve-users) enables you to filter and customize the user list based on available parameters in UserRequestBuilder. This feature allows you to create more specific and targeted queries when fetching users. The following are the parameters available in [UserRequestBuilder](/sdk/ios/retrieve-users) - -| Methods | Type | Description | -| -------------------- | -------------------- | -------------------------------------------------------------------------------------- | -| **setLimit** | int | sets the number users that can be fetched in a single request, suitable for pagination | -| **setSearchKeyword** | String | used for fetching users matching the passed string | -| **hideBlockedUsers** | bool | used for fetching all those users who are not blocked by the logged in user | -| **friendsOnly** | bool | used for fetching only those users in which logged in user is a member | -| **setRoles** | \[String] | used for fetching users containing the passed tags | -| **setTags** | \[String] | used for fetching users containing the passed tags | -| **withTags** | bool | used to fetch tags data along with the list of users. | -| **setStatus** | CometChat.UserStatus | used for fetching users by their status online or offline | -| **setUIDs** | \[String] | used for fetching users containing the passed users | - -**Example** - -In the example below, we are applying a filter to the UserList based on Friends. +```swift lines +import CometChatUIKitSwift - - -```swift -let usersRequestBuilder = UsersRequest.UsersRequestBuilder(limit: 20).friendsOnly(true) +let users = CometChatUsers() -let usersWithMessages = CometChatUsersWithMessages(usersRequestBuilder: usersRequestBuilder) -let naviVC = UINavigationController(rootViewController: usersWithMessages) -self.present(naviVC, animated: true) +users.set(onError: { error in + print("Error loading users: \(error.errorDescription)") +}) ``` - - - - - +#### onEmpty -##### 2. SearchRequestBuilder +Fires when the user list is empty. -The SearchRequestBuilder uses [UserRequestBuilder](/sdk/ios/retrieve-users) enables you to filter and customize the search list based on available parameters in UserRequestBuilder. This feature allows you to keep uniformity between the displayed UserList and searched UserList. - -**Example** In the example below, we are applying a filter to the UserList based on Search. +```swift lines +import CometChatUIKitSwift - - -```swift -let usersRequestBuilder = UsersRequest.UsersRequestBuilder(limit: 20) -.set(searchKeyword: "**") +let users = CometChatUsers() -let usersWithMessages = CometChatUsers(usersRequestBuilder: usersRequestBuilder) -let naviVC = UINavigationController(rootViewController: usersWithMessages) -self.present(naviVC, animated: true) +users.set(onEmpty: { + print("No users found") +}) ``` - - +#### onLoad +Fires when users are successfully loaded. The callback receives a nested array where each inner array represents a section of users (grouped alphabetically). - - -### Events - -[Events](/ui-kit/ios/components-overview#events) are emitted by a `Component`. By using event you can extend existing functionality. Being global events, they can be applied in Multiple Locations and are capable of being Added or Removed. - -To handle events supported by Users you have to add corresponding listeners by using `CometChatUserEvents` - -| Events | Description | -| ----------------- | --------------------------------------------------------------------- | -| emitOnUserBlock | This will get triggered when the logged in user blocks another user | -| emitOnUserUnblock | This will get triggered when the logged in user unblocks another user | +```swift lines +import CometChatUIKitSwift +import CometChatSDK - - -```swift -///pass the [User] object of the user which has been blocked by the logged in user - CometChatUserEvents.emitOnUserBlock(user: User) +let users = CometChatUsers() -///pass the [User] object of the user which has been unblocked by the logged in user - CometChatUserEvents.emitOnUserUnblock(user: User) +users.set(onLoad: { userSections in + let totalUsers = userSections.flatMap { $0 }.count + print("Loaded \(totalUsers) users across \(userSections.count) sections") +}) ``` - - +### Actions Reference +| Method | Description | Example | +|--------|-------------|---------| +| `set(onItemClick:)` | Triggered when a user is tapped | Start conversation | +| `set(onItemLongClick:)` | Triggered on long press | Show options menu | +| `set(onBack:)` | Triggered when back button is pressed | Custom navigation | +| `set(onSelection:)` | Triggered in selection mode | Multi-select users | +| `set(onError:)` | Triggered when an error occurs | Show error alert | +| `set(onEmpty:)` | Triggered when list is empty | Show empty state | +| `set(onLoad:)` | Triggered when users load | Analytics tracking | - +### Global UI Events -**Usage** +| Event | Fires when | Payload | +|-------|------------|---------| +| `ccUserBlocked` | A user is blocked | `User` | +| `ccUserUnblocked` | A user is unblocked | `User` | -```swift Swift -// View controller from your project where you want to listen events. -public class ViewController: UIViewController { +```swift lines +import CometChatUIKitSwift +import CometChatSDK - public override func viewDidLoad() { +class MyViewController: UIViewController, CometChatUserEventListener { + + override func viewDidLoad() { super.viewDidLoad() - - // Subscribing for the listener to listen events from user module - CometChatUserEvents.addListener("UNIQUE_ID", self as CometChatUserEventListener) + CometChatUserEvents.addListener("my-listener", self) } - - public override func viewWillDisappear(_ animated: Bool) { - // Uncubscribing for the listener to listen events from user module - CometChatUserEvents.removeListener("LISTENER_ID_USED_FOR_ADDING_THIS_LISTENER") + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + CometChatUserEvents.removeListener("my-listener") } -} - - // Listener events from user module -extension ViewController: CometChatUserEventListener { - + func onUserBlock(user: User) { - // Do Stuff + print("User blocked: \(user.name ?? "")") } - + func onUserUnblock(user: User) { - // Do Stuff + print("User unblocked: \(user.name ?? "")") } } ``` -## Customization - -To fit your app's design requirements, you can customize the appearance of the users component. We provide exposed methods that allow you to modify the experience and behavior according to your specific needs. - -### Style - -Using Style you can customize the look and feel of the component in your app, These parameters typically control elements such as the color, size, shape, and fonts used within the component. +### SDK Events (Real-Time, Automatic) -##### 1. Users Style +| SDK Listener | Internal behavior | +|--------------|-------------------| +| `onUserOnline` | Updates status indicator to online | +| `onUserOffline` | Updates status indicator to offline | -You can set the `UsersStyle` to the Users Component to customize the styling. - -**Global level styling** - - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) - -CometChatUsers.style.titleColor = UIColor(hex: "#F76808") -CometChatUsers.style.titleFont = UIFont(name: "Times-New-Roman", size: 34) -CometChatUsers.avatarStyle = customAvatarStyle -``` +--- - +## Custom View Slots - +| Slot | Signature | Replaces | +|------|-----------|----------| +| `listItemView` | `(User) -> UIView` | Entire user row | +| `leadingView` | `(User) -> UIView` | Avatar / left section | +| `titleView` | `(User?) -> UIView` | Name / title text | +| `subtitleView` | `(User?) -> UIView` | Status / subtitle text | +| `trailingView` | `(User?) -> UIView` | Right side content | +| `emptyStateView` | `() -> UIView` | Empty state display | +| `errorStateView` | `() -> UIView` | Error state display | +| `loadingStateView` | `() -> UIView` | Loading state display | -**Instance level styling** +### listItemView - - -```swift -let customAvatarStyle = AvatarStyle() -customAvatarStyle.backgroundColor = UIColor(hex: "#FBAA75") -customAvatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) - -let userStyle = UsersStyle() -userStyle.titleColor = UIColor(hex: "#F76808") -userStyle.titleFont = UIFont(name: "Times-New-Roman", size: 34) - -let customUser = CometChatUsers() -customUser.style = userStyle -customUser.avatarStyle = customAvatarStyle -``` +Replace the entire user row with a custom design. - - - - - - - +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -List of properties exposed by MessageListStyle - -| **Property** | **Description** | **Code** | -| ----------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -| **List Item Selected Image** | Image shown when a list item is selected. | `CometChatUsers.style.listItemSelectedImage = UIImage()` | -| **List Item Deselected Image** | Image shown when a list item is deselected. | `CometChatUsers.style.listItemDeSelectedImage = UIImage()` | -| **Search Icon Tint Color** | Tint color for the search icon in the search bar. | `CometChatUsers.style.searchIconTintColor = UIColor()` | -| **Search Bar Style** | Style of the search bar (e.g., default, prominent). | `CometChatUsers.style.searchBarStyle = .default` | -| **Search Tint Color** | Tint color for the search bar elements. | `CometChatUsers.style.searchTintColor = UIColor?` | -| **Search Bar Tint Color** | Background color for the search bar (excluding text input). | `CometChatUsers.style.searchBarTintColor = UIColor?` | -| **Placeholder Text Color** | Color of the placeholder text in the search bar. | `CometChatUsers.style.searchBarPlaceholderTextColor = UIColor?` | -| **Placeholder Text Font** | Font of the placeholder text in the search bar. | `CometChatUsers.style.searchBarPlaceholderTextFont = UIFont?` | -| **Search Bar Text Color** | Color of the entered text in the search bar. | `CometChatUsers.style.searchBarTextColor = UIColor?` | -| **Search Bar Text Font** | Font of the entered text in the search bar. | `CometChatUsers.style.searchBarTextFont = UIFont?` | -| **Search Bar Background Color** | Background color of the search bar’s text input area. | `CometChatUsers.style.searchBarBackgroundColor = UIColor?` | -| **Cancel Icon Tint Color** | Tint color for the cancel button in the search bar. | `CometChatUsers.style.searchBarCancelIconTintColor = UIColor?` | -| **Cross Icon Tint Color** | Tint color for the clear (cross) button in the search bar. | `CometChatUsers.style.searchBarCrossIconTintColor = UIColor?` | -| **Background Color** | Background color for the entire screen or view. | `.backgroundColor = CometChatTheme.backgroundColor01` | -| **Border Width** | Border width for the search bar or container. | `CometChatUsers.style.borderWidth = 0` | -| **Border Color** | Color of the border, default is clear. | `CometChatUsers.style.borderColor = .clear` | -| **Corner Radius** | Corner radius for search bar or other elements. | `CometChatUsers.style.cornerRadius = CometChatCornerStyle.init(cornerRadius: 0)` | -| **Title Text Color** | Text color for title elements within the list or navigation bar. | `CometChatUsers.style.titleColor = CometChatTheme.textColorPrimary` | -| **Title Font** | Font for title text. | `CometChatUsers.style.titleFont = CometChatTypography.Heading4.medium` | -| **Large Title Text Color** | Text color for large titles. | `CometChatUsers.style.largeTitleColor = CometChatTheme.textColorPrimary` | -| **Large Title Font** | Font for large titles. | `CometChatUsers.style.largeTitleFont = UIFont?` | -| **Navigation Bar Tint Color** | Tint color for the navigation bar background. | `CometChatUsers.style.navigationBarTintColor = CometChatTheme.backgroundColor01` | -| **Navigation Bar Items Tint Color** | Tint color for navigation bar items (buttons, icons). | `CometChatUsers.style.navigationBarItemsTintColor = CometChatTheme.iconColorHighlight` | -| **Error Title Font** | Font for the error title displayed in UI. | `CometChatUsers.style.errorTitleTextFont = CometChatTypography.Heading3.bold` | -| **Error Title Text Color** | Text color for the error title. | `CometChatUsers.style.errorTitleTextColor = CometChatTheme.textColorPrimary` | -| **Error Subtitle Font** | Font for the subtitle of error messages. | `CometChatUsers.style.errorSubTitleFont = CometChatTypography.Body.regular` | -| **Error Subtitle Text Color** | Text color for the subtitle of error messages. | `CometChatUsers.style.errorSubTitleTextColor = CometChatTheme.textColorSecondary` | -| **Retry Button Text Color** | Text color for the retry button in error states. | `CometChatUsers.style.retryButtonTextColor = CometChatTheme.buttonTextColor` | -| **Retry Button Text Font** | Font for the retry button text. | `CometChatUsers.style.retryButtonTextFont = CometChatTypography.Button.medium` | -| **Retry Button Background Color** | Background color for the retry button. | `CometChatUsers.style.retryButtonBackgroundColor = CometChatTheme.primaryColor` | -| **Retry Button Border Color** | Border color for the retry button. | `CometChatUsers.style.retryButtonBorderColor = .clear` | -| **Retry Button Border Width** | Border width for the retry button. | `CometChatUsers.style.retryButtonBorderWidth = 0` | -| **Retry Button Corner Radius** | Corner radius for the retry button. | `CometChatUsers.style.retryButtonCornerRadius = CometChatCornerStyle?` | -| **Empty State Title Font** | Font for the empty state title (when no users/items are present). | `CometChatUsers.style.emptyTitleTextFont = CometChatTypography.Heading3.bold` | -| **Empty State Title Color** | Text color for the empty state title. | `CometChatUsers.style.emptyTitleTextColor = CometChatTheme.textColorPrimary` | -| **Empty Subtitle Font** | Font for the subtitle in the empty state. | `CometChatUsers.style.emptySubTitleFont = CometChatTypography.Body.regular` | -| **Empty Subtitle Text Color** | Text color for the subtitle in the empty state. | `CometChatUsers.style.emptySubTitleTextColor = CometChatTheme.textColorSecondary` | -| **Table View Separator Color** | Color for the table view separator. | `CometChatUsers.style.tableViewSeparator = .clear` | -| **List Item Title Text Color** | Text color for list item titles. | `CometChatUsers.style.listItemTitleTextColor = CometChatTheme.textColorPrimary` | -| **List Item Title Font** | Font for list item titles. | `CometChatUsers.style.listItemTitleFont = CometChatTypography.Heading4.medium` | -| **List Item Subtitle Text Color** | Text color for list item subtitles. | `CometChatUsers.style.listItemSubTitleTextColor = CometChatTheme.textColorSecondary` | -| **List Item Subtitle Font** | Font for list item subtitles. | `CometChatUsers.style.listItemSubTitleFont = CometChatTypography.Body.regular` | -| **List Item Background** | Background color for individual list items. | `CometChatUsers.style.listItemBackground = .clear` | -| **List Item Border Width** | Border width for individual list items. | `CometChatUsers.style.listItemBorderWidth = 0` | -| **List Item Border Color** | Border color for individual list items. | `CometChatUsers.style.listItemBorderColor = CometChatTheme.borderColorLight` | -| **List Item Corner Radius** | Corner radius for list items. | `CometChatUsers.style.listItemCornerRadius = CometChatCornerStyle.init(cornerRadius: 0)` | -| **Selection Image Tint Color** | Tint color for selection indicator in list items. | `CometChatUsers.style.listItemSelectionImageTint = CometChatTheme.iconColorHighlight` | -| **Selected Background Color** | Background color for selected list items. | `CometChatUsers.style.listItemSelectedBackground = .clear` | -| **Deselected Image Tint Color** | Tint color for the deselected state image. | `CometChatUsers.style.listItemDeSelectedImageTint = CometChatTheme.borderColorDefault` | -| **Header Title Color** | Text color for section header titles in the list. | `CometChatUsers.style.headerTitleColor = CometChatTheme.textColorHighlight` | -| **Header Title Font** | Font for section header titles. | `CometChatUsers.style.headerTitleFont = CometChatTypography.Heading4.medium` | - -*** - -### Functionality - -These are a set of small functional customizations that allow you to fine-tune the overall experience of the component. With these, you can change text, set custom icons, and toggle the visibility of UI elements. - -Below is a list of customizations along with corresponding code snippets - -| Method | Description | Code | -| -------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- | -| set(userRequestBuilder:) | Sets a custom request builder for fetching users. | `.set(userRequestBuilder: UsersRequest.UsersRequestBuilder())` | -| set(searchRequestBuilder:) | Sets a custom request builder for searching users. | `.set(searchRequestBuilder: UsersRequest.UsersRequestBuilder())` | -| set(searchKeyword:) | Sets a search keyword for filtering users. | `.set(searchKeyword: "John")` | -| hideErrorView | Hides the error state view. | `hideErrorView = true` | -| hideNavigationBar | Hides or shows the navigation bar. | `hideNavigationBar = true` | -| hideSearch | Hides the search bar. | `hideSearch = true` | -| hideBackButton | Hides the back button. | `hideBackButton = true` | -| hideLoadingState | Hides the loading state indicator. | `hideLoadingState = true` | -| hideUserStatus | Hides the online/offline status of users. | `hideUserStatus = true` | -| hideSectionHeader | Hides the section header for table view indicating initials of users. | `hideSectionHeader = true` | - -*** - -### Advance - -For advanced-level customization, you can set custom views to the component. This lets you tailor each aspect of the component to fit your exact needs and application aesthetics. You can create and define your views, layouts, and UI elements and then incorporate those into the component. - -*** - -#### SetOptions - -You can define custom options for each user using .set(options:). This method allows you to return an array of CometChatUserOption based on the user object. - - - -```swift -cometChatUsers.set(options: { user in - return [CometChatUserOptions] -}) -``` - - - - - -*** - -#### AddOptions - -You can dynamically add options to users using .add(options:). This method lets you return additional CometChatUserOption elements. - - - -```swift -cometChatUsers.add(options: { user in - return [ArchiveOption()] -}) -``` - - - - - -*** - -#### SetListItemView - -With this function, you can assign a custom ListItem to the users Component. +let users = CometChatUsers() - - -```swift -let cometChatUser = CometChatUsers() -cometChatUser.set(listItemView: { user in - //Perform Your Actions +users.set(listItemView: { user in + let customView = UIView() + customView.backgroundColor = UIColor.systemBackground + + let avatar = CometChatAvatar(image: UIImage()) + avatar.setAvatar(avatarUrl: user.avatar, with: user.name ?? "") + + let nameLabel = UILabel() + nameLabel.text = user.name + nameLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) + + let statusLabel = UILabel() + statusLabel.text = user.status == .online ? "🟢 Online" : "⚫ Offline" + statusLabel.font = UIFont.systemFont(ofSize: 12) + statusLabel.textColor = UIColor.secondaryLabel + + customView.addSubview(avatar) + customView.addSubview(nameLabel) + customView.addSubview(statusLabel) + + return customView }) ``` - - - - - - - - -You can indeed create a custom listitem UIView file named `Custom_User_ListItem_View` for more complex or unique list items. - -Afterwards, seamlessly integrate this `Custom_User_ListItem_View` UIView file into the `.setListItemView` method within **CometChatUsers()**. - -You can create a `CustomListItemView` as a custom `UIView`. Which we will inflate in `setListItemView()` +### leadingView -```swift swift +Customize the leading view (avatar area) of a user cell. +```swift lines import UIKit import CometChatUIKitSwift +import CometChatSDK -class CustomListItem: UIView { - // Initialize UI components - private var profileImageView: CometChatAvatar = { - let imageView = CometChatAvatar(image: UIImage()) - imageView.translatesAutoresizingMaskIntoConstraints = false // Important for manual layout - return imageView - }() - - private var nameLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false // Important for manual layout - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - setupUI() - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupUI() { - addSubview(profileImageView) - addSubview(nameLabel) +let users = CometChatUsers() - NSLayoutConstraint.activate([ - // Profile image constraints - profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), - profileImageView.centerYAnchor.constraint(equalTo: centerYAnchor), - profileImageView.widthAnchor.constraint(equalToConstant: 40), - profileImageView.heightAnchor.constraint(equalToConstant: 40), - - nameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 8), - nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), - nameLabel.centerYAnchor.constraint(equalTo: centerYAnchor) - ]) - } - - func set(user: User) { - var avatarURL: String? - if let group = conversation.conversationWith as? Group { - nameLabel.text = group.name - avatarURL = group.icon - } - - if let user = conversation.conversationWith as? User { - nameLabel.text = user.name - avatarURL = user.avatar - } - - - - - self.profileImageView.setAvatar(avatarUrl: avatarURL, with: nameLabel.text) - } -} -``` - -*** - -#### SetLeadingView - -You can modify the leading view of a user cell using .set(leadingView:). - - - -```swift -cometChatUsers.set(leadingView: { user in - let view = CustomLeadingView() - return view -}) +users.set(leadingView: { user in + let view = CustomLeadingView(image: UIImage(named: "avatar")) + return view +}) ``` - - - - -Demonstration - - + CometChatUsers with custom leadingView showing user avatars with a star badge overlay -You can create a `CustomLeadingView` as a custom `UIView`. Which we will inflate in `setLeadingView()` +You can create a `CustomLeadingView` as a custom `UIView`: - - -```swift +```swift lines import UIKit class CustomLeadingView: UIView { + // MARK: - UI Components private let imageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFill @@ -623,6 +505,7 @@ class CustomLeadingView: UIView { return view }() + // MARK: - Initialization init(image: UIImage?) { super.init(frame: .zero) imageView.image = image @@ -652,44 +535,35 @@ class CustomLeadingView: UIView { } ``` - - - +### titleView -*** +Customize the title view of a user cell. -#### SetTitleView +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -You can customize the title view of a user cell using .set(titleView:). +let users = CometChatUsers() - - -```swift -cometChatUsers.set(titleView: { user in - let view = CustomTitleView() +users.set(titleView: { user in + let view = CustomTitleView(name: user.name ?? "", role: "Teacher") return view -}) +}) ``` - - - - -Demonstration - - + CometChatUsers with custom titleView showing user names with a green Teacher badge -You can create a `CustomTitleView` as a custom `UIView`. Which we will inflate in `setTitleView()` +You can create a `CustomTitleView` as a custom `UIView`: - - -```swift +```swift lines import UIKit class CustomTitleView: UIView { + // MARK: - UI Components private let nameLabel: UILabel = { let label = UILabel() label.font = UIFont.boldSystemFont(ofSize: 18) @@ -709,6 +583,7 @@ class CustomTitleView: UIView { return label }() + // MARK: - Initialization init(name: String, role: String) { super.init(frame: .zero) nameLabel.text = name @@ -734,48 +609,79 @@ class CustomTitleView: UIView { fatalError("init(coder:) has not been implemented") } } - - ``` - +### subtitleView - +Customize the subtitle area below the user name. -*** +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK -#### SetTrailView +let users = CometChatUsers() + +users.set(subtitleView: { user in + let view = CustomSubtitleView(lastActiveDate: "2 hours ago") + return view +}) +``` -You can modify the trailing view of a user cell using .set(trailView:). + + CometChatUsers with custom subtitleView showing last active timestamp below user names + - - -```swift -cometChatUsers.set(trailView: { user in - let view = CustomTrailView() - return view -}) +You can create a `CustomSubtitleView` as a custom `UIView`: + +```swift lines +import UIKit + +class CustomSubtitleView: UILabel { + + init(lastActiveDate: String) { + super.init(frame: .zero) + self.text = "Last Active at: \(lastActiveDate)" + self.textColor = UIColor.gray + self.font = UIFont.systemFont(ofSize: 14) + self.numberOfLines = 1 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} ``` - +### trailingView + +Customize the trailing view (right side) of a user cell. + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK - +let users = CometChatUsers() -Demonstration +users.set(trailView: { user in + let view = CustomTrailView() + return view +}) +``` - + CometChatUsers with custom trailingView showing a purple PRO badge with star icon -You can create a `CustomTrailView` as a custom `UIView`. Which we will inflate in `setTrailView()` +You can create a `CustomTrailView` as a custom `UIView`: - - -```swift +```swift lines import UIKit class CustomTrailView: UIView { + // MARK: - UI Components private let badgeView: UIView = { let view = UIView() view.backgroundColor = .purple @@ -800,6 +706,7 @@ class CustomTrailView: UIView { return label }() + // MARK: - Initialization init() { super.init(frame: .zero) @@ -828,124 +735,696 @@ class CustomTrailView: UIView { fatalError("init(coder:) has not been implemented") } } +``` - +### loadingStateView + +Customize the loading state view displayed while data is being fetched. + +```swift lines +import UIKit +import CometChatUIKitSwift + +let users = CometChatUsers() + +let loadingIndicator = UIActivityIndicatorView(style: .medium) +loadingIndicator.startAnimating() +users.set(loadingView: loadingIndicator) ``` - +### errorStateView - +Customize the error state view displayed when an error occurs. -*** +```swift lines +import UIKit +import CometChatUIKitSwift + +let users = CometChatUsers() + +let errorLabel = UILabel() +errorLabel.text = "Something went wrong!" +errorLabel.textColor = .red +users.set(errorView: errorLabel) +``` -#### SetSubTitleView +### emptyStateView -You can customize the subtitle view for each users item to meet your requirements +Customize the empty state view displayed when no users are available. + +```swift lines +import UIKit +import CometChatUIKitSwift + +let users = CometChatUsers() + +let emptyLabel = UILabel() +emptyLabel.text = "No users found" +emptyLabel.textColor = .gray +emptyLabel.textAlignment = .center +users.set(emptyView: emptyLabel) +``` + +--- + +## Methods + +### Swipe Action Methods + +#### set(options:) + +Sets custom swipe actions for user list items, replacing the default options. These options appear when the user swipes on a user cell. + +```swift lines +@discardableResult +public func set(options: ((_ user: User?) -> [CometChatUserOption])?) -> Self +``` - - -```swift -let cometChatUser = CometChatUsers() -cometChatUser.set(subtitleView: { user in - let view = CustomSubtitleView() - return view +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((User?) -> [CometChatUserOption])?` | Closure that returns an array of swipe action options for a user | + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() + +users.set(options: { user in + var options = [CometChatUserOption]() + + // Add block option + let blockOption = CometChatUserOption( + id: "block", + title: "Block", + icon: UIImage(systemName: "hand.raised"), + backgroundColor: .systemRed + ) { selectedUser in + // Handle block action + print("Block user: \(selectedUser?.name ?? "")") + } + options.append(blockOption) + + // Add message option + let messageOption = CometChatUserOption( + id: "message", + title: "Message", + icon: UIImage(systemName: "message"), + backgroundColor: .systemBlue + ) { selectedUser in + // Handle message action + print("Message user: \(selectedUser?.name ?? "")") + } + options.append(messageOption) + + return options +}) +``` + +#### add(options:) + +Adds additional swipe actions to the existing default options. + +```swift lines +@discardableResult +public func add(options: ((_ user: User?) -> [CometChatUserOption])?) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `options` | `((User?) -> [CometChatUserOption])?` | Closure that returns additional swipe action options to append | + +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() + +users.add(options: { user in + var options = [CometChatUserOption]() + + // Add favorite option + let favoriteOption = CometChatUserOption( + id: "favorite", + title: "Favorite", + icon: UIImage(systemName: "star.fill"), + backgroundColor: .systemOrange + ) { selectedUser in + print("Favorite user: \(selectedUser?.name ?? "")") + } + options.append(favoriteOption) + + return options }) ``` - +### Data Manipulation Methods - +#### add(user:) -**Example** +Adds a new user to the user list. + +```swift lines +@discardableResult +public func add(user: User) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `user` | `User` | The user to add to the list | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK -Demonstration +let users = CometChatUsers() + +// Add a user programmatically +let newUser = User(uid: "user-123", name: "John Doe") +users.add(user: newUser) +``` + +#### update(user:) + +Updates an existing user in the list. + +```swift lines +@discardableResult +public func update(user: User) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `user` | `User` | The user with updated information | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() + +// Update a user's information +if var existingUser = userToUpdate { + existingUser.name = "Updated Name" + users.update(user: existingUser) +} +``` + +#### remove(user:) + +Removes a user from the list. + +```swift lines +@discardableResult +public func remove(user: User) -> Self +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `user` | `User` | The user to remove from the list | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() + +// Remove a user from the UI +users.remove(user: userToRemove) +``` + +#### getSelectedUsers() + +Returns an array of currently selected users when in selection mode. + +```swift lines +public func getSelectedUsers() -> [User] +``` + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() +users.selectionMode = .multiple + +// Get all selected users +let selectedUsers = users.getSelectedUsers() +print("Selected \(selectedUsers.count) users") + +for user in selectedUsers { + print("User: \(user.name ?? "")") +} +``` + +--- + +## Custom ListItem + +For more complex or unique list items, you can create a custom `UIView` file named `CustomListItem` and integrate it into the `set(listItemView:)` method. - + CometChatUsers with custom listItemView showing a simplified user row with avatar and name -You can seamlessly integrate this `CustomSubtitleView` UIView file into the `.set(subtitleView:)` method within CometChatUsers. +```swift lines +import UIKit +import CometChatUIKitSwift +import CometChatSDK + +class CustomListItem: UIView { + + // MARK: - UI Components + private var profileImageView: CometChatAvatar = { + let imageView = CometChatAvatar(image: UIImage()) + imageView.translatesAutoresizingMaskIntoConstraints = false + return imageView + }() + + private var nameLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + // MARK: - Initialization + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } - - -```swift + // MARK: - Setup + private func setupUI() { + addSubview(profileImageView) + addSubview(nameLabel) + + NSLayoutConstraint.activate([ + // Profile image constraints + profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), + profileImageView.centerYAnchor.constraint(equalTo: centerYAnchor), + profileImageView.widthAnchor.constraint(equalToConstant: 40), + profileImageView.heightAnchor.constraint(equalToConstant: 40), + + // Name label constraints + nameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 8), + nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), + nameLabel.centerYAnchor.constraint(equalTo: centerYAnchor) + ]) + } + + // MARK: - Configuration + func set(user: User) { + nameLabel.text = user.name + profileImageView.setAvatar(avatarUrl: user.avatar, with: user.name) + } +} +``` + +Usage: + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() + +users.set(listItemView: { user in + let customItem = CustomListItem() + customItem.set(user: user) + return customItem +}) +``` + +--- + +## Styling + +### Style Hierarchy + +1. Global styles (`CometChatUsers.style`) apply to all instances +2. Instance styles override global for specific instances + +### Global Level Styling + +```swift lines import UIKit +import CometChatUIKitSwift -class CustomSubtitleView: UILabel { +// Apply global styles that affect all CometChatUsers instances +CometChatUsers.style.backgroundColor = UIColor.systemBackground +CometChatUsers.style.titleColor = UIColor.label +CometChatUsers.style.titleFont = UIFont.systemFont(ofSize: 34, weight: .bold) +CometChatUsers.style.listItemTitleTextColor = UIColor.label +CometChatUsers.style.listItemSubTitleTextColor = UIColor.secondaryLabel + +// Custom avatar style +let avatarStyle = AvatarStyle() +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 20) +CometChatUsers.avatarStyle = avatarStyle +``` + +### Instance Level Styling + +```swift lines +import UIKit +import CometChatUIKitSwift + +// Create a custom style for a specific instance +var customStyle = UsersStyle() +customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0) +customStyle.titleColor = UIColor.darkGray +customStyle.listItemBackground = UIColor.white + +let users = CometChatUsers() +users.style = customStyle +``` + + + CometChatUsers with custom styling showing modified background colors and text appearance + + +### Key Style Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `backgroundColor` | `UIColor` | `CometChatTheme.backgroundColor01` | Background color | +| `titleColor` | `UIColor` | `CometChatTheme.textColorPrimary` | Navigation title color | +| `titleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Navigation title font | +| `listItemTitleTextColor` | `UIColor` | `CometChatTheme.textColorPrimary` | User name color | +| `listItemTitleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | User name font | +| `listItemSubTitleTextColor` | `UIColor` | `CometChatTheme.textColorSecondary` | Status text color | +| `listItemSubTitleFont` | `UIFont` | `CometChatTypography.Body.regular` | Status text font | +| `listItemBackground` | `UIColor` | `.clear` | List item background | +| `searchBarBackgroundColor` | `UIColor?` | `nil` | Search bar background | +| `searchBarTextColor` | `UIColor?` | `nil` | Search bar text color | +| `headerTitleColor` | `UIColor` | `CometChatTheme.textColorHighlight` | Section header color | +| `headerTitleFont` | `UIFont` | `CometChatTypography.Heading4.medium` | Section header font | + +### Customization Matrix + +| What to change | Where | Property/API | Example | +|----------------|-------|--------------|---------| +| Background color | Style | `backgroundColor` | `UIColor.systemBackground` | +| Title appearance | Style | `titleColor`, `titleFont` | Custom colors and fonts | +| List item look | Style | `listItemBackground` | `UIColor.white` | +| Avatar appearance | Style | `avatarStyle` | `AvatarStyle()` with custom radius | +| Search bar | Style | `searchBarBackgroundColor` | Custom background | +| Hide search | Property | `hideSearch` | `users.hideSearch = true` | +| Hide status | Property | `hideUserStatus` | `users.hideUserStatus = true` | +| Custom row | View Slot | `set(listItemView:)` | See Custom View Slots | + +--- + +## Props + +All props are optional. Sorted alphabetically. + +### avatarStyle + +Customizes the appearance of avatars in user list items. + +| | | +|---|---| +| Type | `AvatarStyle` | +| Default | `AvatarStyle()` | + +```swift lines +import CometChatUIKitSwift + +let users = CometChatUsers() + +let avatarStyle = AvatarStyle() +avatarStyle.backgroundColor = UIColor.systemBlue +avatarStyle.cornerRadius = CometChatCornerStyle(cornerRadius: 8) +avatarStyle.borderWidth = 1 +avatarStyle.borderColor = UIColor.systemGray4 + +users.set(avatarStyle: avatarStyle) +``` + +### hideBackButton + +Hides the back button in the navigation bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideErrorView + +Hides the error state view. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideLoadingState + +Hides the loading state indicator. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideNavigationBar + +Hides the entire navigation bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideSearch + +Hides the search bar. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideSectionHeader + +Hides the alphabetical section headers. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### hideUserStatus + +Hides online/offline status indicators. + +| | | +|---|---| +| Type | `Bool` | +| Default | `false` | + +### onSelectedItemProceed + +Callback triggered when the user confirms their selection in selection mode. Use this to handle the selected users. + +| | | +|---|---| +| Type | `(([User]) -> Void)?` | +| Default | `nil` | + +```swift lines +import CometChatUIKitSwift +import CometChatSDK + +let users = CometChatUsers() +users.selectionMode = .multiple +users.selectionLimit = 5 + +users.onSelectedItemProceed = { selectedUsers in + print("Proceeding with \(selectedUsers.count) users") - init(lastActiveDate: String) { - super.init(frame: .zero) - self.text = "Last Active at: \(lastActiveDate)" - self.textColor = UIColor.gray - self.font = UIFont.systemFont(ofSize: 14) - self.numberOfLines = 1 + // Process the selected users + for user in selectedUsers { + print("User: \(user.name ?? "")") } +} +``` + +### searchRequestBuilder + +Custom request builder for search functionality. + +| | | +|---|---| +| Type | `UsersRequest.UsersRequestBuilder?` | +| Default | `nil` | + +### selectedCellCount + +Returns the count of currently selected users in selection mode. + +| | | +|---|---| +| Type | `Int` | +| Default | `0` | + +### selectionLimit + +Sets the maximum number of users that can be selected in selection mode. When the limit is reached, further selections are disabled. + +| | | +|---|---| +| Type | `Int` | +| Default | `0` (unlimited) | + +```swift lines +import CometChatUIKitSwift + +let users = CometChatUsers() +users.selectionMode = .multiple + +// Limit selection to 5 users +users.selectionLimit = 5 + +// Handle selection confirmation +users.onSelectedItemProceed = { selectedUsers in + print("Selected \(selectedUsers.count) users") - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + // Process the selected users + for user in selectedUsers { + print("User: \(user.name ?? "")") } } ``` - +### selectionMode + +Sets the selection mode for multi-select functionality. - +| | | +|---|---| +| Type | `SelectionMode` | +| Default | `.none` | -*** +### statusIndicatorStyle + +Customizes the appearance of online/offline status indicators. + +| | | +|---|---| +| Type | `StatusIndicatorStyle` | +| Default | `StatusIndicatorStyle()` | + +```swift lines +import CometChatUIKitSwift -#### SetLoadingView +let users = CometChatUsers() -You can set a custom loading view using .set(loadingView:). This method accepts a UIView to display while data is being fetched. +let statusIndicatorStyle = StatusIndicatorStyle() +statusIndicatorStyle.backgroundColor = UIColor.systemGreen +statusIndicatorStyle.borderWidth = 2 +statusIndicatorStyle.borderColor = UIColor.white - - -```swift -let loadingIndicator = UIActivityIndicatorView(style: .medium) -loadingIndicator.startAnimating() -cometChatUsers.set(loadingView: loadingIndicator) +users.set(statusIndicatorStyle: statusIndicatorStyle) ``` - +### usersRequestBuilder - +Custom request builder for filtering users. + +| | | +|---|---| +| Type | `UsersRequest.UsersRequestBuilder?` | +| Default | `nil` | + +--- + +## Events + +| Event | Payload | Fires when | +|-------|---------|------------| +| `ccUserBlocked` | `User` | A user is blocked | +| `ccUserUnblocked` | `User` | A user is unblocked | + +--- -*** +## Common Patterns -#### SetErrorView +### Friends-only list -You can customize the error view using .set(errorView:). This method accepts a UIView that appears when an error occurs. +```swift lines +let friendsBuilder = UsersRequest.UsersRequestBuilder(limit: 30) + .friendsOnly(true) - - -```swift -let errorLabel = UILabel() -errorLabel.text = "Something went wrong!" -errorLabel.textColor = .red -cometChatUsers.set(errorView: errorLabel) +let users = CometChatUsers() +users.set(usersRequestBuilder: friendsBuilder) ``` - +### Online users only - +```swift lines +let onlineBuilder = UsersRequest.UsersRequestBuilder(limit: 30) + .set(status: .online) -*** +let users = CometChatUsers() +users.set(usersRequestBuilder: onlineBuilder) +``` + +### Custom empty state with CTA + +```swift lines +let users = CometChatUsers() + +users.set(emptyStateView: { + let emptyView = UIView() + + let label = UILabel() + label.text = "No users found" + label.textAlignment = .center + label.textColor = .secondaryLabel + + let button = UIButton(type: .system) + button.setTitle("Invite friends", for: .normal) + + // Add subviews and constraints... + return emptyView +}) +``` -#### SetEmptyView +### Hide all chrome — minimal list + +```swift lines +let users = CometChatUsers() +users.hideSearch = true +users.hideUserStatus = true +users.hideSectionHeader = true +``` -You can customize the empty state view using .set(emptyView:). This method accepts a UIView that appears when no user are available. +### Multi-select users - - -```swift -let emptyLabel = UILabel() -emptyLabel.text = "No users found" -emptyLabel.textColor = .gray -emptyLabel.textAlignment = .center -cometChatUsers.set(emptyView: emptyLabel) +```swift lines +let users = CometChatUsers() +users.selectionMode = .multiple + +users.set(onSelection: { selectedUsers in + print("Selected \(selectedUsers.count) users") + // Create group with selected users, etc. +}) ``` - +--- - +## Related Components -*** +- [Messages](/ui-kit/ios/messages) - Display messages with a user +- [Conversations](/ui-kit/ios/conversations) - List all conversations +- [Groups](/ui-kit/ios/groups) - List all groups +- [Users With Messages](/ui-kit/ios/users-with-messages) - Combined users and messages view diff --git a/ui-kit/react/core-features.mdx b/ui-kit/react/core-features.mdx index 8af49af9c..529cfe2b2 100644 --- a/ui-kit/react/core-features.mdx +++ b/ui-kit/react/core-features.mdx @@ -210,6 +210,7 @@ Conversation and Advanced Search is a powerful feature provided by CometChat tha | [Conversations](/ui-kit/react/conversations) | [Conversations](/ui-kit/react/conversations) displays the search input. | See the [Groups](/ui-kit/react/groups) component page for details. + --- ## Next Steps