GetStream / stream-chat-flutter

Flutter Chat SDK - Build your own chat app experience using Dart, Flutter and the Stream Chat Messaging API.
https://getstream.io/chat/sdk/flutter/
Other
881 stars 314 forks source link

always showing 'You must have a Stream Chat Theme widget at the top of your widget tree' even if it is wrap #1892

Closed ckc64 closed 2 months ago

ckc64 commented 2 months ago

Which packages are you using?

stream_chat, stream_chat_flutter, stream_chat_flutter_core

On what platforms did you experience the issue?

Web

What version are you using?

7.2.0-hotfix.1 7.2.0-hotfix.1 7.2.0-hotfix.1

What happened?

I want to show reactions on my message bubble, I already added the StreamChatThemeData but everytime I tried to long press any message bubble it showing an error : stream_chat_theme.dart: 27:7 streamChatTheme != null 'You must have a Stream Chat Theme widget at the top of your widget tree'

Steps to reproduce

1. Go to chat
2. Click(Long press) on any message bubble.

Supporting info to reproduce

This is my main chat

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:rive/rive.dart';
import 'package:seatmatch/common/widgets/default_scaffold.dart';
import 'package:seatmatch/constants/rive_stream_reactions.dart';
import 'package:seatmatch/constants/route_names.dart';
import 'package:seatmatch/features/chat/widget/group_chat_profile.dart';
import 'package:seatmatch/features/events/bloc/event_detail_bloc.dart';
import 'package:seatmatch/utils/tailwind_responsive_design.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

class ChatWeb extends StatefulWidget {
  final EventDetailSuccess eventDetailSuccess;
  final StreamChatClient client;
  final Channel channel;
  final String eventId;

  const ChatWeb({
    super.key,
    required this.eventDetailSuccess,
    required this.client,
    required this.channel,
    required this.eventId,
  });

  @override
  State<ChatWeb> createState() => _ChatWebState();
}

class _ChatWebState extends State<ChatWeb> {
  bool showListOfUser = false;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    TailwindResponsiveDesign tailwindResponsiveDesign =
        TailwindResponsiveDesign(context);

