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
32 changes: 0 additions & 32 deletions .github/workflows/merge-main-to-develop.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/release-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
workflow_dispatch:

jobs:
merge-comment:
merge-release-to-main:
name: Merge release to main
runs-on: macos-15
if: github.event_name == 'workflow_dispatch' || (github.event.issue.pull_request && github.event.issue.state == 'open' && github.event.comment.body == '/merge release')
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,28 @@ jobs:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APPSTORE_API_KEY: ${{ secrets.APPSTORE_API_KEY }}
run: bundle exec fastlane publish_release --verbose

merge-main-to-develop:
name: Merge main to develop
runs-on: ubuntu-latest
needs: release
steps:
- uses: actions/[email protected]
with:
token: ${{ secrets.ADMIN_API_TOKEN }}
fetch-depth: 0

- uses: ./.github/actions/ruby-cache

- run: bundle exec fastlane merge_main
env:
GITHUB_TOKEN: ${{ secrets.ADMIN_API_TOKEN }}

- uses: 8398a7/action-slack@v3
if: failure()
with:
status: ${{ job.status }}
text: "⚠️ <!subteam^S030AAHLDLN>, the merge of `main` to `develop` failed on CI. Consider using this command locally: `bundle exec fastlane merge_main`"
fields: repo,commit,author,workflow
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
86 changes: 86 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
Guidance for AI coding agents (Copilot, Cursor, Aider, Claude, etc.) working in this repository. Human readers are welcome, but this file is written for tools.

### Repository purpose

This repo hosts Stream’s SwiftUI Chat SDK for iOS. It builds on the core client and provides SwiftUI-first chat components (views, view models, modifiers) for messaging apps.

Agents should optimize for API stability, backwards compatibility, accessibility, and high test coverage when changing code.

### Tech & toolchain
β€’ Language: Swift (SwiftUI)
β€’ Primary distribution: Swift Package Manager (SPM), secondary CocoaPods and XCFrameworks
β€’ Xcode: 15.x or newer (Apple Silicon supported)
β€’ Platforms / deployment targets: Use the values set in Package.swift/podspecs; do not lower targets without approval
β€’ CI: GitHub Actions (assume PR validation for build + tests + lint)
β€’ Linters & docs: SwiftLint via Mint

### Project layout (high level)

Sources/
StreamChatSwiftUI/ # SwiftUI views, view models, theming, utils
Tests/
StreamChatSwiftUITests/ # Unit/UI tests for SwiftUI layer

When editing near other packages (e.g., StreamChat or StreamChatUI), prefer extending the SwiftUI layer rather than duplicating logic from dependencies.

### Local setup (SPM)
1. Open the repository in Xcode (root contains Package.swift).
2. Resolve packages.
3. Choose an iOS Simulator (e.g., iPhone 15) and Build.

Optional: sample/demo app

If a sample app target exists in this repo, prefer running that to validate UI changes. Keep demo configs free of credentials and use placeholders like YOUR_STREAM_KEY.

### Schemes

Typical scheme names include:
β€’ StreamChatSwiftUI
β€’ StreamChatSwiftUITests

Agents must query existing schemes before invoking xcodebuild.

### Build & test commands (CLI)

Prefer Xcode for day-to-day work; use CLI for CI parity & automation.

Build (Debug):

```
xcodebuild \
-scheme StreamChatSwiftUI \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-configuration Debug build
```

Run tests:

```
xcodebuild \
-scheme StreamChatSwiftUI \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-configuration Debug test
```

If a Makefile or scripts exist (e.g., make build, make test, ./scripts/lint.sh), prefer those to keep parity with CI. Discover with make help and ls scripts/.

Linting & formatting
β€’ SwiftLint (strict):

swiftlint --strict

β€’ Respect .swiftlint.yml and any repo-specific rules. Do not broadly disable rules; scope exceptions and justify in PRs.

