Skip to content

Commit

Permalink
Add archive and unarchive actions. Add predefined channel queries and…
Browse files Browse the repository at this point in the history
… action sheet for selecting different queries
  • Loading branch information
laevandus committed Dec 9, 2024
1 parent daca6ea commit 0ff7bf6
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 38 deletions.
File renamed without changes.
File renamed without changes.
26 changes: 26 additions & 0 deletions DemoAppSwiftUI/ChannelHeader/ChannelListQueryIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Copyright © 2024 Stream.io Inc. All rights reserved.
//

import Foundation
import StreamChat

enum ChannelListQueryIdentifier: String, CaseIterable, Identifiable {
case initial
case archived
case pinned
case unarchivedAndPinnedSorted

var id: String {
rawValue
}

var title: String {
switch self {
case .initial: "Initial Channels"
case .archived: "Archived Channels"
case .pinned: "Pinned Channels"
case .unarchivedAndPinnedSorted: "Sort by Pinned and Ignore Archived Channels"
}
}
}
21 changes: 21 additions & 0 deletions DemoAppSwiftUI/ChannelHeader/ChooseChannelQueryView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Copyright © 2024 Stream.io Inc. All rights reserved.
//

import StreamChat
import StreamChatSwiftUI
import SwiftUI

struct ChooseChannelQueryView: View {
static let queryIdentifiers = ChannelListQueryIdentifier.allCases.sorted(using: KeyPathComparator(\.title))

var body: some View {
ForEach(Self.queryIdentifiers) { queryIdentifier in
Button {
AppState.shared.setChannelQueryIdentifier(queryIdentifier)
} label: {
Text(queryIdentifier.title)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier {

var title: String

@State var isChooseChannelQueryShown = false
@State var isNewChatShown = false
@State var logoutAlertShown = false
@State var actionsPopupShown = false
Expand Down Expand Up @@ -99,18 +100,26 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier {
)
}
.confirmationDialog("", isPresented: $actionsPopupShown) {
Button("Blocked users") {
Button("Choose Channel Query") {
isChooseChannelQueryShown = true
}
Button("Show Blocked Users") {
blockedUsersShown = true
}

Button("Logout") {
Button("Logout", role: .destructive) {
logoutAlertShown = true
}

Button("Cancel", role: .cancel) {}
} message: {
Text("Select an action")
}
.confirmationDialog("", isPresented: $isChooseChannelQueryShown) {
ChooseChannelQueryView()
} message: {
Text("Choose a channel query")
}
}
}
}
File renamed without changes.
File renamed without changes.
116 changes: 85 additions & 31 deletions DemoAppSwiftUI/DemoAppSwiftUIApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright © 2024 Stream.io Inc. All rights reserved.
//

import Combine
import StreamChat
import StreamChatSwiftUI
import SwiftUI
Expand Down Expand Up @@ -39,25 +40,11 @@ struct DemoAppSwiftUIApp: App {
.tabItem { Label("Threads", systemImage: "text.bubble") }
.badge(appState.unreadCount.threads)
}
.id(appState.contentIdentifier)
}
}
.onChange(of: appState.userState) { newValue in
if newValue == .loggedIn {
/*
if let currentUserId = chatClient.currentUserId {
let pinnedByKey = ChatChannel.isPinnedBy(keyForUserId: currentUserId)
let channelListQuery = ChannelListQuery(
filter: .containMembers(userIds: [currentUserId]),
sort: [
.init(key: .custom(keyPath: \.isPinned, key: pinnedByKey), isAscending: true),
.init(key: .lastMessageAt),
.init(key: .updatedAt)
]
)
appState.channelListController = chatClient.channelListController(query: channelListQuery)
}
*/
appState.currentUserController = chatClient.currentUserController()
notificationsHandler.setupRemoteNotifications()
}
}
Expand Down Expand Up @@ -86,28 +73,55 @@ struct DemoAppSwiftUIApp: App {
}

class AppState: ObservableObject, CurrentChatUserControllerDelegate {
@Injected(\.chatClient) var chatClient: ChatClient

@Published var userState: UserState = .launchAnimation {
willSet {
if newValue == .notLoggedIn && userState == .loggedIn {
channelListController = nil
}
}
}

// Recreate the content view when channel query changes.
@Published private(set) var contentIdentifier: String = ""

@Published var userState: UserState = .launchAnimation
@Published var unreadCount: UnreadCount = .noUnread

var channelListController: ChatChannelListController?
var currentUserController: CurrentChatUserController? {
didSet {
currentUserController?.delegate = self
currentUserController?.synchronize()
}
}
private(set) var channelListController: ChatChannelListController?
private(set) var currentUserController: CurrentChatUserController?
private var cancellables = Set<AnyCancellable>()

static let shared = AppState()

private init() {}
private init() {
$userState
.removeDuplicates()
.filter { $0 == .notLoggedIn }
.sink { [weak self] _ in
self?.didLogout()
}
.store(in: &cancellables)
$userState
.removeDuplicates()
.filter { $0 == .loggedIn }
.sink { [weak self] _ in
self?.didLogin()
}
.store(in: &cancellables)
}

private func didLogout() {
channelListController = nil
currentUserController = nil
}

private func didLogin() {
setChannelQueryIdentifier(.initial)

currentUserController = chatClient.currentUserController()
currentUserController?.delegate = self
currentUserController?.synchronize()
}

func setChannelQueryIdentifier(_ identifier: ChannelListQueryIdentifier) {
let query = AppState.channelListQuery(forIdentifier: identifier, chatClient: chatClient)
channelListController = chatClient.channelListController(query: query)
contentIdentifier = identifier.rawValue
}

func currentUserController(_ controller: CurrentChatUserController, didChangeCurrentUserUnreadCount: UnreadCount) {
unreadCount = didChangeCurrentUserUnreadCount
Expand All @@ -125,3 +139,43 @@ enum UserState {
case notLoggedIn
case loggedIn
}

extension AppState {
private static func channelListQuery(
forIdentifier identifier: ChannelListQueryIdentifier,
chatClient: ChatClient
) -> ChannelListQuery {
guard let currentUserId = chatClient.currentUserId else { fatalError("Not logged in") }
switch identifier {
case .initial:
return ChannelListQuery(
filter: .containMembers(userIds: [currentUserId])
)
case .unarchivedAndPinnedSorted:
return ChannelListQuery(
filter: .and([
.containMembers(userIds: [currentUserId]),
.equal(.archived, to: false)
]),
sort: [
.init(key: .pinnedAt, isAscending: false),
.init(key: .default)
]
)
case .archived:
return ChannelListQuery(
filter: .and([
.containMembers(userIds: [currentUserId]),
.equal(.archived, to: true)
])
)
case .pinned:
return ChannelListQuery(
filter: .and([
.containMembers(userIds: [currentUserId]),
.equal(.pinned, to: true)
])
)
}
}
}
36 changes: 36 additions & 0 deletions DemoAppSwiftUI/ViewFactoryExamples.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class DemoAppFactory: ViewFactory {
onDismiss: onDismiss,
onError: onError
)
let archiveChannel = archiveChannelAction(for: channel, onDismiss: onDismiss, onError: onError)
let pinChannel = pinChannelAction(for: channel, onDismiss: onDismiss, onError: onError)
actions.insert(archiveChannel, at: actions.count - 2)
actions.insert(pinChannel, at: actions.count - 2)
return actions
}
Expand Down Expand Up @@ -76,6 +78,40 @@ class DemoAppFactory: ViewFactory {
ShowProfileModifier(messageModifierInfo: messageModifierInfo, mentionsHandler: mentionsHandler)
}

private func archiveChannelAction(
for channel: ChatChannel,
onDismiss: @escaping () -> Void,
onError: @escaping (Error) -> Void
) -> ChannelAction {
ChannelAction(
title: channel.isArchived ? "Unarchive Channel" : "Archive Channel",
iconName: "archivebox",
action: { [weak self] in
guard let self else { return }
let channelController = self.chatClient.channelController(for: channel.cid)
if channel.isArchived {
channelController.unarchive { error in
if let error = error {
onError(error)
} else {
onDismiss()
}
}
} else {
channelController.archive { error in
if let error = error {
onError(error)
} else {
onDismiss()
}
}
}
},
confirmationPopup: nil,
isDestructive: false
)
}

private func pinChannelAction(
for channel: ChatChannel,
onDismiss: @escaping () -> Void,
Expand Down
26 changes: 21 additions & 5 deletions StreamChatSwiftUI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
402C54492B6AAC0100672BFB /* StreamChatSwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8465FBB52746873A00AF091E /* StreamChatSwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4F077EF82C85E05700F06D83 /* DelayedRenderingViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F077EF72C85E05700F06D83 /* DelayedRenderingViewModifier.swift */; };
4F198FDD2C0480EC00148F49 /* Publisher+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F198FDC2C0480EC00148F49 /* Publisher+Extensions.swift */; };
4F65F1862D06EEA7009F69A8 /* ChooseChannelQueryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F65F1852D06EEA5009F69A8 /* ChooseChannelQueryView.swift */; };
4F65F18A2D071798009F69A8 /* ChannelListQueryIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F65F1892D071798009F69A8 /* ChannelListQueryIdentifier.swift */; };
4F6D83352C0F05040098C298 /* PollCommentsViewModel_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6D83342C0F05040098C298 /* PollCommentsViewModel_Tests.swift */; };
4F6D83512C1079A00098C298 /* AlertBannerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6D83502C1079A00098C298 /* AlertBannerViewModifier.swift */; };
4F6D83542C1094220098C298 /* AlertBannerViewModifier_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6D83532C1094220098C298 /* AlertBannerViewModifier_Tests.swift */; };
Expand Down Expand Up @@ -597,6 +599,8 @@
4A65451E274BA170003C5FA8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
4F077EF72C85E05700F06D83 /* DelayedRenderingViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelayedRenderingViewModifier.swift; sourceTree = "<group>"; };
4F198FDC2C0480EC00148F49 /* Publisher+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher+Extensions.swift"; sourceTree = "<group>"; };
4F65F1852D06EEA5009F69A8 /* ChooseChannelQueryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseChannelQueryView.swift; sourceTree = "<group>"; };
4F65F1892D071798009F69A8 /* ChannelListQueryIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListQueryIdentifier.swift; sourceTree = "<group>"; };
4F6D83342C0F05040098C298 /* PollCommentsViewModel_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollCommentsViewModel_Tests.swift; sourceTree = "<group>"; };
4F6D83502C1079A00098C298 /* AlertBannerViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertBannerViewModifier.swift; sourceTree = "<group>"; };
4F6D83532C1094220098C298 /* AlertBannerViewModifier_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertBannerViewModifier_Tests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1169,6 +1173,20 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
4F65F18B2D0724F3009F69A8 /* ChannelHeader */ = {
isa = PBXGroup;
children = (
846B8E2B2C5B8117006A6249 /* BlockedUsersView.swift */,
846B8E2D2C5B8130006A6249 /* BlockedUsersViewModel.swift */,
4F65F1892D071798009F69A8 /* ChannelListQueryIdentifier.swift */,
4F65F1852D06EEA5009F69A8 /* ChooseChannelQueryView.swift */,
8465FCD7274694D200AF091E /* CustomChannelHeader.swift */,
84335015274BABF3007A1B81 /* NewChatView.swift */,
84335017274BAD4B007A1B81 /* NewChatViewModel.swift */,
);
path = ChannelHeader;
sourceTree = "<group>";
};
4F6D83522C108D470098C298 /* CommonViews */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1595,20 +1613,18 @@
8465FCBD27468B6900AF091E /* DemoAppSwiftUI */ = {
isa = PBXGroup;
children = (
4F65F18B2D0724F3009F69A8 /* ChannelHeader */,
8492974727ABD97F00A8EEB0 /* DemoAppSwiftUI.entitlements */,
8465FCBE27468B6900AF091E /* DemoAppSwiftUIApp.swift */,
8465FCD3274694D200AF091E /* AppDelegate.swift */,
8465FCD6274694D200AF091E /* CustomAttachment.swift */,
8465FCD7274694D200AF091E /* CustomChannelHeader.swift */,
8492974827ABDDBF00A8EEB0 /* NotificationsHandler.swift */,
8465FCD4274694D200AF091E /* DemoUser.swift */,
8465FCD2274694D200AF091E /* LaunchAnimationState.swift */,
8465FCD1274694D200AF091E /* LaunchScreen.swift */,
8465FCD5274694D200AF091E /* SceneDelegate.swift */,
84B288D2274D23AF00DD090B /* LoginView.swift */,
84B288D4274D286500DD090B /* LoginViewModel.swift */,
84335015274BABF3007A1B81 /* NewChatView.swift */,
84335017274BAD4B007A1B81 /* NewChatViewModel.swift */,
84B288CC274C544B00DD090B /* CreateGroupView.swift */,
84B288D0274CEDD000DD090B /* GroupNameView.swift */,
84B288CE274C545900DD090B /* CreateGroupViewModel.swift */,
Expand All @@ -1619,8 +1635,6 @@
8451617F2AE7C4E2000A9230 /* WhatsAppChannelHeader.swift */,
8417AE912ADEDB6400445021 /* UserRepository.swift */,
8413C4542B4409B600190AF4 /* PinChannelHelpers.swift */,
846B8E2B2C5B8117006A6249 /* BlockedUsersView.swift */,
846B8E2D2C5B8130006A6249 /* BlockedUsersViewModel.swift */,
84EDBC36274FE5CD0057218D /* Localizable.strings */,
8465FCCA27468B7500AF091E /* Info.plist */,
8465FCC227468B6A00AF091E /* Assets.xcassets */,
Expand Down Expand Up @@ -3036,6 +3050,7 @@
845161802AE7C4E2000A9230 /* WhatsAppChannelHeader.swift in Sources */,
8465FCDC274694D200AF091E /* SceneDelegate.swift in Sources */,
8465FCD9274694D200AF091E /* LaunchAnimationState.swift in Sources */,
4F65F18A2D071798009F69A8 /* ChannelListQueryIdentifier.swift in Sources */,
84B288D1274CEDD000DD090B /* GroupNameView.swift in Sources */,
84335014274BAB15007A1B81 /* ViewFactoryExamples.swift in Sources */,
8465FCDE274694D200AF091E /* CustomChannelHeader.swift in Sources */,
Expand All @@ -3048,6 +3063,7 @@
8465FCDB274694D200AF091E /* DemoUser.swift in Sources */,
8465FCDD274694D200AF091E /* CustomAttachment.swift in Sources */,
8492974B27ABDDCB00A8EEB0 /* NotificationsHandler.swift in Sources */,
4F65F1862D06EEA7009F69A8 /* ChooseChannelQueryView.swift in Sources */,
8465FCDA274694D200AF091E /* AppDelegate.swift in Sources */,
8465FCD8274694D200AF091E /* LaunchScreen.swift in Sources */,
84B288CF274C545900DD090B /* CreateGroupViewModel.swift in Sources */,
Expand Down

0 comments on commit 0ff7bf6

Please sign in to comment.