    return StreamChat(
      useMaterial3: true,
      client: widget.client,
       streamChatThemeData: StreamChatThemeData(
          reactionIcons: riveStreamReactionAnimations
              .map(
                (reaction) => StreamReactionIcon(
                  type: reaction.type,
                  builder: (context, highlighted, size) {
                    return KeyedSubtree(
                      key: ValueKey('reaction-${reaction.type}'),
                      child: RiveAnimation.asset(
                        'assets/stream_reactions.riv',
                        artboard: highlighted
                            ? reaction.artboardHighlighted
                            : reaction.artboard,
                      ),
                    );
                  },
                ),
              )
              .toList(),
       ),
      child: StreamChannel(
        channel: widget.channel,
        child: DefaultScaffold(
          showMenuBar: false,
          child: SizedBox(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: Stack(
              children: [
                Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [

                    Expanded(
                      child: Padding(
                        padding: const EdgeInsets.only(right: 10),
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.stretch,
                          children: [
                            Visibility(
                              visible: !showListOfUser,
                              child: const Expanded(
                                child: StreamMessageListView(
                                  showFloatingDateDivider: false,

                                ),
                              ),
                            ),
                            Visibility(
                              visible: !showListOfUser,
                              child: const Divider(
                                height: 1.5,
                                color: Color(0xFFE7E7E7),
                              ),
                            ),
                            Visibility(
                              visible: !showListOfUser,
                              child: const SizedBox(
                                height: 15,
                              ),
                            ),
                            Visibility(
                              visible: !showListOfUser,
                              child: const StreamMessageInput(
                                enableSafeArea: false,
                                elevation: 0,
                                // sendButtonBuilder:
                                //     (context, streamInputMessageController) {
                                //   return Padding(
                                //     padding: const EdgeInsets.only(left: 10.0),
                                //     child: InkWell(
                                //       onTap: () {
                                //         widget.channel.sendMessage(
                                //           streamInputMessageController.message,
                                //         );
                                //       },
                                //       child: const Icon(
                                //         Icons.send,
                                //         color: Colors.green,
                                //       ),
                                //     ),
                                //   );
                                // },
                                // commandButtonBuilder: (context, commandButton) {
                                //   return InkWell(
                                //     onTap: commandButton.onPressed,
                                //     child: const Icon(
                                //       Icons.thunderstorm,
                                //       color: Colors.black,
                                //     ),
                                //   );
                                // },
                                // attachmentButtonBuilder:
                                //     (context, attachmentButton) {
                                //   return InkWell(
                                //     onTap: attachmentButton.onPressed,
                                //     child: const Icon(
                                //       Icons.attach_file_rounded,
                                //       color: Colors.black,
                                //     ),
                                //   );
                                // },
                              ),
                            ),
                            Visibility(
                              visible: !showListOfUser,
                              child: const SizedBox(
                                height: 15,
                              ),
                            ),
                            Visibility(
                              visible: showListOfUser,
                              child: const SizedBox(
                                height: 32,
                              ),
                            ),
                            Visibility(
                              visible: showListOfUser,
                              child: Expanded(
                                child: Padding(
                                  padding: const EdgeInsets.only(
                                    top: 80.0,
                                    left: 16.0,
                                    right: 16.0,
                                    bottom: 16.0,
                                  ),
                                  child: ListView.separated(
                                    separatorBuilder: (context, index) =>
                                        const SizedBox(
                                      height: 16,
                                    ),
                                    itemCount: widget.eventDetailSuccess
                                        .eventsDetailsModel.group!.users.length,
                                    itemBuilder: (context, index) {
                                      return InkWell(
                                        onTap: () {
                                          context.goNamed(
                                            RouteNames
                                                .matchGroupChatUserProfile,
                                            pathParameters: {
                                              'chatId': widget
                                                  .eventDetailSuccess
                                                  .eventsDetailsModel
                                                  .group!
                                                  .chatId,
                                              "eventId": widget.eventId,
                                              "userId": widget
                                                  .eventDetailSuccess
                                                  .eventsDetailsModel
                                                  .group!
                                                  .users[index]
                                                  .userId,
                                            },
                                          );
                                        },
                                        child: Row(
                                          children: [
                                            GroupChatProfile(
                                              imageLink: widget
                                                  .eventDetailSuccess
                                                  .eventsDetailsModel
                                                  .group!
                                                  .users[index]
                                                  .profilePicture,
                                              radius: 50,
                                            ),
                                            const SizedBox(
                                              width: 16,
                                            ),
                                            Text(
                                              widget
                                                      .eventDetailSuccess
                                                      .eventsDetailsModel
                                                      .group!
                                                      .users[index]
                                                      .name ??
                                                  '',
                                              style: const TextStyle(
                                                fontFamily: 'OpenSauceTwo',
                                                fontWeight: FontWeight.w900,
                                                fontSize: 18,
                                                fontStyle: FontStyle.normal,
                                                color: Colors.black,
                                              ),
                                            )
                                          ],
                                        ),
                                      );
                                    },
                                  ),
                                ),
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
                Container(
                  decoration: const BoxDecoration(
                    color: Colors.white,
                    border: Border(
                      bottom: BorderSide(width: 1.5, color: Color(0xFFE7E7E7)),
                    ),
                  ),
                  padding: const EdgeInsets.symmetric(
                    horizontal: 16.0,
                    vertical: 8.0,
                  ),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      IconButton(onPressed: () => context.pop(), icon: const Icon(Icons.arrow_back_ios_new_rounded), iconSize: 20, color: Colors.black,),
                      Expanded(
                        child: Text(
                          '#${widget.eventDetailSuccess.eventsDetailsModel.name}',
                          style: const TextStyle(
                            fontFamily: 'OpenSauceTwo',
                            fontWeight: FontWeight.w900,
                            fontSize: 18,
                            fontStyle: FontStyle.normal,
                            color: Colors.black,
                          ),
                          maxLines: 2,
                        ),
                      ),
                      Visibility(
                        visible: showListOfUser,
                        child: SizedBox(
                          height: 70.0,
                          child: InkWell(
                            onTap: () {
                              setState(() {
                                showListOfUser = !showListOfUser;
                              });
                            },
                            child: const Icon(
                              Icons.close,
                              size: 36.0,
                            ),
                          ),
                        ),
                      ),
                      Visibility(
                        visible: !showListOfUser,
                        child: widget.eventDetailSuccess.eventsDetailsModel
                                    .interestedUsers!.length >
                                1
                            ? InkWell(
                                onTap: () {
                                  setState(() {
                                    showListOfUser = !showListOfUser;
                                  });
                                },
                                child: SizedBox(
                                  height: 70,
                                  width: 100,
                                  child: Stack(
                                    children: [
                                      Positioned(
                                        top: 8,
                                        right: 0,
                                        child: GroupChatProfile(
                                          imageLink: widget
                                              .eventDetailSuccess
                                              .eventsDetailsModel
                                              .group!
                                              .users[0]
                                              .profilePicture,
                                        ),
                                      ),
                                      Positioned(
                                        top: 21,
                                        right: 23,
                                        child: GroupChatProfile(
                                          imageLink: widget
                                              .eventDetailSuccess
                                              .eventsDetailsModel
                                              .group!
                                              .users[1]
                                              .profilePicture,
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              )
                            : InkWell(
                                onTap: () {
                                  setState(() {
                                    showListOfUser = !showListOfUser;
                                  });
                                },
                                child: GroupChatProfile(
                                  imageLink: widget
                                      .eventDetailSuccess
                                      .eventsDetailsModel
                                      .group!
                                      .users[0]
                                      .profilePicture,
                                ),
                              ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Rive file

import 'package:flutter/material.dart';

const riveStreamReactionAnimations = [
  RiveStreamReaction(
    type: 'love',
    artboard: 'love',
    artboardHighlighted: 'love_highlight',
  ),
  RiveStreamReaction(
    type: 'like',
    artboard: 'like',
    artboardHighlighted: 'like_highlight',
  ),
  RiveStreamReaction(
    type: 'sad',
    artboard: 'sad',
    artboardHighlighted: 'sad_highlight',
  ),
  RiveStreamReaction(
    type: 'haha',
    artboard: 'haha',
    artboardHighlighted: 'haha_highlight',
  ),
  RiveStreamReaction(
    type: 'wow',
    artboard: 'wow',
    artboardHighlighted: 'wow_highlight',
  ),
];

@immutable
class RiveStreamReaction {
  final String type;
  final String artboard;
  final String artboardHighlighted;

  const RiveStreamReaction({
    required this.type,
    required this.artboard,
    required this.artboardHighlighted,
  });
}

Relevant log output

No response

Flutter analyze output

Flutter analyze is success

Flutter doctor output

[✓] Flutter (Channel stable, 3.16.9, on macOS 14.3.1 23D60 darwin-arm64, locale en-PH)
    • Flutter version 3.16.9 on channel stable at /../fvm/versions/3.16.9
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 41456452f2 (2 months ago), 2024-01-25 10:06:23 -0800
    • Engine revision f40e976bed
    • Dart version 3.2.6
    • DevTools version 2.28.5

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15E204a
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).

[✓] VS Code (version 1.87.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.86.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 14.3.1 23D60 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 123.0.6312.107

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.

Code of Conduct

Ssiswent commented 2 months ago

The same

esarbanis commented 2 months ago

Thank for opening this issue, I am investigating.

esarbanis commented 2 months ago

@ckc64 can you please try to use the following instead?

StreamChat(
      useMaterial3: true,
      client: widget.client,
-       streamChatThemeData: StreamChatThemeData(
+       streamChatConfigData: StreamChatConfigurationData(
           reactionIcons: riveStreamReactionAnimations
              .map(
                (reaction) => StreamReactionIcon(
                  type: reaction.type,
                  builder: (context, highlighted, size) {
                    return KeyedSubtree(
                      key: ValueKey('reaction-${reaction.type}'),
                      child: RiveAnimation.asset(
                        'assets/stream_reactions.riv',
                        artboard: highlighted
                            ? reaction.artboardHighlighted
                            : reaction.artboard,
                      ),
                    );
                  },
                ),
              )
              .toList(),
       ),
ckc64 commented 2 months ago

Helloo, I already solve this issue , transferred the Stream chat to the root material app Thank you

Screenshot 2024-04-10 at 2 30 00 AM
adityasethipsi commented 2 weeks ago

I'm facing the same problem. I want the chat API to be included in this project.

adityasethipsi commented 2 weeks ago

@ckc64 @esarbanis @Ssiswent i'm facing this same issue . can you please suggest how can i fix it?

ckc64 commented 2 weeks ago

@ckc64 @esarbanis @Ssiswent i'm facing this same issue . can you please suggest how can i fix it? something like this

Widget build(BuildContext context) { return StreamChatTheme( data: StreamChatThemeData( reactionIcons: riveStreamReactionAnimations .map( (reaction) => StreamReactionIcon( type: reaction.type, builder: (context, highlighted, size) { return KeyedSubtree( key: ValueKey('reaction-${reaction.type}'), child: RiveAnimation.asset( 'assets/stream_reactions.riv', artboard: highlighted ? reaction.artboardHighlighted : reaction.artboard, ), ); }, ), ) .toList(), ), child: StreamChannel( channel: widget.channel, child: Scaffold( ... ...

adityasethipsi commented 2 weeks ago

@ckc64 I need to include this as a feature in my long running project and i need this fix ASAP>

This is the code

`import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:monkee_v2/admin_screens/shared_widgets/form_submit_buttons.dart'; import 'package:monkee_v2/constants/app_constants.dart'; import 'package:monkee_v2/shared_widgets/text_and_description_widget.dart'; import 'package:monkee_v2/shared_widgets/utils/ui_util.dart'; import 'package:monkee_v2/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';

class StreamChatPage extends StatefulWidget { final StreamChatClient client; const StreamChatPage({ super.key, required this.client, });

@override StreamChatPageState createState() => StreamChatPageState(); }

class StreamChatPageState extends State { late Channel channel;

StreamChatPageState();

@override void dispose() { channel.stopWatching(); channel.dispose(); super.dispose(); }

@override void initState() { super.initState(); channel = widget.client.channel( 'messaging', id: 'flutterDevs', );

// _init();

}

// Future _init() async { // // var authToken = await appController.getAuthToken(); // // client = StreamChatClient('z8rtr6acsden', logLevel: Level.INFO); // // await client.connectUser( // // User(id: 'abc'), // // 'Bearer ${authToken ?? 'ANNMCNS'}', // // ); // }

Widget build(BuildContext context) { var theme = StreamChatThemeData( // reactionIcons: riveStreamReactionAnimations // .map( // (reaction) => StreamReactionIcon( // type: reaction.type, // builder: (context, highlighted, size) { // return KeyedSubtree( // key: ValueKey('reaction-${reaction.type}'), // child: RiveAnimation.asset( // 'assets/stream_reactions.riv', // artboard: highlighted // ? reaction.artboardHighlighted // : reaction.artboard, // ), // ); // }, // ), // ) // .toList(), ); return StreamChatTheme( data: theme, child: StreamChat( client: widget.client, streamChatThemeData: theme, useMaterial3: true, child: StreamChannel( channel: channel, child: ChannelPage(channel), ), ), ); } }

class ChannelPage extends StatefulWidget { final Channel channel;

const ChannelPage(this.channel);

@override _ChannelPageState createState() => _ChannelPageState(); }

class _ChannelPageState extends State { @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ Expanded( child: StreamMessageListView( messageBuilder: (p0, p1, p2, defaultMessageWidget) { return defaultMessageWidget.copyWith( showDeleteMessage: true, showEditMessage: true, showReactionPicker: true, showReactions: true, showReplyMessage: true, ); StreamMessageWidget; },

          // onMessageTap: (message) {
          //   showModalBottomSheet(
          //     context: context,
          //     builder: (context) {
          //       return ReactionPicker(
          //         message: message,
          //         onReactionTap: (reactionType) async {
          //           await widget.channel.sendReaction(
          //             message,
          //             reactionType,
          //           );
          //           Navigator.of(context).pop();
          //         },
          //       );
          //     },
          //   );
          // },
          // messageBuilder: (p0, p1, p2, defaultMessageWidget) {
          //   if (p1.message.isDeleted) return SizedBox();
          //   return InkWell(
          //     // onDoubleTap: () async {
          //     //   var status = await channel.unbanMember(
          //     //     'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicDJZMFVvenI0N09ETFVEdmcyQmh0cnRNV1dqMiJ9.ky0c5iEZIMAh72PwxWKBj3Efr2pjgvgM3507m7qol44',
          //     //     //  BanUserRequest(
          //     //     //   timeout: 60, // Ban duration in minutes, omit or set to 0 for permanent ban
          //     //     //   reason: 'Violation of community guidelines',
          //     //     // ),
          //     //   );
          //     //   status;
          //     // },
          //     // onLongPress: () async {
          //     //   var status = await channel.banMember(
          //     //     'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoicDJZMFVvenI0N09ETFVEdmcyQmh0cnRNV1dqMiJ9.ky0c5iEZIMAh72PwxWKBj3Efr2pjgvgM3507m7qol44',
          //     //     {
          //     //       'ttl': 18,
          //     //     },
          //     //     //  BanUserRequest(
          //     //     //   timeout: 60, // Ban duration in minutes, omit or set to 0 for permanent ban
          //     //     //   reason: 'Violation of community guidelines',
          //     //     // ),
          //     //   );
          //     //   status;
          //     // },
          //     // onTap: () {
          //     //   showModalBottomSheet(
          //     //     context: context,
          //     //     builder: (context) {
          //     //       return ReactionPicker(
          //     //         message: p1.message,
          //     //         onReactionTap: (reactionType) async {
          //     //           await channel.sendReaction(
          //     //             p1.message,
          //     //             reactionType,
          //     //           );
          //     //           Navigator.of(context).pop();
          //     //         },
          //     //       );
          //     //     },
          //     //   );
          //     // },
          //     child: Row(
          //       children: [
          //         Text(p1.message.text ?? 'am,s'),
          //         IconButton(
          //           icon: Icon(Icons.delete),
          //           onPressed: () {
          //             widget.channel.deleteMessage(p1.message, hard: true);
          //             setState(() {});
          //           },
          //         ),
          //         IconButton(
          //           icon: Icon(Icons.edit),
          //           onPressed: () async {
          //             await Get.dialog(SetSupplierNameDialog(
          //                 'Edit your company name ',
          //                 p1.message.text!,
          //                 'You can change your company name. This will be updated on all your open and submitted bids.',
          //                 (old, newA) {
          //               var newMessage = Message(
          //                 text: p1.message.text,
          //                 user: p1.message.user,
          //               );
          //               // p1.message.text = newA;
          //               widget.channel.updateMessage(p1.message);
          //             }));
          //           },
          //         ),
          //         IconButton(
          //           icon: Icon(Icons.stop_circle),
          //           onPressed: () {
          //             widget.channel.banMember(
          //               p1.message.user!.id,
          //               {'reason': 'myChoice'},
          //             );
          //             setState(() {});
          //           },
          //         ),
          //         IconButton(
          //           icon: Icon(Icons.pause),
          //           onPressed: () {
          //             widget.channel.removeMembers([p1.message.user!.id]);
          //             setState(() {});
          //           },
          //         ),
          //       ],
          //     ),
          //   );
          // },
        ),
      ),
      const StreamMessageInput(
        allowedAttachmentPickerTypes: [AttachmentPickerType.files],
      ),
    ],
  ),
);

} } `