Files
eatvio_app/lib/features/chat/presentation/pages/chats_screen.dart

134 lines
5.0 KiB
Dart

import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/enums/base_state.dart';
import 'package:eatvio_app/core/utils/pagination_utils.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_state.dart';
import 'package:eatvio_app/features/chat/presentation/widgets/chat_entry_widget.dart';
import 'package:eatvio_app/features/chat/presentation/widgets/chat_search_bar_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ChatsScreen extends StatefulWidget {
const ChatsScreen({super.key, this.initialSearchQuery});
/// When set (e.g. from notification tap), the search field is pre-filled
/// and chat list is filtered by this query.
final String? initialSearchQuery;
@override
State<ChatsScreen> createState() => _ChatsScreenState();
}
class _ChatsScreenState extends State<ChatsScreen> {
final searchController = TextEditingController();
@override
void initState() {
super.initState();
final query = widget.initialSearchQuery?.trim();
if (query != null && query.isNotEmpty) {
searchController.text = query;
}
WidgetsBinding.instance.addPostFrameCallback((_) {
final cubit = context.read<ChatsCubit>();
final state = cubit.state;
if (state.state == BaseState.initial) {
cubit.getChatRoomsWithLoading(query: query?.isNotEmpty == true ? query : null);
} else if (query != null && query.isNotEmpty) {
cubit.getChatRooms(query: query);
}
});
}
@override
Widget build(BuildContext context) {
return BlocBuilder<ChatsCubit, ChatsState>(
builder: (context, state) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
toolbarHeight: 0,
),
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverPadding(
padding: const EdgeInsets.only(top: 8),
sliver: SliverAppBar(
automaticallyImplyLeading: false,
stretchTriggerOffset: 1,
scrolledUnderElevation: 0,
floating: true,
snap: true,
title: Padding(
padding: const EdgeInsets.only(top: 8),
child: ChatSearchBarWidget(
onSuffixIconTap: () => context.read<ChatsCubit>().getChatRooms(),
onChanged: (query) {
if (query.length > 2) {
EasyDebounce.debounce(
'searchChatRoom',
const Duration(milliseconds: 300),
() => context.read<ChatsCubit>().getChatRooms(query: query),
);
} else {
context.read<ChatsCubit>().getChatRooms();
}
},
controller: searchController,
fillColor: const Color(0xFFF0F2F5),
hintText: "Поиск",
hintStyle: const TextStyle(
color: Color(0xFF7B8794),
),
),
),
),
),
];
},
body: RefreshIndicator(
child: switch (state.state) {
BaseState.error => DataErrorWidget(onReload: () => context.read<ChatsCubit>().getChatRooms()),
BaseState.success => _buildChatList(context, state),
_ => const Loader(),
},
onRefresh: () async {
await context.read<ChatsCubit>().getChatRooms();
},
),
),
);
},
);
}
NotificationListener<ScrollNotification> _buildChatList(BuildContext context, ChatsState state) {
return NotificationListener<ScrollNotification>(
onNotification: (notification) {
loadNewContent(notification, context.read<ChatsCubit>().loadMoreChatRooms);
return false;
},
child: ListView.separated(
padding: const EdgeInsets.all(16),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (context, index) {
return const SizedBox(
height: 8,
);
},
itemCount: state.isLoadingMoreChats ? state.chatRooms.length + 1 : state.chatRooms.length,
itemBuilder: (context, index) {
if (index == state.chatRooms.length) {
return const Center(child: Loader());
}
return ChatEntryWidget(chatRoom: state.chatRooms[index]);
},
),
);
}
}