Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### πŸ”„ Changed

# [4.87.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.87.0)
_September 01, 2025_

### βœ… Added
- Add option to scroll to and open a channel from the channel list [#932](https://github.com/GetStream/stream-chat-swiftui/pull/932)
- Make `MediaItem` and `MediaAttachmentContentView` public to allow customization [#935](https://github.com/GetStream/stream-chat-swiftui/pull/935)

### 🐞 Fixed
- Show attachment title instead of URL in the `FileAttachmentPreview` view [#930](https://github.com/GetStream/stream-chat-swiftui/pull/930)
- Fix overriding title color in `ChannelTitleView` [#931](https://github.com/GetStream/stream-chat-swiftui/pull/931)
- Use channel capabilities for validating delete message action [#933](https://github.com/GetStream/stream-chat-swiftui/pull/933)
- Fix the video attachments now fetch the URL once on appear and pause when swiping to another item in the gallery [#934](https://github.com/GetStream/stream-chat-swiftui/pull/934)

# [4.86.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.86.0)
_August 21, 2025_

Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.86.0")
.package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.87.0")
],
targets: [
.target(
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<p align="center">
<a href="https://sonarcloud.io/summary/new_code?id=GetStream_stream-chat-swiftui"><img src="https://sonarcloud.io/api/project_badges/measure?project=GetStream_stream-chat-swiftui&metric=coverage" /></a>

<img id="stream-chat-swiftui-label" alt="StreamChatSwiftUI" src="https://img.shields.io/badge/StreamChatSwiftUI-9.22%20MB-blue"/>
<img id="stream-chat-swiftui-label" alt="StreamChatSwiftUI" src="https://img.shields.io/badge/StreamChatSwiftUI-9.24%20MB-blue"/>
</p>

## SwiftUI StreamChat SDK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public struct ChannelTitleView: View {
VStack(spacing: 2) {
Text(channelNamer(channel, currentUserId) ?? "")
.font(fonts.bodyBold)
.foregroundColor(Color(colors.text))
.accessibilityIdentifier("chatName")

if shouldShowTypingIndicator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public struct FileAttachmentsView: View {
.padding(.vertical)
}
.sheet(item: $viewModel.selectedAttachment) { item in
FileAttachmentPreview(url: item.assetURL)
FileAttachmentPreview(title: item.title, url: item.assetURL)
}

Divider()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public struct MediaAttachmentsView<Factory: ViewFactory>: View {
}
}

struct MediaAttachmentContentView<Factory: ViewFactory>: View {
public struct MediaAttachmentContentView<Factory: ViewFactory>: View {
@State private var galleryShown = false

let factory: Factory
Expand All @@ -112,7 +112,23 @@ struct MediaAttachmentContentView<Factory: ViewFactory>: View {
let itemWidth: CGFloat
let index: Int

var body: some View {
public init(
factory: Factory,
mediaItem: MediaItem,
mediaAttachment: MediaAttachment,
allMediaAttachments: [MediaAttachment],
itemWidth: CGFloat,
index: Int
) {
self.factory = factory
self.mediaItem = mediaItem
self.mediaAttachment = mediaAttachment
self.allMediaAttachments = allMediaAttachments
self.itemWidth = itemWidth
self.index = index
}

public var body: some View {
Button {
galleryShown = true
} label: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,29 @@ class MediaAttachmentsViewModel: ObservableObject, ChatMessageSearchControllerDe
}
}

struct MediaItem: Identifiable {
let id: String
let isVideo: Bool
let message: ChatMessage
public struct MediaItem: Identifiable {
public let id: String
public let isVideo: Bool
public let message: ChatMessage

var videoAttachment: ChatMessageVideoAttachment?
var imageAttachment: ChatMessageImageAttachment?
public var videoAttachment: ChatMessageVideoAttachment?
public var imageAttachment: ChatMessageImageAttachment?

var mediaAttachment: MediaAttachment? {
public init(
id: String,
isVideo: Bool,
message: ChatMessage,
videoAttachment: ChatMessageVideoAttachment?,
imageAttachment: ChatMessageImageAttachment?
) {
self.id = id
self.isVideo = isVideo
self.message = message
self.videoAttachment = videoAttachment
self.imageAttachment = imageAttachment
}

public var mediaAttachment: MediaAttachment? {
if let videoAttachment {
return MediaAttachment(url: videoAttachment.videoURL, type: .video)
} else if let imageAttachment {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ struct StreamVideoPlayer: View {
}
}
.onAppear {
guard avPlayer == nil else {
avPlayer?.play()
return
}
fileCDN.adjustedURL(for: url) { result in
switch result {
case let .success(url):
Expand All @@ -179,5 +183,8 @@ struct StreamVideoPlayer: View {
}
}
}
.onDisappear {
avPlayer?.pause()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@ public struct FileAttachmentPreview: View {
utils.fileCDN
}

let title: String?
var url: URL

@State private var adjustedUrl: URL?
@State private var isLoading = false
@State private var title: String?
@State private var webViewTitle: String?
@State private var error: Error?


var navigationTitle: String {
if let title, !title.isEmpty { return title }
if let webViewTitle, !webViewTitle.isEmpty { return webViewTitle }
return url.absoluteString
}

public var body: some View {
NavigationView {
ZStack {
Expand All @@ -35,7 +42,7 @@ public struct FileAttachmentPreview: View {
WebView(
url: adjustedUrl,
isLoading: $isLoading,
title: $title,
title: $webViewTitle,
error: $error
)
}
Expand All @@ -58,7 +65,7 @@ public struct FileAttachmentPreview: View {
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Text(title ?? url.absoluteString)
Text(navigationTitle)
.font(fonts.bodyBold)
.lineLimit(1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public struct FileAttachmentView: View {
.roundWithBorder()
.withUploadingStateIndicator(for: attachment.uploadingState, url: attachment.assetURL)
.sheet(isPresented: $fullScreenShown) {
FileAttachmentPreview(url: attachment.assetURL)
FileAttachmentPreview(title: attachment.title, url: attachment.assetURL)
}
.accessibilityIdentifier("FileAttachmentView")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public extension MessageAction {
}
}

if message.isSentByCurrentUser {
if channel.canDeleteAnyMessage || channel.canDeleteOwnMessage && message.isSentByCurrentUser {
let deleteAction = deleteMessageAction(
for: message,
channel: channel,
Expand All @@ -166,7 +166,9 @@ public extension MessageAction {
)

messageActions.append(deleteAction)
} else {
}

if !message.isSentByCurrentUser {
if channel.canFlagMessage {
let flagAction = flagMessageAction(
for: message,
Expand Down
16 changes: 14 additions & 2 deletions Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public struct ChannelList<Factory: ViewFactory>: View {
var channels: LazyCachedMapCollection<ChatChannel>
@Binding var selectedChannel: ChannelSelectionInfo?
@Binding var swipedChannelId: String?
@Binding var scrolledChannelId: String?
private var scrollable: Bool
private var onlineIndicatorShown: (ChatChannel) -> Bool
private var imageLoader: (ChatChannel) -> UIImage
Expand All @@ -30,6 +31,7 @@ public struct ChannelList<Factory: ViewFactory>: View {
channels: LazyCachedMapCollection<ChatChannel>,
selectedChannel: Binding<ChannelSelectionInfo?>,
swipedChannelId: Binding<String?>,
scrolledChannelId: Binding<String?> = .constant(nil),
scrollable: Bool = true,
onlineIndicatorShown: ((ChatChannel) -> Bool)? = nil,
imageLoader: ((ChatChannel) -> UIImage)? = nil,
Expand Down Expand Up @@ -72,13 +74,23 @@ public struct ChannelList<Factory: ViewFactory>: View {
self.scrollable = scrollable
_selectedChannel = selectedChannel
_swipedChannelId = swipedChannelId
_scrolledChannelId = scrolledChannelId
}

public var body: some View {
Group {
if scrollable {
ScrollView {
channelsVStack
ScrollViewReader { scrollView in
ScrollView {
channelsVStack
}
.onChange(of: scrolledChannelId) { newValue in
if let newValue {
withAnimation {
scrollView.scrollTo(newValue, anchor: .bottom)
}
}
}
}
} else {
channelsVStack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ public struct ChatChannelListContentView<Factory: ViewFactory>: View {
channels: viewModel.channels,
selectedChannel: $viewModel.selectedChannel,
swipedChannelId: $viewModel.swipedChannelId,
scrolledChannelId: $viewModel.scrolledChannelId,
onlineIndicatorShown: viewModel.onlineIndicatorShown(for:),
imageLoader: channelHeaderLoader.image(for:),
onItemTap: onItemTap,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController

/// Index of the selected channel.
private var selectedChannelIndex: Int?

/// When set, scrolls to the specified channel id (if it exists).
@Published public var scrolledChannelId: String?

/// Published variables.
@Published public var channels = LazyCachedMapCollection<ChatChannel>() {
Expand Down Expand Up @@ -180,6 +183,38 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
}
}
}

/// Opens the chat channel destination with the provided channel id.
///
/// - Parameter channelId: the id of the channel that will be shown.
public func openChannel(with channelId: ChannelId) {
func loadUntilFound() {
guard let controller else { return }
if let channel = controller.channels.first(where: { $0.id == channelId.rawValue }) {
log.debug("Showing channel with id \(channelId)")
scrollToAndOpen(channel: channel)
return
}

// Stop if there are no more channels to load
if controller.hasLoadedAllPreviousChannels {
scrolledChannelId = nil
return
}

controller.loadNextChannels { [weak self] error in
if error != nil {
self?.scrolledChannelId = nil
return
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
loadUntilFound()
}
}
}

loadUntilFound()
}

public func loadAdditionalSearchResults(index: Int) {
switch searchType {
Expand Down Expand Up @@ -543,6 +578,14 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
markDirty = true
channels = LazyCachedMapCollection(source: temp, map: { $0 })
}

private func scrollToAndOpen(channel: ChatChannel) {
scrolledChannelId = channel.id
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
self?.selectedChannel = .init(channel: channel, message: nil)
self?.scrolledChannelId = nil
}
}

private func observeChannelDismiss() {
NotificationCenter.default.addObserver(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import Foundation

enum SystemEnvironment {
/// A Stream Chat version.
public static let version: String = "4.86.0"
public static let version: String = "4.87.0"
}
2 changes: 1 addition & 1 deletion Sources/StreamChatSwiftUI/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>4.86.0</string>
<string>4.87.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPhotoLibraryUsageDescription</key>
Expand Down
4 changes: 2 additions & 2 deletions StreamChatSwiftUI-XCFramework.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'StreamChatSwiftUI-XCFramework'
spec.version = '4.86.0'
spec.version = '4.87.0'
spec.summary = 'StreamChat SwiftUI Chat Components'
spec.description = 'StreamChatSwiftUI SDK offers flexible SwiftUI components able to display data provided by StreamChat SDK.'

Expand All @@ -19,7 +19,7 @@ Pod::Spec.new do |spec|

spec.framework = 'Foundation', 'UIKit', 'SwiftUI'

spec.dependency 'StreamChat-XCFramework', '~> 4.86.0'
spec.dependency 'StreamChat-XCFramework', '~> 4.87.0'

spec.cocoapods_version = '>= 1.11.0'
end
4 changes: 2 additions & 2 deletions StreamChatSwiftUI.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'StreamChatSwiftUI'
spec.version = '4.86.0'
spec.version = '4.87.0'
spec.summary = 'StreamChat SwiftUI Chat Components'
spec.description = 'StreamChatSwiftUI SDK offers flexible SwiftUI components able to display data provided by StreamChat SDK.'

Expand All @@ -19,5 +19,5 @@ Pod::Spec.new do |spec|

spec.framework = 'Foundation', 'UIKit', 'SwiftUI'

spec.dependency 'StreamChat', '~> 4.86.0'
spec.dependency 'StreamChat', '~> 4.87.0'
end
Loading
Loading