Skip to content

Commit 4e13e10

Browse files
Added blocked users example in the demo app (#571)
1 parent 42f5672 commit 4e13e10

File tree

5 files changed

+134
-7
lines changed

5 files changed

+134
-7
lines changed

DemoAppSwiftUI/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
6363
#endif
6464

6565
let utils = Utils(
66-
messageListConfig: MessageListConfig(dateIndicatorPlacement: .messageList),
66+
messageListConfig: MessageListConfig(dateIndicatorPlacement: .messageList, userBlockingEnabled: true),
6767
composerConfig: ComposerConfig(isVoiceRecordingEnabled: true)
6868
)
6969
streamChat = StreamChat(chatClient: chatClient, utils: utils)

DemoAppSwiftUI/BlockedUsersView.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Copyright © 2024 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import StreamChatSwiftUI
6+
import SwiftUI
7+
8+
struct BlockedUsersView: View {
9+
10+
@StateObject var viewModel = BlockedUsersViewModel()
11+
12+
var body: some View {
13+
ZStack {
14+
if !viewModel.blockedUsers.isEmpty {
15+
List {
16+
ForEach(viewModel.blockedUsers) { blockedUser in
17+
HStack {
18+
MessageAvatarView(avatarURL: blockedUser.imageURL, size: .init(width: 48, height: 48))
19+
Text(blockedUser.name ?? blockedUser.id)
20+
.font(.headline)
21+
Spacer()
22+
}
23+
.listRowSeparator(.hidden)
24+
}
25+
.onDelete(perform: delete)
26+
}
27+
.toolbar {
28+
EditButton()
29+
}
30+
.listStyle(.plain)
31+
} else {
32+
VStack {
33+
Text("There are currently no blocked users.")
34+
.padding()
35+
Spacer()
36+
}
37+
}
38+
}
39+
.onAppear {
40+
viewModel.loadBlockedUsers()
41+
}
42+
.navigationTitle("Blocked Users")
43+
}
44+
45+
func delete(at offsets: IndexSet) {
46+
if let first = offsets.first, first < viewModel.blockedUsers.count {
47+
viewModel.unblock(user: viewModel.blockedUsers[first])
48+
}
49+
}
50+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Copyright © 2024 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import StreamChat
6+
import StreamChatSwiftUI
7+
import SwiftUI
8+
9+
class BlockedUsersViewModel: ObservableObject {
10+
11+
@Injected(\.chatClient) var chatClient
12+
13+
@Published var blockedUsers = [ChatUser]()
14+
15+
private let currentUserController: CurrentChatUserController
16+
17+
init() {
18+
currentUserController = InjectedValues[\.chatClient].currentUserController()
19+
currentUserController.synchronize()
20+
}
21+
22+
func loadBlockedUsers() {
23+
let blockedUserIds = currentUserController.currentUser?.blockedUserIds ?? []
24+
for blockedUserId in blockedUserIds {
25+
if let user = currentUserController.dataStore.user(id: blockedUserId) {
26+
blockedUsers.append(user)
27+
} else {
28+
let controller = chatClient.userController(userId: blockedUserId)
29+
controller.synchronize { [weak self] _ in
30+
if let user = controller.user {
31+
self?.blockedUsers.append(user)
32+
}
33+
}
34+
}
35+
}
36+
}
37+
38+
func unblock(user: ChatUser) {
39+
let unblockController = chatClient.userController(userId: user.id)
40+
unblockController.unblock { [weak self] error in
41+
if error == nil {
42+
self?.blockedUsers.removeAll { blocked in
43+
blocked.id == user.id
44+
}
45+
}
46+
}
47+
}
48+
}

DemoAppSwiftUI/CustomChannelHeader.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public struct CustomChannelHeader: ToolbarContent {
1515
var title: String
1616
var currentUserController: CurrentChatUserController
1717
@Binding var isNewChatShown: Bool
18-
@Binding var logoutAlertShown: Bool
18+
@Binding var actionsPopupShown: Bool
1919

2020
@MainActor
2121
public var body: some ToolbarContent {
@@ -39,7 +39,7 @@ public struct CustomChannelHeader: ToolbarContent {
3939
}
4040
ToolbarItem(placement: .navigationBarLeading) {
4141
Button {
42-
logoutAlertShown = true
42+
actionsPopupShown = true
4343
} label: {
4444
StreamLazyImage(url: currentUserController.currentUser?.imageURL)
4545
}
@@ -55,6 +55,8 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier {
5555

5656
@State var isNewChatShown = false
5757
@State var logoutAlertShown = false
58+
@State var actionsPopupShown = false
59+
@State var blockedUsersShown = false
5860

5961
func body(content: Content) -> some View {
6062
ZStack {
@@ -63,9 +65,15 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier {
6365
title: title,
6466
currentUserController: chatClient.currentUserController(),
6567
isNewChatShown: $isNewChatShown,
66-
logoutAlertShown: $logoutAlertShown
68+
actionsPopupShown: $actionsPopupShown
6769
)
6870
}
71+
72+
NavigationLink(isActive: $blockedUsersShown) {
73+
BlockedUsersView()
74+
} label: {
75+
EmptyView()
76+
}
6977

7078
NavigationLink(isActive: $isNewChatShown) {
7179
NewChatView(isNewChatShown: $isNewChatShown)
@@ -90,6 +98,19 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier {
9098
secondaryButton: .cancel()
9199
)
92100
}
101+
.confirmationDialog("", isPresented: $actionsPopupShown) {
102+
Button("Blocked users") {
103+
blockedUsersShown = true
104+
}
105+
106+
Button("Logout") {
107+
logoutAlertShown = true
108+
}
109+
110+
Button("Cancel", role: .cancel) {}
111+
} message: {
112+
Text("Select an action")
113+
}
93114
}
94115
}
95116
}

StreamChatSwiftUI.xcodeproj/project.pbxproj

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@
322322
846AD4D2284F89B10074A0DD /* StreamChatTestTools in Frameworks */ = {isa = PBXBuildFile; productRef = 846AD4D1284F89B10074A0DD /* StreamChatTestTools */; };
323323
846AD4D4284F95710074A0DD /* CustomChannelHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846AD4D3284F95710074A0DD /* CustomChannelHeader.swift */; };
324324
846B15F42817E7630017F7A1 /* ChatChannelInfoViewModel_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846B15F32817E7630017F7A1 /* ChatChannelInfoViewModel_Tests.swift */; };
325+
846B8E2C2C5B8117006A6249 /* BlockedUsersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846B8E2B2C5B8117006A6249 /* BlockedUsersView.swift */; };
326+
846B8E2E2C5B8130006A6249 /* BlockedUsersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846B8E2D2C5B8130006A6249 /* BlockedUsersViewModel.swift */; };
325327
846D6564279FF0800094B36E /* ReactionUserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846D6563279FF0800094B36E /* ReactionUserView.swift */; };
326328
847110B628611033004A46D6 /* MessageActions_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840008BA27E8D64A00282D88 /* MessageActions_Tests.swift */; };
327329
847305BB28241D8D004AC770 /* ChatChannelHeader_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847305BA28241D8D004AC770 /* ChatChannelHeader_Tests.swift */; };
@@ -885,6 +887,8 @@
885887
8469592E29BB235400134EA0 /* LazyImageExtensions_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyImageExtensions_Tests.swift; sourceTree = "<group>"; };
886888
846AD4D3284F95710074A0DD /* CustomChannelHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomChannelHeader.swift; sourceTree = "<group>"; };
887889
846B15F32817E7630017F7A1 /* ChatChannelInfoViewModel_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatChannelInfoViewModel_Tests.swift; sourceTree = "<group>"; };
890+
846B8E2B2C5B8117006A6249 /* BlockedUsersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersView.swift; sourceTree = "<group>"; };
891+
846B8E2D2C5B8130006A6249 /* BlockedUsersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersViewModel.swift; sourceTree = "<group>"; };
888892
846D6563279FF0800094B36E /* ReactionUserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionUserView.swift; sourceTree = "<group>"; };
889893
847305BA28241D8D004AC770 /* ChatChannelHeader_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatChannelHeader_Tests.swift; sourceTree = "<group>"; };
890894
847305BC28243D25004AC770 /* WebView_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView_Tests.swift; sourceTree = "<group>"; };
@@ -1571,6 +1575,8 @@
15711575
8451617F2AE7C4E2000A9230 /* WhatsAppChannelHeader.swift */,
15721576
8417AE912ADEDB6400445021 /* UserRepository.swift */,
15731577
8413C4542B4409B600190AF4 /* PinChannelHelpers.swift */,
1578+
846B8E2B2C5B8117006A6249 /* BlockedUsersView.swift */,
1579+
846B8E2D2C5B8130006A6249 /* BlockedUsersViewModel.swift */,
15741580
84EDBC36274FE5CD0057218D /* Localizable.strings */,
15751581
8465FCCA27468B7500AF091E /* Info.plist */,
15761582
8465FCC227468B6A00AF091E /* Assets.xcassets */,
@@ -2920,6 +2926,7 @@
29202926
files = (
29212927
8465FDDD2747A14700AF091E /* CustomComposerAttachmentView.swift in Sources */,
29222928
84335016274BABF3007A1B81 /* NewChatView.swift in Sources */,
2929+
846B8E2C2C5B8117006A6249 /* BlockedUsersView.swift in Sources */,
29232930
84335018274BAD4B007A1B81 /* NewChatViewModel.swift in Sources */,
29242931
84B288CD274C544B00DD090B /* CreateGroupView.swift in Sources */,
29252932
845161802AE7C4E2000A9230 /* WhatsAppChannelHeader.swift in Sources */,
@@ -2930,6 +2937,7 @@
29302937
8465FCDE274694D200AF091E /* CustomChannelHeader.swift in Sources */,
29312938
8451617E2AE7B093000A9230 /* AppleMessageComposerView.swift in Sources */,
29322939
8413C4552B4409B600190AF4 /* PinChannelHelpers.swift in Sources */,
2940+
846B8E2E2C5B8130006A6249 /* BlockedUsersViewModel.swift in Sources */,
29332941
84B288D3274D23AF00DD090B /* LoginView.swift in Sources */,
29342942
84B288D5274D286500DD090B /* LoginViewModel.swift in Sources */,
29352943
8465FCBF27468B6900AF091E /* DemoAppSwiftUIApp.swift in Sources */,
@@ -3129,7 +3137,7 @@
31293137
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
31303138
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
31313139
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
3132-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
3140+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
31333141
LD_RUNPATH_SEARCH_PATHS = (
31343142
"$(inherited)",
31353143
"@executable_path/Frameworks",
@@ -3564,7 +3572,7 @@
35643572
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
35653573
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
35663574
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
3567-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
3575+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
35683576
LD_RUNPATH_SEARCH_PATHS = (
35693577
"$(inherited)",
35703578
"@executable_path/Frameworks",
@@ -3599,7 +3607,7 @@
35993607
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
36003608
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
36013609
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
3602-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
3610+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
36033611
LD_RUNPATH_SEARCH_PATHS = (
36043612
"$(inherited)",
36053613
"@executable_path/Frameworks",

0 commit comments

Comments
 (0)