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

How to update ChannelListView with a query? #586

Closed
hyqshr opened this issue Aug 19, 2024 · 3 comments
Closed

How to update ChannelListView with a query? #586

hyqshr opened this issue Aug 19, 2024 · 3 comments

Comments

@hyqshr
Copy link

hyqshr commented Aug 19, 2024

What did you do?

I try to build a chat type filter so user click each type picker and I can update ChannelListView with the query result.

image

I tried to build a dynamic controller and pass to ChatChannelListView:

struct ConversationView: View {
    @EnvironmentObject var userViewModel: UserViewModel
    @State private var showSelectSheet = false
    @State private var selectedChatType: String = "Team" // Add a state for the selected chat type
    @Injected(\.chatClient) private var chatClient: ChatClient // Inject chatClient

    var body: some View {
        VStack {
            ChatChannelListView(
                viewFactory: CustomChatUIFactory(userViewModel: userViewModel, selectedChatType: $selectedChatType),
                channelListController: makeCustomChannelListController(for: selectedChatType) // Pass the dynamic controller
            )
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button(action: {
                    showSelectSheet = true
                }) {
                    Image(systemName: "plus.circle")
                        .foregroundColor(.primary)
                }
            }
        }
        .sheet(isPresented: $showSelectSheet) {
            SelectChatMembersView()
        }
    }
    
    private func makeCustomChannelListController(for chatType: String) -> ChatChannelListController {
        let filter: Filter<ChannelListFilterScope>
        switch chatType {
        case "Team":
            filter = .and([.equal(.type, to: .team), .containMembers(userIds: [chatClient.currentUserId!])])
        case "Tenants":
            filter = .equal(.type, to: .custom("tenant")) // Assuming "tenant" is a custom channel type
        case "Applicants":
            filter = .equal(.type, to: .custom("applicant")) // Assuming "applicant" is a custom channel type
        default:
            filter = .containMembers(userIds: [chatClient.currentUserId ?? ""])
        }

        let controller = chatClient.channelListController(
            query: .init(
                filter: filter,
                sort: [.init(key: .lastMessageAt, isAscending: true)],
                pageSize: 10
            )
        )
        print("Selected Chat Type: \(chatType)")
        print("Controller: \(controller)")
        print("Count \(controller.channels.count)")
      
        return controller
    }
}

What did you expect to happen?

The ChannelListView correctly updated when user tap the picker.

What happened instead?

The screen freeze after tap the filter, can not open any chat afterward.

GetStream Environment

**GetStream Chat version:4.60.0
GetStream Chat frameworks: StreamChat, StreamChatSwiftUI
iOS version:
Swift version:
**Xcode version:15.4
**Device:Simulator iPhone 15 Pro

Additional context

@martinmitrevski
Copy link
Contributor

Hi @hyqshr,

Seems like you are not storing the created controllers anywhere - they are re-created every time your view's body is being re-evaluated, thus causing issues. If it's already created once, you should reuse it, e.g. keep it as a State, or somewhere outside the view.

Additionally, if you filter by custom data, you should also provide a filter block, as described here: https://getstream.io/chat/docs/sdk/ios/client/controllers/channels/#filtering-with-extra-data.

Hope that helps,
Martin

@hyqshr
Copy link
Author

hyqshr commented Aug 19, 2024

Hi @martinmitrevski ,

Thank you for your help. I tried to create different controllers outside of the view like:

class DependencyContainer {
    @Injected(\.chatClient) var chatClient: ChatClient
}

let dependencies = DependencyContainer()

let allChannelListController: ChatChannelListController = {
    let controller = dependencies.chatClient.channelListController(
        query: .init(
            filter: .containMembers(userIds: [dependencies.chatClient.currentUserId ?? ""])
        )
    )
    print("$$ \(controller.channels.count) ALL")
    return controller
}()

let teamChannelListController: ChatChannelListController = {
    let controller = dependencies.chatClient.channelListController(
        query: .init(
            filter: .and([.equal(.type, to: .team), .containMembers(userIds: [dependencies.chatClient.currentUserId!])])
        )
    )
    print("$$ \(controller.channels.count) TEAM")
    return controller
}()

And then in chat view, I re-use the created controller based on type selection:

struct ConversationView: View {
    @EnvironmentObject var userViewModel: UserViewModel
    @State private var showSelectSheet = false
    @State private var selectedChatType: String = "All"
    
    var body: some View {
        VStack {
            ChatChannelListView(
                viewFactory: CustomChatUIFactory(userViewModel: userViewModel, selectedChatType: $selectedChatType),
                channelListController: channelListController(for: selectedChatType)
            )
        }
.....
    }

    private func channelListController(for chatType: String) -> ChatChannelListController {
        switch chatType {
        case "Team":
            return teamChannelListController
        default:
            return allChannelListController
        }
    }
}

It still doesn't work, the channels list will be unclickable and the filter query is not working.

Also when I try do ChatClient.shared.channelListController like the doc you suggested, it throw error:

Value of type 'ChatClient' has no member 'shared

https://getstream.io/chat/docs/sdk/ios/client/controllers/channels/#filtering-with-extra-data

@vojtabohm
Copy link

@martinmitrevski Does this imply that for each filter you have inside the app (e.g. Unread, Group Chats, Teams) you should have a matching controller? Therefore if you have 5 filters in total, you should have 5 different controllers?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants