Skip to content

Commit d5aef69

Browse files
Implemented configuring the swipe area of a channel list item
1 parent 5012e07 commit d5aef69

File tree

17 files changed

+561
-145
lines changed

17 files changed

+561
-145
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
### ✅ Added
77
- Image gallery
8+
- Editing messages
9+
- Mentions
10+
- Composer commands
11+
- Configuration of channel item swipe area
12+
13+
### 🔄 Changed
14+
- Creation of channel items
815

916
# [4.6.3](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.6.3)
1017
_December 21, 2021_

DemoAppSwiftUI/iMessagePocView.swift

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//
2+
// Copyright © 2022 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import StreamChat
6+
import StreamChatSwiftUI
7+
import SwiftUI
8+
9+
struct iMessagePocView: View {
10+
11+
@Injected(\.colors) var colors
12+
13+
@StateObject var viewModel: iMessageChatChannelListViewModel
14+
@StateObject private var channelHeaderLoader = ChannelHeaderLoader()
15+
16+
private var factory = iMessageViewFactory.shared
17+
18+
init() {
19+
_viewModel = StateObject(
20+
wrappedValue:
21+
iMessageChatChannelListViewModel(
22+
channelListController: nil,
23+
selectedChannelId: nil
24+
)
25+
)
26+
}
27+
28+
var body: some View {
29+
NavigationView {
30+
VStack {
31+
if !viewModel.pinnedChannels.isEmpty {
32+
ScrollView(.horizontal) {
33+
HStack {
34+
ForEach(viewModel.pinnedChannels) { channel in
35+
ChannelAvatarView(
36+
avatar: channelHeaderLoader.image(for: channel),
37+
showOnlineIndicator: false
38+
)
39+
.padding()
40+
}
41+
}
42+
}
43+
.frame(height: 60)
44+
}
45+
ChannelList(
46+
factory: factory,
47+
channels: viewModel.channels,
48+
selectedChannel: $viewModel.selectedChannel,
49+
currentChannelId: $viewModel.currentChannelId,
50+
onlineIndicatorShown: viewModel.onlineIndicatorShown(for:),
51+
imageLoader: channelHeaderLoader.image(for:),
52+
onItemTap: { channel in
53+
viewModel.selectedChannel = channel
54+
},
55+
onItemAppear: viewModel.checkForChannels(index:),
56+
channelNaming: viewModel.name(forChannel:),
57+
channelDestination: factory.makeChannelDestination(),
58+
trailingSwipeRightButtonTapped: viewModel.onDeleteTapped(channel:),
59+
trailingSwipeLeftButtonTapped: viewModel.onMoreTapped(channel:),
60+
leadingSwipeButtonTapped: viewModel.pinChannelTapped(_:)
61+
)
62+
.alert(isPresented: $viewModel.alertShown) {
63+
switch viewModel.channelAlertType {
64+
case let .deleteChannel(channel):
65+
return Alert(
66+
title: Text("Delete"),
67+
message: Text("Are you sure you want to delete this channel?"),
68+
primaryButton: .destructive(Text("Delete")) {
69+
viewModel.delete(channel: channel)
70+
},
71+
secondaryButton: .cancel()
72+
)
73+
default:
74+
return Alert.defaultErrorAlert
75+
}
76+
}
77+
78+
Spacer()
79+
}
80+
.blur(radius: (viewModel.customAlertShown || viewModel.alertShown) ? 6 : 0)
81+
.overlay(viewModel.customAlertShown ? customViewOverlay() : nil)
82+
.accentColor(colors.tintColor)
83+
.navigationTitle("Messages")
84+
}
85+
}
86+
87+
@ViewBuilder
88+
private func customViewOverlay() -> some View {
89+
switch viewModel.customChannelPopupType {
90+
case let .moreActions(channel):
91+
factory.makeMoreChannelActionsView(for: channel) {
92+
withAnimation {
93+
viewModel.customChannelPopupType = nil
94+
}
95+
} onError: { error in
96+
viewModel.showErrorPopup(error)
97+
}
98+
.edgesIgnoringSafeArea(.all)
99+
default:
100+
EmptyView()
101+
}
102+
}
103+
}
104+
105+
class iMessageChatChannelListViewModel: ChatChannelListViewModel {
106+
107+
@Published var pinnedChannels = [ChatChannel]()
108+
109+
func pinChannelTapped(_ channel: ChatChannel) {
110+
if !pinnedChannels.contains(channel) {
111+
pinnedChannels.append(channel)
112+
}
113+
}
114+
}
115+
116+
class iMessageViewFactory: ViewFactory {
117+
118+
@Injected(\.chatClient) var chatClient
119+
@Injected(\.colors) var colors
120+
121+
static let shared = iMessageViewFactory()
122+
123+
private init() {}
124+
125+
func makeLeadingSwipeActionsView(
126+
channel: ChatChannel,
127+
offsetX: CGFloat,
128+
buttonWidth: CGFloat,
129+
buttonTapped: @escaping (ChatChannel) -> Void
130+
) -> some View {
131+
HStack {
132+
ActionItemButton(imageName: "pin.fill") {
133+
buttonTapped(channel)
134+
}
135+
.frame(width: buttonWidth)
136+
.foregroundColor(Color.white)
137+
.background(Color.yellow)
138+
139+
Spacer()
140+
}
141+
}
142+
}

Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright © 2021 Stream.io Inc. All rights reserved.
2+
// Copyright © 2022 Stream.io Inc. All rights reserved.
33
//
44

