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
933 stars 343 forks source link

In ChannelListView onChannelTap is not hiding bottom bar #580

Closed jasnicaa closed 3 years ago

jasnicaa commented 3 years ago

Hi, I have ChannelList view as a part of a screen which is one of TabBar items. So when I tap on the chat from the list bottom bar is still there which is not what I want it. Is this happening because of the tabBar itself or is there something in the implementation of onChannelTap that I am missing and should be customizing? thanks.

Using 2.0.0-nullsafety.8 version.

xsahil03x commented 3 years ago

Hey @jasnicaa, can you please share a small video or images describing your issues?

jasnicaa commented 3 years ago

sure.

this is channel list view:

Screenshot 2021-07-27 at 14 52 37

and this is the chat screen where I would like to remove the bottom bar

Screenshot 2021-07-27 at 14 52 48
imtoori commented 3 years ago

@jasnicaa do you have a nested navigator in the Chat tab?

jasnicaa commented 3 years ago

Nope, just tabBarView instantiating its children in order which they are visible in tabBar.

imtoori commented 3 years ago

that's weird, can you paste a snippet of it?

jasnicaa commented 3 years ago

Sure, but I have the feeling that the actual culprit is in the chat screen so I will paste that one as well.

class MainMenu extends StatefulWidget {
  final int initPage;
  final int initSubPage;
  final StreamChatClient? client;

  const MainMenu({
    this.initPage = 0,
    this.initSubPage = 0,
    Key? key,
    this.client,
  }) : super(key: key);

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

class MainMenuState extends State<MainMenu> with TickerProviderStateMixin {
  TabController? _tabController;
  String _titleText = "";
  final List<String> _titles = ["Hello", "Chat", "Expenses"];

  /// The channel we'd like to observe and participate.
  Channel? channel;

  final db = FirebaseFirestore.instance;

  bool? _canClick = true;

  @override
  void initState() {
    super.initState();
    _titleText = _titles[widget.initPage];
    _tabController =
        TabController(initialIndex: widget.initPage, length: 3, vsync: this);
    _tabController!.addListener(
      () {
        if (_tabController!.indexIsChanging) {
          _handleTitle();
        }
      },
    );

    _canClick = ClickHandler.instance.canClick;
  }

  @override
  void dispose() {
    super.dispose();
    _tabController!.dispose();
  }

  void _handleTitle() {
    setState(() {
      _titleText = AppLocalizations.of(context)!
          .translateList("menuTitles")[_tabController!.index];
    });
  }

