Skip to content

StreamChannelHeader causing error "You must have a StreamChat widget at the top of your widget tree" #1923

Description

@Jonny1987

Which packages are you using?

stream_chat_flutter

On what platforms did you experience the issue?

Android

What version are you using?

7.1.0
flutter 3.22.0

What happened?

The following _Exception was thrown building StreamConnectionStatusBuilder(dirty):
Exception: You must have a StreamChat widget at the top of your widget tree

The relevant error-causing widget was:
    StreamChannelHeader StreamChannelHeader:file:///home/john/dev/WorkWith/lib/src/features/chat/presentation/channel_page/channel_page.dart:12:21

When the exception was thrown, this was the stack:
#0      StreamChat.of (package:stream_chat_flutter/src/stream_chat.dart:85:7)
stream_chat.dart:85
#1      StreamConnectionStatusBuilder.build (package:stream_chat_flutter/src/misc/connection_status_builder.dart:37:20)
connection_status_builder.dart:37
#2      StatelessElement.build (package:flutter/src/widgets/framework.dart:5557:49)
framework.dart:5557

Steps to reproduce

Here is my code (Code exactly the same as #1924 but with app_bar added to from channel_page.dart and StreamMessageInput removed):

gorouter:

      GoRoute(
        path: '/home',
        name: AppRoute.home.name,
        builder: (context, state) {
          final tabName = state.uri.queryParameters['tab'];
          final tab =
              tabName == null ? TabsEnum.venues : getTabFromString(tabName);
          return StreamChat(
            client: streamChatClient,
            child: HomePage(
              tab: tab,
            ),
          );
        },
        routes: [
          GoRoute(
            path: 'chat',
            name: AppRoute.venueChat.name,
            builder: (context, state) {
              Channel channel = state.extra as Channel;
              return StreamChannel(
                channel: channel,
                child: const ChannelPage(),
              );
            },
          ),
        ],
      )

chat_tab.dart (as a tab in BottomNavigationBar):

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:workwith/src/features/auth/data/auth_repository.dart';
import 'package:workwith/src/features/chat/presentation/chat_tab/channel_list.dart';
import 'package:workwith/src/features/profile/domain/profile_model.dart';
import 'package:workwith/src/features/profile/presentation/profile_tab/profile_tab_controller.dart';
import 'package:workwith/src/utils/constants.dart';

class ChatTab extends ConsumerStatefulWidget {
  const ChatTab({super.key});

  @override
  ConsumerState<ChatTab> createState() => _ChatTabState();
}

class _ChatTabState extends ConsumerState<ChatTab> {
  OwnUser? ownUser;

  Future<void> connectUser(Profile profile) async {
    if (ownUser != null) {
      return;
    }
    final user = User(
      id: ref.read(authRepositoryProvider).currentUserId,
      extraData: {
        'username': profile.username!,
        'image': profile.profilePhotoUrl,
      },
    );
    ownUser = await streamChatClient.connectUser(
      user,
      streamChatClient.devToken(profile.username!).rawValue,
    );
  }

  @override
  Widget build(BuildContext context) {
    final profile = ref
        .watch(profileTabControllerProvider
            .select((value) => value.profileGetStatus))
        .value;
    if (profile == null) {
      return const Center(child: CircularProgressIndicator());
    } else {
      return FutureBuilder(
        future: connectUser(profile),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else {
            return ChannelListPage(client: streamChatClient);
          }
        },
      );
    }
  }
}

channel_list.dart:

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:workwith/src/logger.dart';
import 'package:workwith/src/routing/app_router.dart';

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

  final StreamChatClient client;

  @override
  State<ChannelListPage> createState() => _ChannelListPageState();
}

class _ChannelListPageState extends State<ChannelListPage> {
  late final _controller = StreamChannelListController(
    client: widget.client,
    filter: Filter.in_(
      'members',
      [StreamChat.of(context).currentUser!.id],
    ),
    channelStateSort: const [SortOption('last_message_at')],
  );

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        body: RefreshIndicator(
          onRefresh: _controller.refresh,
          child: StreamChannelListView(
            controller: _controller,
            onChannelTap: (channel) {
              logger().w('Channel tapped: ${channel.cid}');
              context.pushNamed(AppRoute.venueChat.name, extra: channel);
            },
          ),
        ),
      );
}

channel_page.dart:

import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

class ChannelPage extends StatelessWidget {
  const ChannelPage({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const StreamChannelHeader(),
      body: Column(
        children: <Widget>[
          Expanded(
            child: StreamMessageListView(
              messageBuilder:
                  (context, details, messageList, defaultMessageWidget) {
                return defaultMessageWidget.copyWith(
                  showThreadReplyIndicator: false,
                  showUserAvatar: DisplayWidget.show,
                  reverse: true,
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

Also in main.dart I wrap the MaterialApp.router with StreamChatTheme (following the last comment here: #1892)

Supporting info to reproduce

removing the app_bar from channel_page.dart stops the error occurring

Relevant log output

No response

Flutter analyze output

No issues

Flutter doctor output

[✓] Flutter (Channel stable, 3.22.0, on Ubuntu 22.04.4 LTS 6.5.0-28-generic, locale en_US.UTF-8)
    • Flutter version 3.22.0 on channel stable at /home/john/dev/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 5dcb86f68f (12 days ago), 2024-05-09 07:39:20 -0500
    • Engine revision f6344b75dc
    • Dart version 3.4.0
    • DevTools version 2.34.3

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /home/john/Android/Sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /opt/android-studio/jbr/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • Ubuntu clang version 14.0.0-1ubuntu1.1
    • cmake version 3.22.1
    • ninja version 1.10.1
    • pkg-config version 0.29.2

[✓] Android Studio (version 2023.1)
    • Android Studio at /opt/android-studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] VS Code (version 1.88.1)
    • VS Code at /usr/share/code
    • Flutter extension version 3.88.0

[✓] Connected device (3 available)
    • sdk gphone x86 64 (mobile) • emulator-5554 • android-x64    • Android 13 (API 33) (emulator)
    • Linux (desktop)            • linux         • linux-x64      • Ubuntu 22.04.4 LTS 6.5.0-28-generic
    • Chrome (web)               • chrome        • web-javascript • Google Chrome 123.0.6312.86

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

• No issues found!

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions