GetStream / stream-chat-swiftui

SwiftUI Chat SDK ➜ Stream Chat 💬
https://getstream.io/chat/sdk/swiftui/
Other
346 stars 86 forks source link

Giphy button disappears from Leading Composer View #261

Closed Subtextaps closed 1 year ago

Subtextaps commented 1 year ago

What did you do?

There seems to be a bug in the Leading Composer View. Prior to 4.25.0 the giphy button was visible in all channels. Now the giphy button sometimes disappears at random when opening channels. I've played with your demo app where some channels show the giphy buttons and others don't. But I can't find anywhere in the code that implies that the message composer should be rendered differently from channel to channel.

I've also tried implementing makeLeadingComposerView in my own code but cannot find any way to set the visibility of the giphy button.

Thanks,

Thomas

What did you expect to happen?

That the giphy button should be visible in the Leading Composer View at all times.

What happened instead?

The giphy button seems to disappear at random when channels are opened.

GetStream Environment

GetStream Chat version: StreamChatSwiftUI 4.25.0 GetStream Chat frameworks: StreamChatSwiftUI 4.25.0 iOS version: 16.2 Swift version: Swift 5 Xcode version: Xcode 14.2 Device: iPhone 11

Additional context

martinmitrevski commented 1 year ago

Hey @Subtextaps,

Thanks for reporting. By default, the visibility of this button is controlled by the channelConfig's commands property, that's controlled from the dashboard. There shouldn't be any changes in this logic in the last 5-6 releases.

For some channels, we have some commands disabled in the demo app. However, does this happen for your channels as well?

If yes, I will check this with our backend team.

Best, Martin

martinmitrevski commented 1 year ago

Additionally, if you want to show it always (regardless of the backend config), just remove the if commandsAvailable check in your custom implementation of AttachmentPickerTypeView (the makeLeadingComposerView method).

Subtextaps commented 1 year ago

Hey @Subtextaps,

Thanks for reporting. By default, the visibility of this button is controlled by the channelConfig's commands property, that's controlled from the dashboard. There shouldn't be any changes in this logic in the last 5-6 releases.

For some channels, we have some commands disabled in the demo app. However, does this happen for your channels as well?

If yes, I will check this with our backend team.

Best, Martin

Hi Martin,

Thank you for the quick reply. The giphy command is enabled for the messaging channel that I've been testing this on. Still the giphy button comes and goes randomly. So I would presume there is a bug as we haven't changed anything on the client-side nor on the backend.

Subtextaps commented 1 year ago

Additionally, if you want to show it always (regardless of the backend config), just remove the if commandsAvailable check in your custom implementation of AttachmentPickerTypeView (the makeLeadingComposerView method).

I'll try this to see if it fixes things.

Thanks,

Thomas

martinmitrevski commented 1 year ago

In any case, the issue is reported to our backend team, as soon as we have more info, we will update you.

Subtextaps commented 1 year ago

Additionally, if you want to show it always (regardless of the backend config), just remove the if commandsAvailable check in your custom implementation of AttachmentPickerTypeView (the makeLeadingComposerView method).

I'll try this to see if it fixes things.

Thanks,

Thomas

Hi @martinmitrevski,

I've tried implementing a custom AttachmentPickerTypeView in the makeLeadingComposerView method as suggested. However it is not being called. There seems to be an issues with the types.

In your documentation (https://getstream.io/chat/docs/sdk/ios/swiftui/chat-channel-components/message-composer/) you show an example where the makeLeadingComposerView returns some View. When I implement this method in my custom ViewFactory it is not called.

Here's the snippet:

public func makeLeadingComposerView(state: Binding, channelConfig: ChannelConfig?) -> some View { CustomAttachmentPickerTypeView( pickerTypeState: state, channelConfig: channelConfig ) }

However if I look at the makeLeadingComposerView in your current SDK it returns LeadingComposerViewType. This method does not accept my custom CustomAttachmentPickerTypeView as it doesn't not return the correct type.

Here's the snippet (which cannot be run as it doesn't return some View):

func makeLeadingComposerView(state: Binding, channelConfig: ChannelConfig?) -> LeadingComposerViewType { CustomAttachmentPickerTypeView( pickerTypeState: state, channelConfig: channelConfig ) }

Am I missing something? Could you please point me in the right direction so that I can test your suggestion properly?

Thanks,

Thomas

martinmitrevski commented 1 year ago

Hey @Subtextaps,

It seems your method signature is not correct. I've tried the following:

class DemoAppFactory: ViewFactory {

    @Injected(\.chatClient) public var chatClient

    private init() {}

    public static let shared = DemoAppFactory()

    func makeLeadingComposerView(state: Binding<PickerTypeState>, channelConfig: ChannelConfig?) -> some View {
        CustomAttachmentPickerTypeView(
            pickerTypeState: state,
            channelConfig: channelConfig
        )
    }

}