  void _aloneSnackbar(BuildContext context) {
    SnackBarHandler.instance.showSnackBar(
        context,
        () => {},
        AppLocalizations.of(context)!.translateString("chatStudio"),
        Icons.info_outline,
        Colors.white,
        CustomColors.orangy);
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: null,
      child: Scaffold(
        backgroundColor: Colors.white,
        body: SafeArea(
          child: IgnorePointer(
            ignoring: !_canClick!,
            child: TabBarView(
              physics: const NeverScrollableScrollPhysics(),
              controller: _tabController,
              children: <Widget>[
                home.Home(),
                ChatScreen(),
                ExpensesScreen(),
              ],
            ),
          ),
        ),
        bottomNavigationBar: Container(
          decoration: const BoxDecoration(
            boxShadow: [BoxShadow(color: CustomColors.navGrey, blurRadius: 12)],
          ),
          child: BottomAppBar(
            color: Colors.white,
            clipBehavior: Clip.antiAlias,
            elevation: 2,
            shape: const CircularNotchedRectangle(),
            child: TabBar(
              labelColor: CustomColors.topaz,
              unselectedLabelColor: CustomColors.navGrey,
              indicator: const CustomUnderlineTabIndicator(
                insets: EdgeInsets.symmetric(horizontal: 12),
                borderSide: BorderSide(
                  width: 3.5,
                  color: CustomColors.topaz,
                ),
              ),
              controller: _tabController,
              tabs: <Widget>[
                Tab(
                  icon: const Icon(
                    IconData(0xe800, fontFamily: 'custom-home'),
                    size: 24,
                  ),
                  child: Text(
                    AppLocalizations.of(context)!.translateString("feed"),
                    style: _tabController!.index == 0
                        ? CustomTextStyles.appBarSelected
                        : CustomTextStyles.appBarUnselected,
                  ),
                ),
                Tab(
                  icon: const Icon(
                    IconData(0xe800, fontFamily: 'custom-chat'),
                    size: 24,
                  ),
                  child: Text(
                    AppLocalizations.of(context)!.translateString("chat"),
                    style: _tabController!.index == 1
                        ? CustomTextStyles.appBarSelected
                        : CustomTextStyles.appBarUnselected,
                  ),
                ),
                Tab(
                  icon: const Icon(
                    IconData(0xe800, fontFamily: 'custom-money'),
                    size: 26,
                  ),
                  child: Text(
                    AppLocalizations.of(context)!.translateString("expenses"),
                    style: _tabController!.index == 2
                        ? CustomTextStyles.appBarSelected
                        : CustomTextStyles.appBarUnselected,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

CHAT SCREENS:


class ChatScreen extends StatefulWidget {
  const ChatScreen();

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

class _ChatScreenState extends State<ChatScreen> {
  StreamChatClient? client;

  Future<void> setUpGetStreamChat() async {
    await BlocProvider.of<ChatCubit>(context).getChatInitialData(context);
    Channel? channel;

    final bloc = BlocProvider.of<ChatCubit>(context);

    client = chat.StreamChatClient(
      bloc.state.chatDataModel!.apiKey,
      logLevel: chat.Level.INFO,
    );

    await client?.connectUser(
      chat.User(
        id: bloc.state.chatDataModel!.username!,
        extraData: {
          'image': bloc.state.chatDataModel!.avatar,
        },
      ),
      bloc.state.chatDataModel!.token,
    );

    final channelCreated = bloc.state.chatDataModel?.channels[0];

    channel = client?.channel("messaging", id: channelCreated);
    channel?.watch();

    bloc.setChannel(channel);
  }

  @override
  void didChangeDependencies() async {
    await setUpGetStreamChat();
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChatFirstPage(),
      builder: (context, wid) {
        return BlocBuilder<ChatCubit, ChatState>(
          builder: (context, state) {
            if (state.status == ChatStatus.failure) {
              // TODO handle errors

            }
            if (state.status == ChatStatus.loaded) {
              return chat.StreamChat(
                client: client!,
                child: wid,
                streamChatThemeData:
                    StreamChatThemeData.fromTheme(Theme.of(context)).copyWith(
                  channelTheme: chat.ChannelTheme(
                    channelHeaderTheme: ChannelHeaderTheme(
                        title: CustomTextStyles.chatTitleOthers,
                        subtitle: CustomTextStyles.chatSubtitle),
                  ),
                  ownMessageTheme: MessageTheme(
                    messageBackgroundColor: CustomColors.topaz,
                    messageText: CustomTextStyles.chatTitleAuthor,
                    messageAuthor: CustomTextStyles.chatSubtitle,
                    createdAt: CustomTextStyles.chatSubtitle,
                    avatarTheme: chat.AvatarTheme(),
                  ),
                  otherMessageTheme: MessageTheme(
                    messageBackgroundColor: Colors.white,
                    messageText: CustomTextStyles.chatTitleOthers,
                    messageAuthor: CustomTextStyles.chatSubtitle,
                    createdAt: CustomTextStyles.chatSubtitle,
                  ),
                  channelPreviewTheme: ChannelPreviewTheme(
                    title: CustomTextStyles.chatTitleOthers,
                    subtitle: CustomTextStyles.chatSubtitle,
                    lastMessageAt: CustomTextStyles.chatSubtitle,
                  ),
                ),
              );
            } else {
              return const LoadingIndicator();
            }
          },
        );
      },
    );
  }
}

class ChatFirstPage extends StatefulWidget {
  ChatFirstPage({Key? key}) : super(key: key);

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

class _ChatFirstPageState extends State<ChatFirstPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocBuilder<ChatCubit, ChatState>(
        builder: (context, state) {
          if (state.status == ChatStatus.failure) {
            // tODO handle errors
          }
          if ((state.status == ChatStatus.loaded) && state.channel != null) {
            return chat.StreamChannel(
              channel: state.channel!,
              child: ChannelListPage(),
            );
          } else {
            return const LoadingIndicator();
          }
        },
      ),
    );
  }
}

class ChannelListPage extends StatefulWidget {
  @override
  _ChannelListPageState createState() => _ChannelListPageState();
}

class _ChannelListPageState extends State<ChannelListPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        brightness: Brightness.light,
        centerTitle: false,
        backgroundColor: Colors.white,
        elevation: 0,
        title: Text("Chat", style: CustomTextStyles.appBarBlueTitle),
        actions: [
          IconButton(
            padding: const EdgeInsets.only(right: 15),
            onPressed: () {
              Navigator.pushNamed(context, dashboardScreenRoute);
            },
            icon: const Icon(
              IconData(0xe800, fontFamily: 'side-menu-icon'),
              color: CustomColors.hintGrey,
              size: 20,
            ),
          ),
        ],
      ),
      body: ChannelsBloc(
        child: Padding(
          padding: const EdgeInsets.fromLTRB(8, 16, 8, 16),
          child: ChannelListView(
            loadingBuilder: (BuildContext context) {
              return const LoadingIndicator();
            },
            filter: Filter.in_(
              'members',
              [StreamChat.of(context).user!.id],
            ),
            sort: [SortOption('last_message_at')],
            pagination: PaginationParams(
              limit: 30,
            ),
            channelWidget: ChannelPage(),
          ),
        ),
      ),
    );
  }
}

/// Displays the list of messages inside the channel
class ChannelPage extends StatelessWidget implements PreferredSizeWidget {
  @override
  final Size preferredSize;
  final VoidCallback? onTitleTap;

  ChannelPage({
    this.onTitleTap,
    Key? key,
  }) : preferredSize = const Size.fromHeight(kToolbarHeight);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: false,
        brightness: Brightness.light,
        automaticallyImplyLeading: false,
        backgroundColor: Colors.white,
        elevation: 0,
        leading: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: CircleAvatar(
                radius: 20,
                child: Image.asset("assets/chat-icon-0.png", fit: BoxFit.fill),
              ),
            ),
            const SizedBox(width: 8),
            InkWell(
              onTap: onTitleTap,
              child: SizedBox(
                height: preferredSize.height,
                width: preferredSize.width,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    ChannelName(
                      textStyle: CustomTextStyles.chatTitleAuthor,
                    ),
                    const SizedBox(height: 2),
                  ],
                ),
              ),
            ),
          ],
        ),
        actions: [
          IconButton(
            padding: const EdgeInsets.only(right: 15),
            onPressed: () => Navigator.of(context).pop(),
            icon: const Icon(
              IconData(0xe800, fontFamily: "custom-close"),
              color: CustomColors.hintGrey,
              size: 18.0,
            ),
          ),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: MessageListView(
                // threadBuilder: (_, parentMessage) {
                //   return ThreadPage(parent: parentMessage);
                // },
                ),
          ),
          MessageInput(),
        ],
      ),
    );
  }
}
imtoori commented 3 years ago

@jasnicaa a MaterialApp wraps everything in a Navigator, that's why the new page gets pushed in that subtree How come you're using a nested MaterialApp?

I'm closing this because it's unrelated to the sdk, but let's try to solve this! I think you could remove the MaterialApp from here