Public API & SemVer
β€’ Follow semantic versioning for the SwiftUI package.
β€’ Any public API change must include updated docs and migration notes.
β€’ Avoid source-breaking changes. If unavoidable, add deprecations first with a transition path.

Accessibility & UI quality
β€’ Ensure components have accessibility labels, traits, and dynamic type support.
β€’ Support both light/dark mode.
β€’ When altering UI, attach before/after screenshots (or screen recordings) in PRs.

Testing policy
β€’ Add/extend tests in StreamChatSwiftUITests/ for:
β€’ View models and state handling
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### πŸ”„ Changed

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

### βœ… Added
- Add `ColorPalette.navigationBarTitle`, `ColorPalette.navigationBarSubtitle`, `ColorPalette.navigationBarTintColor`, `ColorPalette.navigationBarBackground` [#939](https://github.com/GetStream/stream-chat-swiftui/pull/939)
### 🐞 Fixed
- Long message with a link preview was truncated sometimes [#940](https://github.com/GetStream/stream-chat-swiftui/pull/940)
- Fix quoted message shown in the composer when editing a quoting message [#943](https://github.com/GetStream/stream-chat-swiftui/pull/943)
- Fix pinned messages view not using relative time formatter [#946](https://github.com/GetStream/stream-chat-swiftui/pull/946)

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

Expand All @@ -22,7 +32,7 @@ _September 01, 2025_
_August 21, 2025_

### 🐞 Fixed
- Fix inconsistencies in gallery view displaying images and videos [927](https://github.com/GetStream/stream-chat-swiftui/pull/927)
- Fix inconsistencies in gallery view displaying images and videos [#927](https://github.com/GetStream/stream-chat-swiftui/pull/927)
- Prevent audio messages increasing width in reply mode [#926](https://github.com/GetStream/stream-chat-swiftui/pull/926)

# [4.85.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.85.0)
Expand Down
38 changes: 28 additions & 10 deletions DemoAppSwiftUI/ChannelHeader/CustomChannelHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public struct CustomChannelHeader: ToolbarContent {
Image(uiImage: images.messageActionEdit)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.foregroundColor(Color.white)
.padding(.all, 8)
.background(colors.tintColor)
Expand All @@ -41,9 +42,12 @@ public struct CustomChannelHeader: ToolbarContent {
Button {
actionsPopupShown = true
} label: {
StreamLazyImage(url: currentUserController.currentUser?.imageURL)
.accessibilityLabel("Account Actions")
.accessibilityAddTraits(.isButton)
StreamLazyImage(
url: currentUserController.currentUser?.imageURL,
size: CGSize(width: 36, height: 36)
)
.accessibilityLabel("Account Actions")
.accessibilityAddTraits(.isButton)
}
}
}
Expand All @@ -62,13 +66,27 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier {

func body(content: Content) -> some View {
ZStack {
content.toolbar {
CustomChannelHeader(
title: title,
currentUserController: chatClient.currentUserController(),
isNewChatShown: $isNewChatShown,
actionsPopupShown: $actionsPopupShown
)
if #available(iOS 26, *) {
content.toolbar {
CustomChannelHeader(
title: title,
currentUserController: chatClient.currentUserController(),
isNewChatShown: $isNewChatShown,
actionsPopupShown: $actionsPopupShown
)
#if compiler(>=6.2)
.sharedBackgroundVisibility(.hidden)
#endif
}
} else {
content.toolbar {
CustomChannelHeader(
title: title,
currentUserController: chatClient.currentUserController(),
isNewChatShown: $isNewChatShown,
actionsPopupShown: $actionsPopupShown
)
}
}

NavigationLink(isActive: $blockedUsersShown) {
Expand Down
16 changes: 5 additions & 11 deletions DemoAppSwiftUI/DemoAppSwiftUIApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,13 @@ extension AppState {
guard let currentUserId = chatClient.currentUserId else { fatalError("Not logged in") }
switch identifier {
case .initial:
var sort: [Sorting<ChannelListSortingKey>] = [Sorting(key: .default)]
if AppConfiguration.default.isChannelPinningFeatureEnabled {
sort.insert(Sorting(key: .pinnedAt), at: 0)
}
return ChannelListQuery(
filter: .containMembers(userIds: [currentUserId]),
sort: [
Sorting(key: .default)
]
)
case .initial where AppConfiguration.default.isChannelPinningFeatureEnabled:
return ChannelListQuery(
filter: .containMembers(userIds: [currentUserId]),
sort: [
Sorting(key: .pinnedAt),
Sorting(key: .default)
]
sort: sort
)
case .archived:
return ChannelListQuery(
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.87.0")
.package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.88.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.24%20MB-blue"/>
<img id="stream-chat-swiftui-label" alt="StreamChatSwiftUI" src="https://img.shields.io/badge/StreamChatSwiftUI-9.35%20MB-blue"/>
</p>

## SwiftUI StreamChat SDK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public struct DefaultChatChannelHeader<Factory: ViewFactory>: ToolbarContent {
)
.offset(x: 4)
}
.accentColor(colors.navigationBarTintColor)
.accessibilityLabel(Text(L10n.Channel.Header.Info.title))

NavigationLink(isActive: $isActive) {
Expand Down Expand Up @@ -108,13 +109,31 @@ public struct DefaultChannelHeaderModifier<Factory: ViewFactory>: ChatChannelHea
}

public func body(content: Content) -> some View {
content.toolbar {
DefaultChatChannelHeader(
factory: factory,
channel: channel,
headerImage: channelHeaderLoader.image(for: channel),
isActive: $isActive
)
if #available(iOS 26, *) {
content
.navigationBarBackground()
.toolbar {
DefaultChatChannelHeader(
factory: factory,
channel: channel,
headerImage: channelHeaderLoader.image(for: channel),
isActive: $isActive
)
#if compiler(>=6.2)
.sharedBackgroundVisibility(.hidden)
#endif
}
} else {
content
.navigationBarBackground()
.toolbar {
DefaultChatChannelHeader(
factory: factory,
channel: channel,
headerImage: channelHeaderLoader.image(for: channel),
isActive: $isActive
)
}
}
}
}
Expand Down Expand Up @@ -145,7 +164,7 @@ public struct ChannelTitleView: View {
VStack(spacing: 2) {
Text(channelNamer(channel, currentUserId) ?? "")
.font(fonts.bodyBold)
.foregroundColor(Color(colors.text))
.foregroundColor(Color(colors.navigationBarTitle))
.accessibilityIdentifier("chatName")

if shouldShowTypingIndicator {
Expand All @@ -156,7 +175,7 @@ public struct ChannelTitleView: View {
} else {
Text(channel.onlineInfoText(currentUserId: currentUserId))
.font(fonts.footnote)
.foregroundColor(Color(colors.textLowEmphasis))
.foregroundColor(Color(colors.navigationBarSubtitle))
.accessibilityIdentifier("chatOnlineInfo")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ public struct DefaultMessageThreadHeader: ToolbarContent {
VStack {
Text(L10n.Message.Actions.threadReply)
.font(fonts.bodyBold)
.foregroundColor(Color(colors.navigationBarTitle))
Text(L10n.Message.Threads.subtitle)
.font(fonts.footnote)
.foregroundColor(Color(colors.textLowEmphasis))
.foregroundColor(Color(colors.navigationBarSubtitle))
}
}
}
Expand All @@ -29,8 +30,10 @@ public struct DefaultMessageThreadHeader: ToolbarContent {
/// The default message thread header modifier.
public struct DefaultMessageThreadHeaderModifier: MessageThreadHeaderViewModifier {
public func body(content: Content) -> some View {
content.toolbar {
DefaultMessageThreadHeader()
}
content
.navigationBarBackground()
.toolbar {
DefaultMessageThreadHeader()
}
}
}
Loading
Loading