From 16f8baf6294bae0d865847c6c385fa14a0f4ba33 Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Tue, 14 Nov 2023 17:20:31 +0100 Subject: [PATCH 1/6] Testing new docs structure --- docusaurus/sidebars-ios.json | 208 ++++++++++++++++------------------- 1 file changed, 96 insertions(+), 112 deletions(-) diff --git a/docusaurus/sidebars-ios.json b/docusaurus/sidebars-ios.json index 7b38ab0f3d6..52efe917710 100644 --- a/docusaurus/sidebars-ios.json +++ b/docusaurus/sidebars-ios.json @@ -8,65 +8,81 @@ ] }, { - "UIKit": [ - "uikit/uikit-overview", - "uikit/getting-started", + "Core Concepts": [ + "client/llc-client-overview", + "client/offline-support", + "client/extra-data", + "client/importance-of-synchronize", + "client/custom-cdn", { - "Core Principles": [ - "uikit/localization", - "uikit/theming", - "uikit/custom-components", - "uikit/data-formatting" + "Audio Support": [ + "client/audio-support/audio-recording-and-playback-overview", + "client/audio-support/audio-recording", + "client/audio-support/audio-analysis", + "client/audio-support/audio-playback" ] }, { - "Core Components": [ - "uikit/components/channel-list", - "uikit/components/message-list", - "uikit/components/channel", - "uikit/components/thread", - "uikit/components/message", - "uikit/components/message-composer", - "uikit/components/voice-recording" + "Controllers and Delegates": [ + "client/controllers/controllers-overview", + "client/controllers/connection", + "client/controllers/channels", + "client/controllers/users", + "client/controllers/messages", + "client/controllers/events" ] - }, + } + ] + }, + { + "UIKit Components": [ + "uikit/uikit-overview", + "uikit/getting-started", + "uikit/theming", + "uikit/custom-components", { - "Views": [ - "uikit/views/channel-list-item-view", + "Channel List": [ + "uikit/components/channel-list", + "uikit/views/channel-list-item-view" + ], + "Channel": [ "uikit/views/channel-header-view", - "uikit/views/thread-header-view", - "uikit/views/message-layout-options-resolver", - "uikit/views/avatar", - "uikit/views/reactions" + "uikit/components/channel", + { + "Message List": [ + "uikit/components/message-list", + "uikit/components/thread", + "uikit/components/message", + "uikit/views/thread-header-view", + "uikit/views/message-layout-options-resolver", + "uikit/views/avatar", + "uikit/views/reactions", + "uikit/guides/customize-message-actions", + "uikit/guides/message-list-delivery-status", + "uikit/guides/customize-message-delivery-status" + ], + "Message Composer": [ + "uikit/components/message-composer", + "uikit/guides/working-with-attachments", + "uikit/guides/customize-message-composer", + "uikit/guides/message-composer-custom-attachments" + ] + }, + "uikit/components/voice-recording" ] }, "uikit/navigation", - { - "Guides": [ - "uikit/guides/customize-message-actions", - "uikit/guides/working-with-attachments", - "uikit/guides/customize-message-composer", - "uikit/guides/message-composer-custom-attachments", - "uikit/guides/message-list-delivery-status", - "uikit/guides/customize-message-delivery-status" - ] - } - + "uikit/localization", + "uikit/data-formatting" ] }, { - "SwiftUI": [ + "SwiftUI Components": [ "swiftui/swiftui-overview", "swiftui/getting-started", + "swiftui/view-customizations", { - "Core Principles": [ - "swiftui/localization", - "swiftui/dependency-injection", - "swiftui/view-customizations" - ] - }, - { - "Channel List Components": [ + "Channel List": [ "swiftui/channel-list-components/channel-list-header", "swiftui/channel-list-components/helper-views", "swiftui/channel-list-components/list-tap-events", @@ -75,71 +91,50 @@ ] }, { - "Chat Channel Components": [ + "Channel": [ "swiftui/chat-channel-components/overview", "swiftui/chat-channel-components/channel-header", - "swiftui/chat-channel-components/message-list", - "swiftui/chat-channel-components/message-composer", - "swiftui/chat-channel-components/composer-commands" + { + "Message List": [ + "swiftui/chat-channel-components/message-list", + "swiftui/message-components/message-display-options", + "swiftui/message-components/message-background", + "swiftui/message-components/custom-avatar", + "swiftui/message-components/attachments", + "swiftui/message-components/message-reactions", + "swiftui/message-components/message-threads", + "swiftui/message-components/inline-replies", + "swiftui/message-components/typing-indicators", + "swiftui/message-components/read-indicators" + ] + }, + { + "Message Composer": [ + "swiftui/chat-channel-components/message-composer", + "swiftui/chat-channel-components/composer-commands" + ] + } ] }, - { - "Message Components": [ - "swiftui/message-components/message-display-options", - "swiftui/message-components/message-background", - "swiftui/message-components/custom-avatar", - "swiftui/message-components/attachments", - "swiftui/message-components/message-reactions", - "swiftui/message-components/message-threads", - "swiftui/message-components/inline-replies", - "swiftui/message-components/typing-indicators", - "swiftui/message-components/read-indicators" - ] - }, - { - "SwiftUI Cookbook": [ - "swiftui/swiftui-cookbook/overview", - "swiftui/swiftui-cookbook/custom-channel-header", - "swiftui/swiftui-cookbook/custom-composer", - "swiftui/swiftui-cookbook/reactions-reordering", - "swiftui/swiftui-cookbook/list-alignment", - "swiftui/swiftui-cookbook/custom-message-list", - "swiftui/swiftui-cookbook/creating-channels" - ] - } + "swiftui/localization", + "swiftui/dependency-injection" ] }, { - "Client": [ - "client/llc-client-overview", - "client/extra-data", - "client/offline-support", - "client/importance-of-synchronize", - "client/push-notifications", - "client/custom-cdn", - { - "Audio Support": [ - "client/audio-support/audio-recording-and-playback-overview", - "client/audio-support/audio-recording", - "client/audio-support/audio-analysis", - "client/audio-support/audio-playback" - ] - }, - { - "Controllers and Delegates": [ - "client/controllers/controllers-overview", - "client/controllers/connection", - "client/controllers/channels", - "client/controllers/users", - "client/controllers/messages", - "client/controllers/events" - ] - } + "SwiftUI Cookbook": [ + "swiftui/swiftui-cookbook/overview", + "swiftui/swiftui-cookbook/custom-channel-header", + "swiftui/swiftui-cookbook/custom-composer", + "swiftui/swiftui-cookbook/reactions-reordering", + "swiftui/swiftui-cookbook/list-alignment", + "swiftui/swiftui-cookbook/custom-message-list", + "swiftui/swiftui-cookbook/creating-channels" ] }, { - "Advanced": - [ + "Advanced Guides": [ + "client/push-notifications", + "guides/share-extension", "advanced/assertions", { "Combine": [ @@ -154,20 +149,9 @@ ] }, { - "Guides": [ - { - "Third Party Video": [ - "guides/video-100ms", - "guides/video-agora" - ] - }, - { - "Major version upgrades": [ - "guides/migrating-from-3-to-4", - "guides/migrating-from-1.x-and-2.x" - ] - }, - "guides/share-extension" + "Migration Guides": [ + "guides/migrating-from-3-to-4", + "guides/migrating-from-1.x-and-2.x" ] }, { From abc368a08eec0992b785e930daa8728c1814f802 Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Fri, 17 Nov 2023 17:51:46 +0100 Subject: [PATCH 2/6] Small updates --- docusaurus/docs/iOS/basics/integration.md | 2 +- docusaurus/sidebars-ios.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docusaurus/docs/iOS/basics/integration.md b/docusaurus/docs/iOS/basics/integration.md index 6d4bf3c733f..9aca40a03a3 100644 --- a/docusaurus/docs/iOS/basics/integration.md +++ b/docusaurus/docs/iOS/basics/integration.md @@ -1,5 +1,5 @@ --- -title: Integration +title: Installation --- # Integration diff --git a/docusaurus/sidebars-ios.json b/docusaurus/sidebars-ios.json index 52efe917710..16315f9ae0e 100644 --- a/docusaurus/sidebars-ios.json +++ b/docusaurus/sidebars-ios.json @@ -13,7 +13,6 @@ "client/offline-support", "client/extra-data", "client/importance-of-synchronize", - "client/custom-cdn", { "Audio Support": [ "client/audio-support/audio-recording-and-playback-overview", @@ -134,6 +133,7 @@ { "Advanced Guides": [ "client/push-notifications", + "client/custom-cdn", "guides/share-extension", "advanced/assertions", { From 5df3f371c1f7dd04f59ce3659c722373134df458 Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Mon, 27 Nov 2023 13:17:31 +0100 Subject: [PATCH 3/6] Added message grouping docs --- .../message-grouping.md | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docusaurus/docs/iOS/swiftui/chat-channel-components/message-grouping.md diff --git a/docusaurus/docs/iOS/swiftui/chat-channel-components/message-grouping.md b/docusaurus/docs/iOS/swiftui/chat-channel-components/message-grouping.md new file mode 100644 index 00000000000..bcec2b32856 --- /dev/null +++ b/docusaurus/docs/iOS/swiftui/chat-channel-components/message-grouping.md @@ -0,0 +1,112 @@ +--- +title: Message Grouping +--- + +Chat apps frequently group messages based on a certain criteria (for example, time interval between the sending dates). The messages that are part of a group, usually have a different compact UI to distinguish themselves from the other groups. + +The messages in the message list are grouped based on the `maxTimeIntervalBetweenMessagesInGroup` value in the `MessageListConfig` (if the `groupMessages` option is set to `true`). It specifies a `TimeInterval` which determines how far apart messages can maximally be to be grouped together. + +The default value of this property is 60 seconds, which means messages that are 60 seconds (or less) apart, will be grouped together. Messages that are farther apart are not grouped together and appear as standalone messages. + +To change it up from the default value (`60` seconds) a different value (in this case: `20` seconds) can be specified like this: + +```swift +let messageListConfig = MessageListConfig( +// highlight-start + maxTimeIntervalBetweenMessagesInGroup: 20 +// highlight-end +) +let utils = Utils(messageListConfig: messageListConfig) +streamChat = StreamChat(chatClient: chatClient, utils: utils) +``` + +The information whether a message is first in the group is provided via the factory method `makeMessageContainerView`, with the `showsAllInfo` parameter. If this parameter is `true`, the message is first in the group. + +```swift +func makeMessageContainerView( + channel: ChatChannel, + message: ChatMessage, + width: CGFloat?, + showsAllInfo: Bool, + isInThread: Bool, + scrolledId: Binding, + quotedMessage: Binding, + onLongPress: @escaping (MessageDisplayInfo) -> Void, + isLast: Bool +) -> some View { + MessageContainerView( + factory: self, + channel: channel, + message: message, + width: width, + showsAllInfo: showsAllInfo, + isInThread: isInThread, + isLast: isLast, + scrolledId: scrolledId, + quotedMessage: quotedMessage, + onLongPress: onLongPress + ) +} +``` + +You can also provide a view for the last message in the group. In order to do that, you should implement the `makeLastInGroupHeaderView` factory method. + +```swift +public func makeLastInGroupHeaderView(for message: ChatMessage) -> some View { + YourCustomViewHere() +} +``` + +If you want to have a different grouping criteria (different than a time interval based), you can subclass the `ChatChannelViewModel` and override the `groupMessages` method. + +```swift +open func groupMessages() { + var temp = [String: [String]]() + for (index, message) in messages.enumerated() { + let date = message.createdAt + temp[message.id] = [] + if index == 0 { + temp[message.id] = [firstMessageKey] + continue + } else if index == messages.count - 1 { + temp[message.id] = [lastMessageKey] + } + + let previous = index - 1 + let previousMessage = messages[previous] + let currentAuthorId = messageCachingUtils.authorId(for: message) + let previousAuthorId = messageCachingUtils.authorId(for: previousMessage) + + if currentAuthorId != previousAuthorId { + temp[message.id]?.append(firstMessageKey) + var prevInfo = temp[previousMessage.id] ?? [] + prevInfo.append(lastMessageKey) + temp[previousMessage.id] = prevInfo + } + + if previousMessage.type == .error + || previousMessage.type == .ephemeral + || previousMessage.type == .system { + temp[message.id] = [firstMessageKey] + continue + } + + let delay = previousMessage.createdAt.timeIntervalSince(date) + + if delay > utils.messageListConfig.maxTimeIntervalBetweenMessagesInGroup { + temp[message.id]?.append(firstMessageKey) + var prevInfo = temp[previousMessage.id] ?? [] + prevInfo.append(lastMessageKey) + temp[previousMessage.id] = prevInfo + } + + if temp[message.id]?.isEmpty == true { + temp[message.id] = nil + } + } + + messagesGroupingInfo = temp +} +``` + +The important part here is that you set the `messagesGroupingInfo` value, consisting of message IDs and markers if they are a first or last message key. If no grouping info is provided, the message is considered as part of a group. \ No newline at end of file From 812f28714a4622ff6e2b066d002a2c9afad77c80 Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Mon, 27 Nov 2023 14:33:51 +0100 Subject: [PATCH 4/6] Small fixes --- docusaurus/docs/iOS/basics/integration.md | 2 +- docusaurus/docs/iOS/basics/overview.md | 6 +++--- docusaurus/docs/iOS/client/llc-client-overview.md | 2 +- docusaurus/sidebars-ios.json | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docusaurus/docs/iOS/basics/integration.md b/docusaurus/docs/iOS/basics/integration.md index 9aca40a03a3..4ea723c39a0 100644 --- a/docusaurus/docs/iOS/basics/integration.md +++ b/docusaurus/docs/iOS/basics/integration.md @@ -2,7 +2,7 @@ title: Installation --- -# Integration +# Installation To integrate Stream Chat in your app, you can use one of the following dependency managers: diff --git a/docusaurus/docs/iOS/basics/overview.md b/docusaurus/docs/iOS/basics/overview.md index 2d539e5f37c..0aff42c5544 100644 --- a/docusaurus/docs/iOS/basics/overview.md +++ b/docusaurus/docs/iOS/basics/overview.md @@ -5,7 +5,7 @@ slug: / Building on top of the Stream Chat API, the Stream Chat iOS component libraries include everything you need to build feature-rich and high-functioning chat user experiences out of the box. -We have a component libraries available for both UIKit and SwiftUI. Each library includes an extensive set of fast performing and customizable UI components which allow you to get started quickly with little to no plumbing required. The libraries supports: +We have a component libraries available for both UIKit and SwiftUI. Each library includes an extensive set of fast performing and customizable UI components which allow you to get started quickly with little to no plumbing required. The libraries support: - Rich media messages - Reactions @@ -17,6 +17,7 @@ We have a component libraries available for both UIKit and SwiftUI. Each library - Channel and message lists - Push (APN or Firebase) - Offline storage +- Voice messages - OSX ## Architecture @@ -27,7 +28,7 @@ StreamChat Swift SDK consists of three separate frameworks: - [`StreamChatSwiftUI`](./swiftui) provides a set of reusable and customizable UI components to add chat to your SwiftUI application. - `StreamChat` is the low-level client that provides the main chat functionality including offline storage and optimistic updates. You can use it directly in case you want to build your own UI layer for the chat. -We suggest using either [`StreamChatUI`](./uikit) or [`StreamChatSwiftUI`](./swiftui) for most of our users. Unless your UI is completely different from the common industry standard, you should be able to customize the built-in components to match your needs. +We suggest using either [`StreamChatUI`](./uikit) or [`StreamChatSwiftUI`](./swiftui) to most of our customers. Unless your UI is completely different from the common industry standard, you should be able to customize the built-in components to match your needs. :::note You can use this library to develop OSX application by using the `StreamChat` framework @@ -56,7 +57,6 @@ This SDK tries to keep the list of external dependencies to a minimum, these are :::note Starting **4.6.0**, and in order to improve the developer experience, dependencies are hidden inside our libraries. -(Does not apply to StreamChatSwiftUI's dependencies yet) ::: ## Choosing the right SDK diff --git a/docusaurus/docs/iOS/client/llc-client-overview.md b/docusaurus/docs/iOS/client/llc-client-overview.md index 25afbdd3eaf..6fe9c5ffe74 100644 --- a/docusaurus/docs/iOS/client/llc-client-overview.md +++ b/docusaurus/docs/iOS/client/llc-client-overview.md @@ -3,7 +3,7 @@ title: Low Level Client Overview slug: /client --- -Our low-level client provides the main chat functionality including offline storage and optimistic updates. You can use it directly in case you want to build your own UI layer for the chat. +Our [low-level client](https://getstream.io/chat/docs/ios-swift/?language=swift) provides the main chat functionality including offline storage and optimistic updates. You can use it directly in case you want to build your own UI layer for the chat. Both our [UIKit](../uikit) and [SwiftUI](../swiftui) UI component libraries use the low-level client. This way we are able to share common functionality across both our UI components libraries and increase performance and stability with every release. diff --git a/docusaurus/sidebars-ios.json b/docusaurus/sidebars-ios.json index 24b9698d5f8..3ec20fb0bfc 100644 --- a/docusaurus/sidebars-ios.json +++ b/docusaurus/sidebars-ios.json @@ -3,8 +3,7 @@ { "Basics": [ "basics/overview", - "basics/integration", - "basics/logs" + "basics/integration" ] }, { @@ -12,6 +11,7 @@ "client/llc-client-overview", "client/offline-support", "client/extra-data", + "basics/logs", "client/importance-of-synchronize", { "Audio Support": [ From 139b85a7f3b91c3d229d568557a5f4023614e0a4 Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Mon, 27 Nov 2023 15:35:23 +0100 Subject: [PATCH 5/6] Added channel list search doc --- .../channel-list-search.md | 46 +++++++++++++++++++ docusaurus/sidebars-ios.json | 1 + 2 files changed, 47 insertions(+) create mode 100644 docusaurus/docs/iOS/swiftui/channel-list-components/channel-list-search.md diff --git a/docusaurus/docs/iOS/swiftui/channel-list-components/channel-list-search.md b/docusaurus/docs/iOS/swiftui/channel-list-components/channel-list-search.md new file mode 100644 index 00000000000..70564b37126 --- /dev/null +++ b/docusaurus/docs/iOS/swiftui/channel-list-components/channel-list-search.md @@ -0,0 +1,46 @@ +--- +title: Channel List Search +--- + +By default, the channel list component shows a search bar at the top. This component lets you search through messages matching the search term inside the channels. When you tap on a search result, the corresponding channel is opened, automatically scrolling to the searched message. + +The SwiftUI components can also scroll to a message that is not available in the local database at that moment. In those cases, the messages around that message are also loaded. The scrolling in these cases can happen in both directions - up (for loading older messages) and down (for loading newer messages). + +You can also search for messages that are part of message threads. In those cases, first the channel is opened, and then the corresponding message thread is shown, scrolling to the searched message. + +In order to replace this component with your own (or completely remove it by returning an EmptyView), you need to implement the `makeChannelListTopView` method: + +```swift +func makeChannelListTopView( + searchText: Binding +) -> some View { + SearchBar(text: searchText) +} +``` + +In this method, a binding of the search text is provided, in case you want to implement your custom search bar. + +### Message Search Controller + +Under the hood, the channel list search uses the `MessageSearchController`, that you can also use to provide search in your custom UI components. + +Here's an example how to search for a particular search text: + +```swift +let messageSearchController = chatClient.messageSearchController() +let query = MessageSearchQuery( + channelFilter: .containMembers(userIds: [userId]), + messageFilter: .autocomplete(.text, text: searchText) +) +messageSearchController?.search(query: query, completion: { [weak self] _ in + self?.updateSearchResults() +}) +``` + +In order to perform search, you need to create a `MessageSearchQuery`. The query consists of `channelFilter` and `messageFilter`. + +The `channelFilter` defines which channels should be included in the filter. In the query above, we are including all channels that the current user is part of, by using the `containMembers` filter, that contains the current user id. + +The message filter defines which messages should be returned in the search query. In this case, we are using the `autocomplete` filter, with a search text taken from the user's input. + +For the different message search options, please check this [page](https://getstream.io/chat/docs/ios-swift/search/?language=swift). \ No newline at end of file diff --git a/docusaurus/sidebars-ios.json b/docusaurus/sidebars-ios.json index 3ec20fb0bfc..7b97cf63223 100644 --- a/docusaurus/sidebars-ios.json +++ b/docusaurus/sidebars-ios.json @@ -84,6 +84,7 @@ "Channel List": [ "swiftui/channel-list-components/channel-list-header", "swiftui/channel-list-components/helper-views", + "swiftui/channel-list-components/channel-list-search", "swiftui/channel-list-components/list-tap-events", "swiftui/channel-list-components/swipe-actions-channels", "swiftui/channel-list-components/query-filters" From cd2e618fbec4e83fa198636335eb74a96f532536 Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Mon, 27 Nov 2023 15:51:29 +0100 Subject: [PATCH 6/6] Updates to the message list docs --- .../docs/iOS/swiftui/chat-channel-components/message-list.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docusaurus/docs/iOS/swiftui/chat-channel-components/message-list.md b/docusaurus/docs/iOS/swiftui/chat-channel-components/message-list.md index a44ef673e46..dfa552432c5 100644 --- a/docusaurus/docs/iOS/swiftui/chat-channel-components/message-list.md +++ b/docusaurus/docs/iOS/swiftui/chat-channel-components/message-list.md @@ -10,7 +10,9 @@ The message list is the place to show a list of the messages of a specific chann A message can come in **many different forms**. If you are looking for the different types of messages and how to customize them the place to look for is the [Message Components](../../message-components/message-display-options/) section. The Message List is really handling the **list of the messages** that a channel contains. -The **default message list implementation** in the SDK follows the style of **other messaging apps** such as Apple's iMessage, Facebook Messenger, WhatsApp, Viber, and many other. In these kinds of apps, the **current sender's messages** are displayed on the **right side**, while the **other participants' messages** are displayed on the **left side**. In addition to that, there is an **avatar** of the user sending a message shown. +The **default message list implementation** in the SDK follows the style of **other messaging apps** such as Apple's iMessage, Facebook Messenger, WhatsApp, Telegram, and many others. In these kinds of apps, the **current sender's messages** are displayed on the **right side**, while the **other participants' messages** are displayed on the **left side**. In addition to that, there is an **avatar** of the user sending a message shown. + +The message list has many different customization options, and you can support many different layouts with it. We highly recommend to customize our message list component (by implementing your own message views) over building one from scratch. ## Customization options