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
4 changes: 2 additions & 2 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ file_name_no_space:

cyclomatic_complexity:
ignores_case_statements: true
warning: 25
error: 30
warning: 30
error: 35
Comment on lines -70 to +71
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was getting a warning about the ChatChannel equality implementation and there is no good solution so I bumped these values.


custom_rules:
regular_constraints_forbidden:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `ChatClient.deleteAttachment(remoteUrl:)` [#3883](https://github.com/GetStream/stream-chat-swift/pull/3883)
- Add `CDNClient.deleteAttachment(remoteUrl:)` [#3883](https://github.com/GetStream/stream-chat-swift/pull/3883)
- Add `heic`, `heif` and `svg` formats to the supported image file types [#3883](https://github.com/GetStream/stream-chat-swift/pull/3883)
- Add support for filter tags in channels [#3886](https://github.com/GetStream/stream-chat-swift/pull/3886)
- Add `ChatChannel.filterTags`
- Add `filterTags` channel list filtering key
- Add `filterTags` argument to `ChatChannelController` and `Chat` factory methods in `ChatClient`
- Add `filterTags` argument to `ChatChannelController.updateChannel` and `ChatChannelController.partialUpdateChannel`
- Add `filterTags` argument to `Chat.update` and `Chat.updatePartial`
### 🐞 Fixed
- Fix rare crash in `WebSocketClient.connectEndpoint` [#3882](https://github.com/GetStream/stream-chat-swift/pull/3882)
- Fix audio recordings not playing from AirPods automatically [#3884](https://github.com/GetStream/stream-chat-swift/pull/3884)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,14 @@ final class DemoChatChannelListRouter: ChatChannelListRouter {
}
}
}),
.init(title: "Add Premium Tag", isEnabled: canUpdateChannel, handler: { [unowned self] _ in
channelController.partialChannelUpdate(filterTags: ["premium"]) { error in
if let error = error {
self.rootViewController.presentAlert(title: "Couldn't make the channel \(cid) premium", message: "\(error)")
}
}
}),

.init(title: "Unmute channel", isEnabled: canMuteChannel, handler: { [unowned self] _ in
channelController.unmuteChannel { error in
if let error = error {
Expand Down
18 changes: 17 additions & 1 deletion DemoApp/StreamChat/Components/DemoChatChannelListVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ final class DemoChatChannelListVC: ChatChannelListVC {
lazy var equalMembersQuery: ChannelListQuery = .init(filter:
.equal(.members, values: [currentUserId, "r2-d2"])
)

lazy var premiumTaggedChannelsQuery: ChannelListQuery = .init(filter: .in(.filterTags, values: ["premium"]))

var demoRouter: DemoChatChannelListRouter? {
router as? DemoChatChannelListRouter
Expand Down Expand Up @@ -256,6 +258,15 @@ final class DemoChatChannelListVC: ChatChannelListVC {
self?.title = "R2-D2 Channels (Equal Members)"
self?.setEqualMembersChannelsQuery()
}

let taggedChannelsAction = UIAlertAction(
title: "Premium Tagged Channels",
style: .default,
handler: { [weak self] _ in
self?.title = "Premium Tagged Channels"
self?.setPremiumTaggedChannelsQuery()
}
)

presentAlert(
title: "Filter Channels",
Expand All @@ -271,7 +282,8 @@ final class DemoChatChannelListVC: ChatChannelListVC {
pinnedChannelsAction,
archivedChannelsAction,
equalMembersAction,
channelRoleChannelsAction
channelRoleChannelsAction,
taggedChannelsAction
].sorted(by: { $0.title ?? "" < $1.title ?? "" }),
preferredStyle: .actionSheet,
sourceView: filterChannelsButton
Expand Down Expand Up @@ -327,6 +339,10 @@ final class DemoChatChannelListVC: ChatChannelListVC {
func setEqualMembersChannelsQuery() {
replaceQuery(equalMembersQuery)
}

func setPremiumTaggedChannelsQuery() {
replaceQuery(premiumTaggedChannelsQuery)
}

func setInitialChannelsQuery() {
replaceQuery(initialQuery)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public enum ChannelCodingKeys: String, CodingKey, CaseIterable {
case members
/// Invites.
case invites
case filterTags = "filter_tags"
/// The team the channel belongs to.
case team
case memberCount = "member_count"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@
let team: String?
let members: Set<UserId>
let invites: Set<UserId>
let filterTags: Set<String>
let extraData: [String: RawJSON]

init(

Check warning on line 18 in Sources/StreamChat/APIClient/Endpoints/Payloads/ChannelEditDetailPayload.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Initializer has 8 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-swift&issues=AZrLFuJNhOwvUL1tRFZv&open=AZrLFuJNhOwvUL1tRFZv&pullRequest=3886
cid: ChannelId,
name: String?,
imageURL: URL?,
team: String?,
members: Set<UserId>,
invites: Set<UserId>,
filterTags: Set<String>,
extraData: [String: RawJSON]
) {
id = cid.id
Expand All @@ -30,16 +32,18 @@
self.team = team
self.members = members
self.invites = invites
self.filterTags = filterTags
self.extraData = extraData
}

init(

Check warning on line 39 in Sources/StreamChat/APIClient/Endpoints/Payloads/ChannelEditDetailPayload.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Initializer has 8 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-swift&issues=AZrLFuJNhOwvUL1tRFZw&open=AZrLFuJNhOwvUL1tRFZw&pullRequest=3886
type: ChannelType,
name: String?,
imageURL: URL?,
team: String?,
members: Set<UserId>,
invites: Set<UserId>,
filterTags: Set<String>,
extraData: [String: RawJSON]
) {
id = nil
Expand All @@ -49,6 +53,7 @@
self.team = team
self.members = members
self.invites = invites
self.filterTags = filterTags
self.extraData = extraData
}

Expand All @@ -63,6 +68,10 @@
allMembers = allMembers.union(invites)
try container.encode(invites, forKey: .invites)
}

if !filterTags.isEmpty {
try container.encode(filterTags, forKey: .filterTags)
}

if !allMembers.isEmpty {
try container.encode(allMembers, forKey: .members)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ struct ChannelDetailPayload {
let createdBy: UserPayload?
/// A config.
let config: ChannelConfig
let filterTags: [String]?
/// The list of actions that the current user can perform in a channel.
/// It is optional, since not all events contain the own capabilities property for performance reasons.
let ownCapabilities: [String]?
Expand Down Expand Up @@ -188,6 +189,7 @@ extension ChannelDetailPayload: Decodable {
truncatedAt: try container.decodeIfPresent(Date.self, forKey: .truncatedAt),
createdBy: try container.decodeIfPresent(UserPayload.self, forKey: .createdBy),
config: try container.decode(ChannelConfig.self, forKey: .config),
filterTags: try container.decodeIfPresent([String].self, forKey: .filterTags),
ownCapabilities: try container.decodeIfPresent([String].self, forKey: .ownCapabilities),
isDisabled: try container.decode(Bool.self, forKey: .disabled),
isFrozen: try container.decode(Bool.self, forKey: .frozen),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,16 +253,18 @@
/// - team: New team.
/// - members: New members.
/// - invites: New invites.
/// - filterTags: A list of tags to add to the channel.
/// - extraData: New `ExtraData`.
/// - completion: The completion. Will be called on a **callbackQueue** when the network request is finished.
/// If request fails, the completion will be called with an error.
///
public func updateChannel(

Check warning on line 261 in Sources/StreamChat/Controllers/ChannelController/ChannelController.swift

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Function has 8 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-chat-swift&issues=AZrZQ8QMx5NRFfrnljy0&open=AZrZQ8QMx5NRFfrnljy0&pullRequest=3886
name: String?,
imageURL: URL?,
team: String?,
members: Set<UserId> = [],
invites: Set<UserId> = [],
filterTags: Set<String> = [],
extraData: [String: RawJSON] = [:],
completion: ((Error?) -> Void)? = nil
) {
Expand All @@ -279,6 +281,7 @@
team: team,
members: members,
invites: invites,
filterTags: filterTags,
extraData: extraData
)

Expand All @@ -295,6 +298,7 @@
/// - team: New team.
/// - members: New members.
/// - invites: New invites.
/// - filterTags: A list of tags to add to the channel.
/// - extraData: New `ExtraData`.
/// - unsetProperties: Properties from the channel that are going to be cleared/unset.
/// - completion: The completion. Will be called on a **callbackQueue** when the network request is finished.
Expand All @@ -306,6 +310,7 @@
team: String? = nil,
members: Set<UserId> = [],
invites: Set<UserId> = [],
filterTags: Set<String> = [],
extraData: [String: RawJSON] = [:],
unsetProperties: [String] = [],
completion: ((Error?) -> Void)? = nil
Expand All @@ -323,6 +328,7 @@
team: team,
members: members,
invites: invites,
filterTags: filterTags,
extraData: extraData
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public extension ChatClient {
/// - isCurrentUserMember: If set to `true` the current user will be included into the channel. Is `true` by default.
/// - messageOrdering: Describes the ordering the messages are presented.
/// - invites: IDs for the new channel invitees.
/// - filterTags: A list of tags to add to the channel.
/// - extraData: Extra data for the new channel.
/// - channelListQuery: The channel list query the channel this controller represents is part of.
/// - Throws: `ClientError.CurrentUserDoesNotExist` if there is no currently logged-in user.
Expand All @@ -78,6 +79,7 @@ public extension ChatClient {
isCurrentUserMember: Bool = true,
messageOrdering: MessageOrdering = .topToBottom,
invites: Set<UserId> = [],
filterTags: Set<String> = [],
extraData: [String: RawJSON] = [:],
channelListQuery: ChannelListQuery? = nil
) throws -> ChatChannelController {
Expand All @@ -92,6 +94,7 @@ public extension ChatClient {
team: team,
members: members.union(isCurrentUserMember ? [currentUserId] : []),
invites: invites,
filterTags: filterTags,
extraData: extraData
)

Expand Down Expand Up @@ -119,6 +122,7 @@ public extension ChatClient {
/// - name: The new channel name.
/// - imageURL: The new channel avatar URL.
/// - team: Team for the new channel.
/// - filterTags: A list of tags to add to the channel.
/// - extraData: Extra data for the new channel.
/// - channelListQuery: The channel list query the channel this controller represents is part of.
///
Expand All @@ -134,6 +138,7 @@ public extension ChatClient {
name: String? = nil,
imageURL: URL? = nil,
team: String? = nil,
filterTags: Set<String> = [],
extraData: [String: RawJSON],
channelListQuery: ChannelListQuery? = nil
) throws -> ChatChannelController {
Expand All @@ -147,6 +152,7 @@ public extension ChatClient {
team: team,
members: members.union(isCurrentUserMember ? [currentUserId] : []),
invites: [],
filterTags: filterTags,
extraData: extraData
)
return .init(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,7 @@ public class LivestreamChannelController: DataStoreProvider, EventsControllerDel
isHidden: event.channel.isHidden,
createdBy: event.channel.createdBy,
config: event.channel.config,
filterTags: event.channel.filterTags,
ownCapabilities: event.channel.ownCapabilities,
isFrozen: event.channel.isFrozen,
isDisabled: event.channel.isDisabled,
Expand Down
5 changes: 5 additions & 0 deletions Sources/StreamChat/Database/DTOs/ChannelDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class ChannelDTO: NSManagedObject {
@NSManaged var typeRawValue: String
@NSManaged var extraData: Data
@NSManaged var config: ChannelConfigDTO
@NSManaged var filterTags: [String]
@NSManaged var ownCapabilities: [String]

@NSManaged var createdAt: DBDate
Expand Down Expand Up @@ -255,6 +256,9 @@ extension NSManagedObjectContext {
dto.typeRawValue = payload.typeRawValue
dto.id = payload.cid.id
dto.config = payload.config.asDTO(context: self, cid: dto.cid)
if let filterTags = payload.filterTags {
dto.filterTags = filterTags
}
if let ownCapabilities = payload.ownCapabilities {
dto.ownCapabilities = ownCapabilities
}
Expand Down Expand Up @@ -645,6 +649,7 @@ extension ChatChannel {
isHidden: dto.isHidden,
createdBy: dto.createdBy?.asModel(),
config: dto.config.asModel(),
filterTags: Set(dto.filterTags),
ownCapabilities: Set(dto.ownCapabilities.compactMap(ChannelCapability.init(rawValue:))),
isFrozen: dto.isFrozen,
isDisabled: dto.isDisabled,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="24299" systemVersion="25A362" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="24411" systemVersion="25B78" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AttachmentDTO" representedClassName="AttachmentDTO" syncable="YES">
<attribute name="data" attributeType="Binary"/>
<attribute name="id" attributeType="String"/>
Expand Down Expand Up @@ -47,6 +47,7 @@
<attribute name="defaultSortingAt" attributeType="Date" usesScalarValueType="NO" spotlightIndexingEnabled="YES"/>
<attribute name="deletedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="extraData" attributeType="Binary"/>
<attribute name="filterTags" optional="YES" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromDataTransformer"/>
<attribute name="hasUnreadSorting" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="String"/>
<attribute name="imageURL" optional="YES" attributeType="URI"/>
Expand Down
9 changes: 9 additions & 0 deletions Sources/StreamChat/Models/Channel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public struct ChatChannel {
/// A configuration struct of the channel. It contains additional information about the channel settings.
public let config: ChannelConfig

/// The list of tags associated with the channel.
public let filterTags: Set<String>

/// The list of actions that the current user can perform in a channel.
public let ownCapabilities: Set<ChannelCapability>

Expand Down Expand Up @@ -192,6 +195,7 @@ public struct ChatChannel {
isHidden: Bool,
createdBy: ChatUser? = nil,
config: ChannelConfig = .init(),
filterTags: Set<String> = [],
ownCapabilities: Set<ChannelCapability> = [],
isFrozen: Bool = false,
isDisabled: Bool = false,
Expand Down Expand Up @@ -228,6 +232,7 @@ public struct ChatChannel {
self.isHidden = isHidden
self.createdBy = createdBy
self.config = config
self.filterTags = filterTags
self.ownCapabilities = ownCapabilities
self.isFrozen = isFrozen
self.isDisabled = isDisabled
Expand Down Expand Up @@ -274,6 +279,7 @@ public struct ChatChannel {
isHidden: isHidden,
createdBy: createdBy,
config: config,
filterTags: filterTags,
ownCapabilities: ownCapabilities,
isFrozen: isFrozen,
isDisabled: isDisabled,
Expand Down Expand Up @@ -313,6 +319,7 @@ public struct ChatChannel {
isHidden: Bool? = nil,
createdBy: ChatUser? = nil,
config: ChannelConfig? = nil,
filterTags: Set<String>? = nil,
ownCapabilities: Set<ChannelCapability>? = nil,
isFrozen: Bool? = nil,
isDisabled: Bool? = nil,
Expand Down Expand Up @@ -341,6 +348,7 @@ public struct ChatChannel {
isHidden: isHidden ?? self.isHidden,
createdBy: createdBy ?? self.createdBy,
config: config ?? self.config,
filterTags: filterTags ?? self.filterTags,
ownCapabilities: ownCapabilities ?? self.ownCapabilities,
isFrozen: isFrozen ?? self.isFrozen,
isDisabled: isDisabled ?? self.isDisabled,
Expand Down Expand Up @@ -452,6 +460,7 @@ extension ChatChannel: Hashable {
guard lhs.membership == rhs.membership else { return false }
guard lhs.team == rhs.team else { return false }
guard lhs.truncatedAt == rhs.truncatedAt else { return false }
guard lhs.filterTags == rhs.filterTags else { return false }
guard lhs.ownCapabilities == rhs.ownCapabilities else { return false }
guard lhs.draftMessage == rhs.draftMessage else { return false }
guard lhs.activeLiveLocations.count == rhs.activeLiveLocations.count else { return false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ extension ChannelPayload {
unreadCount: ChannelUnreadCount?
) -> ChatChannel {
let channelPayload = channel

// Map members
let mappedMembers = members.compactMap { $0.asModel(channelId: channelPayload.cid) }

// Map latest messages
let reads = channelReads.map { $0.asModel() }
let latestMessages = messages.compactMap {
$0.asModel(cid: channel.cid, currentUserId: currentUserId, channelReads: reads)
}

// Map reads
let mappedReads = channelReads.map { $0.asModel() }

// Map watchers
let mappedWatchers = watchers?.map { $0.asModel() } ?? []

return ChatChannel(
cid: channelPayload.cid,
name: channelPayload.name,
Expand All @@ -41,6 +41,7 @@ extension ChannelPayload {
isHidden: isHidden ?? false,
createdBy: channelPayload.createdBy?.asModel(),
config: channelPayload.config,
filterTags: Set(channelPayload.filterTags ?? []),
ownCapabilities: Set(channelPayload.ownCapabilities?.compactMap { ChannelCapability(rawValue: $0) } ?? []),
isFrozen: channelPayload.isFrozen,
isDisabled: channelPayload.isDisabled,
Expand Down
Loading
Loading