struct CustomAttachmentPickerTypeView: View {

    @Binding var pickerTypeState: PickerTypeState
    var channelConfig: ChannelConfig?

    var body: some View {
        Text("custom view")
    }

}

This both compiles and customizes the view. Let me know if it helps.

Best, Martin

Subtextaps commented 1 year ago

Hi Martin,

The makeLeadingComposerView method is still not called when I try to set a breakpoint. All of the other methods in the custom ViewFactory are called as expected when I set breakpoints. Just not the makeLeadingComposerView. But the code compiles just fine.

Below is the complete ViewFactory class. Could you please have a look?

import Foundation import SwiftUI import StreamChat import StreamChatSwiftUI import Resolver

class CustomFactory: ViewFactory {

@StreamChatSwiftUI.Injected(\.chatClient) public var chatClient

private init() {}

// let stringPath = Bundle.main.path(forResource: "Icon2022", ofType: "png")!

public static let shared = CustomFactory()

func makeChannelListHeaderViewModifier(title: String) -> some ChannelListHeaderViewModifier {
        CustomChannelModifier(title: title)
    }

func makeMessageAvatarView(for userDisplayInfo: UserDisplayInfo) -> some View {

    CustomUserAvatar(avatarURL: userDisplayInfo.imageURL)
    }

func makeLoadingView() -> some View {
    VStack {
        Spacer()
    ProgressView()
        Spacer()
    }
}

// These are shown when you swipe left on the channel in the channel list
func supportedMoreChannelActions(for channel: ChatChannel, onDismiss: @escaping () -> Void, onError: @escaping (Error) -> Void) -> [ChannelAction] {
    var defaultActions = ChannelAction.defaultActions(
            for: channel,
               chatClient: self.chatClient,
            onDismiss: onDismiss,
            onError: onError
        )

    defaultActions = []

    let mute = {
        let controller = self.chatClient.channelController(for: channel.cid)
        controller.muteChannel { error in
            if let error = error {
                onError(error)
            } else {
                onDismiss()
            }
        }
    }

    let muteAction = ChannelAction(
        title: "Slå notifikationer fra",
        iconName: "speaker.slash",
        action: mute,
        confirmationPopup: nil,
        isDestructive: false
    )

    let unMute = {
        let controller = self.chatClient.channelController(for: channel.cid)
        controller.unmuteChannel { error in
            if let error = error {
                onError(error)
            } else {
                onDismiss()
            }
        }
    }

    let unMuteAction = ChannelAction(
        title: "Slå notifikationer til",
        iconName: "speaker.wave.1",
        action: unMute,
        confirmationPopup: nil,
        isDestructive: false
    )

    defaultActions.append(muteAction)
    defaultActions.append(unMuteAction)
    return defaultActions

}

// func makeMoreChannelActionsView( // for channel: ChatChannel, // swipedChannelId: Binding<String?>, // onDismiss: @escaping () -> Void, // onError: @escaping (Error) -> Void // ) -> some View { // Text("Test") // }

func makeNoChannelsView() -> some View {
    VStack {
        Text("Ingen chatkanaler at vise")
    }
}

func makeLeadingComposerView(state: Binding<PickerTypeState>, channelConfig: ChannelConfig?) -> some View {
       CustomAttachmentPickerTypeView(
           pickerTypeState: state,
           channelConfig: channelConfig
       )
   }

}

martinmitrevski commented 1 year ago

Hey @Subtextaps,

I'm hitting the breakpoint with this implementation. Could you maybe try cleaning the project + derived data?

Sometimes, when you modify a protocol, Xcode has hard time figuring things out.

Let me know if that helps.

Subtextaps commented 1 year ago

Hey @Subtextaps,

I'm hitting the breakpoint with this implementation. Could you maybe try cleaning the project + derived data?

Sometimes, when you modify a protocol, Xcode has hard time figuring things out.

Let me know if that helps.

This issue was that the PickerState was defined twice in two different files. Somehow the compiler didn't register that. Now the makeLeadingComposerView method is called.

Back to the issue with the giphy button:)

I've tried removing the ifCommandsAvailable check. This helps as the giphy button is now visible. But nothing happens when I tap it. Commands are enabled in the Dashboard for the channel type (Messaging) and giphy is added in the Commands field. However there seems to be no issue with the Livestream channel type which also has the giphy command enabled. So the issue seems to be only with the Messaging channel type (in our case). Also a small issue with the rendering of the custom AttachmentPickerTypeView: The picker and giphy buttons are not horizontally aligned with the text input field and the TrailingComposerView but instead slightly off center (see attached).

Here's the custom AttachmentPickerTypeView that I've been testing with:

import SwiftUI import StreamChat import StreamChatSwiftUI

