Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.69.0 Release #3537

Merged
merged 16 commits into from
Dec 18, 2024
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
1 change: 1 addition & 0 deletions .github/workflows/release-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APPSTORE_API_KEY: ${{ secrets.APPSTORE_API_KEY }}
XCODE_VERSION: "15.0.1"
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### 🔄 Changed

# [4.69.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.69.0)
_December 18, 2024_

## StreamChat
### ✅ Added
- Archiving channels for the current user [#3524](https://github.com/GetStream/stream-chat-swift/pull/3524)
- Add `Chat.archive(scope:)` and `Chat.unarchive(scope:)`
- Add `ChatChannelController.archive(scope:completion:)` and `ChatChannelController.unarchive(scope:completion:)`
- Add `FilterKey.archive` for filtering channel lists
- Add `ChatChannel.membership.archivedAt`
- Add `ChatChannel.isArchived`
- Pinning channels for the current user [#3518](https://github.com/GetStream/stream-chat-swift/pull/3518)
- Add `Chat.pin(scope:)` and `Chat.unpin(scope:)`
- Add `ChatChannelController.pin(scope:completion:)` and `ChatChannelController.unpin(scope:completion:)`
- Add `FilterKey.pinned` for filtering channel lists
- Add `ChannelListSortingKey.pinnedAt`
- Add `ChatChannel.membership.pinnedAt`
- Add `ChatChannel.isPinned`
- Add channel list filtering key: `FilterKey.members` [#3536](https://github.com/GetStream/stream-chat-swift/pull/3536)
- Add member list filtering keys: `FilterKey.channelRole` and `FilterKey.email` [#3535](https://github.com/GetStream/stream-chat-swift/pull/3535)
- Add member list sorting key: `ChannelMemberListSortingKey.channelRole` [#3535](https://github.com/GetStream/stream-chat-swift/pull/3535)
### 🐞 Fixed
- End background task before starting a new one [#3528](https://github.com/GetStream/stream-chat-swift/pull/3528)

# [4.68.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.68.0)
_December 03, 2024_

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ struct DemoAppConfig {
var isAtlantisEnabled: Bool
/// A Boolean value to define if an additional message debugger action will be added.
var isMessageDebuggerEnabled: Bool
/// A Boolean value to define if channel pinning example is enabled.
var isChannelPinningEnabled: Bool
/// A Boolean value to define if custom location attachments are enabled.
var isLocationAttachmentsEnabled: Bool
/// Set this value to define if we should mimic token refresh scenarios.
Expand Down Expand Up @@ -49,7 +47,6 @@ class AppConfig {
isHardDeleteEnabled: false,
isAtlantisEnabled: false,
isMessageDebuggerEnabled: false,
isChannelPinningEnabled: false,
isLocationAttachmentsEnabled: false,
tokenRefreshDetails: nil,
shouldShowConnectionBanner: false,
Expand Down Expand Up @@ -172,7 +169,6 @@ class AppConfigViewController: UITableViewController {
case isHardDeleteEnabled
case isAtlantisEnabled
case isMessageDebuggerEnabled
case isChannelPinningEnabled
case isLocationAttachmentsEnabled
case tokenRefreshDetails
case shouldShowConnectionBanner
Expand Down Expand Up @@ -322,10 +318,6 @@ class AppConfigViewController: UITableViewController {
cell.accessoryView = makeSwitchButton(demoAppConfig.isMessageDebuggerEnabled) { [weak self] newValue in
self?.demoAppConfig.isMessageDebuggerEnabled = newValue
}
case .isChannelPinningEnabled:
cell.accessoryView = makeSwitchButton(demoAppConfig.isChannelPinningEnabled) { [weak self] newValue in
self?.demoAppConfig.isChannelPinningEnabled = newValue
}
case .isLocationAttachmentsEnabled:
cell.accessoryView = makeSwitchButton(demoAppConfig.isLocationAttachmentsEnabled) { [weak self] newValue in
self?.demoAppConfig.isLocationAttachmentsEnabled = newValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class DemoChatChannelListItemView: ChatChannelListItemView {
if content?.searchResult?.message != nil {
return super.contentBackgroundColor
}
if AppConfig.shared.demoAppConfig.isChannelPinningEnabled && content?.channel.isPinned == true {
if content?.channel.isPinned == true {
return appearance.colorPalette.pinnedMessageBackground
}
return super.contentBackgroundColor
Expand Down
34 changes: 20 additions & 14 deletions DemoApp/StreamChat/Components/DemoChatChannelListRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -451,22 +451,28 @@ final class DemoChatChannelListRouter: ChatChannelListRouter {
}
}
}),
.init(title: "Pin channel", isEnabled: AppConfig.shared.demoAppConfig.isChannelPinningEnabled, handler: { [unowned self] _ in
let userId = channelController.channel?.membership?.id ?? ""
let pinnedKey = ChatChannel.isPinnedBy(keyForUserId: userId)
channelController.partialChannelUpdate(extraData: [pinnedKey: true]) { error in
if let error = error {
self.rootViewController.presentAlert(title: "Couldn't pin channel \(cid)", message: "\(error)")
}
.init(title: "Pin channel", isEnabled: true, handler: { [unowned self] _ in
channelController.pin { error in
guard let error else { return }
self.rootViewController.presentAlert(title: "Couldn't pin channel \(cid)", message: "\(error)")
}
}),
.init(title: "Unpin channel", isEnabled: AppConfig.shared.demoAppConfig.isChannelPinningEnabled, handler: { [unowned self] _ in
let userId = channelController.channel?.membership?.id ?? ""
let pinnedKey = ChatChannel.isPinnedBy(keyForUserId: userId)
channelController.partialChannelUpdate(extraData: [pinnedKey: false]) { error in
if let error = error {
self.rootViewController.presentAlert(title: "Couldn't unpin channel \(cid)", message: "\(error)")
}
.init(title: "Unpin channel", isEnabled: true, handler: { [unowned self] _ in
channelController.unpin { error in
guard let error else { return }
self.rootViewController.presentAlert(title: "Couldn't unpin channel \(cid)", message: "\(error)")
}
}),
.init(title: "Archive channel", isEnabled: true, handler: { [unowned self] _ in
channelController.archive { error in
guard let error else { return }
self.rootViewController.presentAlert(title: "Couldn't archive channel \(cid)", message: "\(error)")
}
}),
.init(title: "Unarchive channel", isEnabled: true, handler: { [unowned self] _ in
channelController.unarchive { error in
guard let error else { return }
self.rootViewController.presentAlert(title: "Couldn't unarchive channel \(cid)", message: "\(error)")
}
}),
.init(title: "Enable slow mode", isEnabled: canSetChannelCooldown, handler: { [unowned self] _ in
Expand Down
57 changes: 55 additions & 2 deletions DemoApp/StreamChat/Components/DemoChatChannelListVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ final class DemoChatChannelListVC: ChatChannelListVC {
.containMembers(userIds: [currentUserId]),
.equal("is_cool", to: true)
]))

lazy var archivedChannelsQuery: ChannelListQuery = .init(filter: .and([
.containMembers(userIds: [currentUserId]),
.equal(.archived, to: true)
]))

lazy var pinnedChannelsQuery: ChannelListQuery = .init(filter: .and([
.containMembers(userIds: [currentUserId]),
.equal(.pinned, to: true)
]))

lazy var equalMembersQuery: ChannelListQuery = .init(filter:
.equal(.members, values: [currentUserId, "r2-d2"])
)

var demoRouter: DemoChatChannelListRouter? {
router as? DemoChatChannelListRouter
Expand Down Expand Up @@ -144,6 +158,30 @@ final class DemoChatChannelListVC: ChatChannelListVC {
self?.setMutedChannelsQuery()
}
)

let archivedChannelsAction = UIAlertAction(
title: "Archived Channels",
style: .default
) { [weak self] _ in
self?.title = "Archived Channels"
self?.setArchivedChannelsQuery()
}

let pinnedChannelsAction = UIAlertAction(
title: "Pinned Channels",
style: .default
) { [weak self] _ in
self?.title = "Pinned Channels"
self?.setPinnedChannelsQuery()
}

let equalMembersAction = UIAlertAction(
title: "R2-D2 Channels (Equal Members)",
style: .default
) { [weak self] _ in
self?.title = "R2-D2 Channels (Equal Members)"
self?.setEqualMembersChannelsQuery()
}

presentAlert(
title: "Filter Channels",
Expand All @@ -152,8 +190,11 @@ final class DemoChatChannelListVC: ChatChannelListVC {
unreadChannelsAction,
hiddenChannelsAction,
mutedChannelsAction,
coolChannelsAction
],
coolChannelsAction,
pinnedChannelsAction,
archivedChannelsAction,
equalMembersAction
].sorted(by: { $0.title ?? "" < $1.title ?? "" }),
preferredStyle: .actionSheet,
sourceView: filterChannelsButton
)
Expand All @@ -180,6 +221,18 @@ final class DemoChatChannelListVC: ChatChannelListVC {
)
replaceChannelListController(controller)
}

func setArchivedChannelsQuery() {
replaceQuery(archivedChannelsQuery)
}

func setPinnedChannelsQuery() {
replaceQuery(pinnedChannelsQuery)
}

func setEqualMembersChannelsQuery() {
replaceQuery(equalMembersQuery)
}

func setInitialChannelsQuery() {
replaceQuery(initialQuery)
Expand Down
30 changes: 3 additions & 27 deletions DemoApp/StreamChat/DemoAppCoordinator+DemoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,9 @@ extension DemoAppCoordinator {
let channelListQuery: ChannelListQuery
switch user {
case let .credentials(userCredentials):
if AppConfig.shared.demoAppConfig.isChannelPinningEnabled {
let pinnedByKey = ChatChannel.isPinnedBy(keyForUserId: userCredentials.id)
channelListQuery = .init(
filter: .containMembers(userIds: [userCredentials.id]),
sort: [
.init(key: .custom(keyPath: \.isPinned, key: pinnedByKey), isAscending: true),
.init(key: .lastMessageAt),
.init(key: .updatedAt)
]
)
} else {
channelListQuery = .init(
filter: .containMembers(userIds: [userCredentials.id])
)
}
channelListQuery = .init(
filter: .containMembers(userIds: [userCredentials.id])
)
case let .custom(userCredentials):
guard let userId = userCredentials?.id else {
fallthrough
Expand Down Expand Up @@ -216,18 +204,6 @@ private extension DemoAppCoordinator {
}
}

extension ChatChannel {
static func isPinnedBy(keyForUserId userId: UserId) -> String {
"is_pinned_by_\(userId)"
}

var isPinned: Bool {
guard let userId = membership?.id else { return false }
let key = Self.isPinnedBy(keyForUserId: userId)
return extraData[key]?.boolValue ?? false
}
}

private extension DemoUserType {
var staticUserId: UserId? {
guard case let .credentials(user) = self else { return nil }
Expand Down
3 changes: 3 additions & 0 deletions DemoApp/StreamChat/StreamChatWrapper+DemoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ extension StreamChatWrapper {
LogConfig.formatters = [
PrefixLogFormatter(prefixes: [.info: "ℹ️", .debug: "🛠", .warning: "⚠️", .error: "🚨"])
]
if let subsystems = StreamRuntimeCheck.subsystems {
LogConfig.subsystems = subsystems
}

// Create Client
if client == nil {
Expand Down
6 changes: 6 additions & 0 deletions DemoApp/StreamRuntimeCheck+StreamInternal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ extension StreamRuntimeCheck {
guard let intValue = Int(value) else { return nil }
return LogLevel(rawValue: intValue)
}

static var subsystems: LogSubsystem? {
guard let value = ProcessInfo.processInfo.environment["STREAM_LOG_SUBSYSTEM"] else { return nil }
guard let intValue = Int(value) else { return nil }
return LogSubsystem(rawValue: intValue)
}
}
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ GEM
fastlane
pry
fastlane-plugin-sonarcloud_metric_kit (0.2.1)
fastlane-plugin-stream_actions (0.3.76)
fastlane-plugin-stream_actions (0.3.77)
xctest_list (= 1.2.1)
fastlane-plugin-versioning (0.6.0)
ffi (1.17.0)
Expand Down Expand Up @@ -439,7 +439,7 @@ DEPENDENCIES
fastlane-plugin-create_xcframework
fastlane-plugin-lizard
fastlane-plugin-sonarcloud_metric_kit
fastlane-plugin-stream_actions (= 0.3.76)
fastlane-plugin-stream_actions (= 0.3.77)
fastlane-plugin-versioning
jazzy
json
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<a href="https://sonarcloud.io/summary/new_code?id=GetStream_stream-chat-swift"><img src="https://sonarcloud.io/api/project_badges/measure?project=GetStream_stream-chat-swift&metric=coverage" /></a>
</p>
<p align="center">
<img id="stream-chat-label" alt="StreamChat" src="https://img.shields.io/badge/StreamChat-7.08%20MB-blue"/>
<img id="stream-chat-ui-label" alt="StreamChatUI" src="https://img.shields.io/badge/StreamChatUI-4.96%20MB-blue"/>
<img id="stream-chat-label" alt="StreamChat" src="https://img.shields.io/badge/StreamChat-7.21%20MB-blue"/>
<img id="stream-chat-ui-label" alt="StreamChatUI" src="https://img.shields.io/badge/StreamChatUI-4.98%20MB-blue"/>
</p>

This is the official iOS SDK for [Stream Chat](https://getstream.io/chat/sdk/ios/), a service for building chat and messaging applications. This library includes both a low-level SDK and a set of reusable UI components.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ extension Endpoint {
static func partialMemberUpdate(
userId: UserId,
cid: ChannelId,
extraData: [String: RawJSON]?,
updates: MemberUpdatePayload?,
unset: [String]?
) -> Endpoint<PartialMemberUpdateResponse> {
var body: [String: AnyEncodable] = [:]
if let extraData {
body["set"] = AnyEncodable(extraData)
if let updates {
body["set"] = AnyEncodable(updates)
}
if let unset {
body["unset"] = AnyEncodable(unset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct MemberPayload: Decodable {
case inviteAcceptedAt = "invite_accepted_at"
case inviteRejectedAt = "invite_rejected_at"
case notificationsMuted = "notifications_muted"
case archivedAt = "archived_at"
case pinnedAt = "pinned_at"
}

let userId: String
Expand All @@ -63,6 +65,10 @@ struct MemberPayload: Decodable {
let inviteAcceptedAt: Date?
/// A date when an invited was rejected.
let inviteRejectedAt: Date?
/// A date when the channel was archived.
let archivedAt: Date?
/// A date when the channel was pinned.
let pinnedAt: Date?

/// A boolean value that returns whether the user has muted the channel or not.
let notificationsMuted: Bool
Expand All @@ -82,6 +88,8 @@ struct MemberPayload: Decodable {
isInvited: Bool? = nil,
inviteAcceptedAt: Date? = nil,
inviteRejectedAt: Date? = nil,
archivedAt: Date? = nil,
pinnedAt: Date? = nil,
notificationsMuted: Bool = false,
extraData: [String: RawJSON]? = nil
) {
Expand All @@ -96,6 +104,8 @@ struct MemberPayload: Decodable {
self.isInvited = isInvited
self.inviteAcceptedAt = inviteAcceptedAt
self.inviteRejectedAt = inviteRejectedAt
self.archivedAt = archivedAt
self.pinnedAt = pinnedAt
self.notificationsMuted = notificationsMuted
self.extraData = extraData
}
Expand All @@ -112,6 +122,8 @@ struct MemberPayload: Decodable {
isInvited = try container.decodeIfPresent(Bool.self, forKey: .isInvited)
inviteAcceptedAt = try container.decodeIfPresent(Date.self, forKey: .inviteAcceptedAt)
inviteRejectedAt = try container.decodeIfPresent(Date.self, forKey: .inviteRejectedAt)
archivedAt = try container.decodeIfPresent(Date.self, forKey: .archivedAt)
pinnedAt = try container.decodeIfPresent(Date.self, forKey: .pinnedAt)
notificationsMuted = try container.decodeIfPresent(Bool.self, forKey: .notificationsMuted) ?? false

if let user = user {
Expand Down
Loading
Loading