55
import Combine
@@ -8,7 +8,7 @@ import StreamChat
88
import SwiftUI
99

1010
/// View model for the `ChatChannelView`.
11-
public class ChatChannelViewModel: ObservableObject, MessagesDataSource {
11+
open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
1212

1313
@Injected(\.chatClient) private var chatClient
1414
@Injected(\.utils) private var utils
@@ -42,15 +42,15 @@ public class ChatChannelViewModel: ObservableObject, MessagesDataSource {
4242
@Atomic private var loadingPreviousMessages: Bool = false
4343
@Atomic private var lastMessageRead: String?
4444

45-
var channelController: ChatChannelController
46-
var messageController: ChatMessageController?
45+
public var channelController: ChatChannelController
46+
public var messageController: ChatMessageController?
4747

48-
@Published var scrolledId: String?
49-
@Published var listId = UUID().uuidString
48+
@Published public var scrolledId: String?
49+
@Published public var listId = UUID().uuidString
5050

51-
@Published var showScrollToLatestButton = false
52-
@Published var currentDateString: String?
53-
@Published var messages = LazyCachedMapCollection<ChatMessage>() {
51+
@Published public var showScrollToLatestButton = false
52+
@Published public var currentDateString: String?
53+
@Published public var messages = LazyCachedMapCollection<ChatMessage>() {
5454
didSet {
5555
var temp = [String: [String]]()
5656
for (index, message) in messages.enumerated() {
@@ -76,24 +76,24 @@ public class ChatChannelViewModel: ObservableObject, MessagesDataSource {
7676
}
7777
}
7878

79-
@Published var messagesGroupingInfo = [String: [String]]()
80-
@Published var currentSnapshot: UIImage? {
79+
@Published public var messagesGroupingInfo = [String: [String]]()
80+
@Published public var currentSnapshot: UIImage? {
8181
didSet {
8282
withAnimation {
8383
reactionsShown = currentSnapshot != nil
8484
}
8585
}
8686
}
8787

88-
@Published var reactionsShown = false
89-
@Published var quotedMessage: ChatMessage?
90-
@Published var editedMessage: ChatMessage?
88+
@Published public var reactionsShown = false
89+
@Published public var quotedMessage: ChatMessage?
90+
@Published public var editedMessage: ChatMessage?
9191

92-
var channel: ChatChannel {
92+
public var channel: ChatChannel {
9393
channelController.channel!
9494
}
9595

96-
var isMessageThread: Bool {
96+
public var isMessageThread: Bool {
9797
messageController != nil
9898
}
9999

@@ -129,13 +129,13 @@ public class ChatChannelViewModel: ObservableObject, MessagesDataSource {
129129
Nuke.ImageCache.shared.removeAll()
130130
}
131131

132-
func scrollToLastMessage() {
132+
public func scrollToLastMessage() {
133133
if scrolledId != messages.first?.messageId {
134134
scrolledId = messages.first?.messageId
135135
}
136136
}
137137

138-
func handleMessageAppear(index: Int) {
138+
public func handleMessageAppear(index: Int) {
139139
let message = messages[index]
140140
checkForNewMessages(index: index)
141141
save(lastDate: message.createdAt)
@@ -179,7 +179,7 @@ public class ChatChannelViewModel: ObservableObject, MessagesDataSource {
179179
messages = channelController.messages
180180
}
181181

182-
func showReactionOverlay() {
182+
public func showReactionOverlay() {
183183
guard let view: UIView = topVC()?.view else {
184184
currentSnapshot = UIImage(systemName: "photo")
185185
return
@@ -190,20 +190,20 @@ public class ChatChannelViewModel: ObservableObject, MessagesDataSource {
190190
UIGraphicsEndImageContext()
191191
}
192192

193-
func messageActionExecuted(_ messageActionInfo: MessageActionInfo) {
193+
public func messageActionExecuted(_ messageActionInfo: MessageActionInfo) {
194194
utils.messageActionsResolver.resolveMessageAction(
195195
info: messageActionInfo,
196196
viewModel: self
197197
)
198198
}
199199

200-
func onViewAppear() {
200+
public func onViewAppear() {
201201
reactionsShown = false
202202
isActive = true
203203
messages = channelDataSource.messages
204204
}
205205

206-
func onViewDissappear() {
206+
public func onViewDissappear() {
207207
isActive = false
208208
}
209209

0 commit comments

Comments
 (0)