/// View for picking the attachment type (media or giphy commands). struct CustomAttachmentPickerTypeView: View { @Injected(.images) private var images @Injected(.colors) private var colors

@Binding var pickerTypeState: PickerTypeState
var channelConfig: ChannelConfig?

private var commandsAvailable: Bool {
    channelConfig?.commands.count ?? 0 > 0
}

var body: some View { HStack(spacing: 16) { switch pickerTypeState { case let .expanded(attachmentPickerType): if channelConfig?.uploadsEnabled == true { PickerTypeButton( pickerTypeState: $pickerTypeState, pickerType: .media, selected: attachmentPickerType ) .accessibilityIdentifier("PickerTypeButtonMedia") }

// if commandsAvailable { PickerTypeButton( pickerTypeState: $pickerTypeState, pickerType: .instantCommands, selected: attachmentPickerType ) .accessibilityIdentifier("PickerTypeButtonCommands") // } case .collapsed: Button { withAnimation { pickerTypeState = .expanded(.none) } } label: { Image(uiImage: images.shrinkInputArrow) .renderingMode(.template) .foregroundColor(Color(colors.highlightedAccentBackground)) } .accessibilityIdentifier("PickerTypeButtonCollapsed") } } .accessibilityElement(children: .contain) } }

/// View for the picker type button. struct PickerTypeButton: View { @Injected(.images) private var images @Injected(.colors) private var colors

@Binding var pickerTypeState: PickerTypeState

let pickerType: AttachmentPickerType
let selected: AttachmentPickerType

var body: some View {
    Button {
        withAnimation {
            onTap(attachmentType: pickerType, selected: selected)
        }
    } label: {
        Image(uiImage: icon)
            .renderingMode(.template)
            .aspectRatio(contentMode: .fill)
            .frame(height: 18)
            .foregroundColor(
                foregroundColor(for: pickerType, selected: selected)
            )
    }
}

private var icon: UIImage {
    if pickerType == .media {
        return images.openAttachments
    } else {
        return images.commands
    }
}

private func onTap(
    attachmentType: AttachmentPickerType,
    selected: AttachmentPickerType
) {
    if selected == attachmentType {
        pickerTypeState = .expanded(.none)
    } else {
        pickerTypeState = .expanded(attachmentType)
    }
}

private func foregroundColor(
    for pickerType: AttachmentPickerType,
    selected: AttachmentPickerType
) -> Color {
    if pickerType == selected {
        return Color(colors.highlightedAccentBackground)
    } else {
        return Color(colors.textLowEmphasis)
    }
}

} StreamChat_buttons

martinmitrevski commented 1 year ago

thanks, this seems to be a backend issue. The team there is looking into it.

Subtextaps commented 1 year ago

thanks, this seems to be a backend issue. The team there is looking into it.

We've spotted another bug which seems closely related. The @ command (tagging people) also stopped working in the Message channels. It still works in the Livestream channels. So both problems (the giphy and the @ commands) seem to be with the Message Channel type.

martinmitrevski commented 1 year ago

hey @Subtextaps, I've done some more analysis on this - even if we disable all UI restrictions and be able to send the giphy command, the backend will still not accept it.

Therefore, the workarounds won't work, we would need to wait for the resolution on our backend.

Subtextaps commented 1 year ago

hey @Subtextaps, I've done some more analysis on this - even if we disable all UI restrictions and be able to send the giphy command, the backend will still not accept it.

Therefore, the workarounds won't work, we would need to wait for the resolution on our backend.

Hi @martinmitrevski,

We just discovered that the problem is the same in our Android version (Jetpack Compose). The giphy button does not work in the Message channels but works just fine in the LiveStream channels. However the @ command seems to work fine in both types of channels. Could you let your Jetpack Compose team know about the issue or should I create a new issue in the repo?

martinmitrevski commented 1 year ago

hey @Subtextaps, yes, it's most likely that it appears on Android as well, since it's related to the backend. I will ping the Android team as well, but the backend team is working on it. I'll update you when we know more.

martinmitrevski commented 1 year ago

hey @Subtextaps

Here's the response from the backend team: please make sure that you have the RunMessageAction added as permission for the channel type messaging, for the role channel_member on your dashboard.

It seems you have moved this permission for other roles and that's causing the issue.

Looking forward to your feedback.

Subtextaps commented 1 year ago

hey @Subtextaps

Here's the response from the backend team: please make sure that you have the RunMessageAction added as permission for the channel type messaging, for the role channel_member on your dashboard.

It seems you have moved this permission for other roles and that's causing the issue.

Looking forward to your feedback.

Yes, that was the problem. Now it works! I have no clue how this permission was disabled as we haven't changed any permissions in a long time.

Thanks a lot for your help with this!

martinmitrevski commented 1 year ago

perfect, glad to hear that 🎉