import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pmd_labs/components/utils/debounce.dart'; import 'package:pmd_labs/data/repositories/album_repository.dart'; import 'package:pmd_labs/details_page/detail_page.dart'; import 'package:pmd_labs/home_page/bloc/events.dart'; import 'package:pmd_labs/home_page/bloc/state.dart'; import 'package:pmd_labs/card_data.dart'; import '../data/dto/album_dto.dart'; import 'bloc/home_bloc.dart'; part 'card.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: const Color(0xFF231a24), title: Text( widget.title, style: Theme.of(context) .textTheme .headlineLarge ?.copyWith(color: Colors.orange), ), ), body: Container( color: const Color(0xFF403042), child: const Body(), // Ваш виджет Body ), ); } } class Body extends StatefulWidget { const Body({super.key}); @override State createState() => _BodyState(); } class _BodyState extends State { final AlbumRepository repo = AlbumRepository(); final ScrollController scrollController = ScrollController(); final TextEditingController searchController = TextEditingController(); late final Debounce debounce; @override void initState() { super.initState(); // Настройка времени дебаунса WidgetsBinding.instance.addPostFrameCallback((_) { context.read().add(const HomeLoadDataEvent()); }); scrollController.addListener(_onNextPageListener); } void _onNextPageListener() { if (scrollController.position.pixels >= scrollController.position.maxScrollExtent && !context.read().state.isPaginationLoading) { final bloc = context.read(); bloc.add(HomeLoadDataEvent( search: searchController.text, nextPage: bloc.state.data?.nextPage, )); } } void _showSnackbar(BuildContext context, String title, bool isLiked) { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( 'Лайк на $title ${isLiked ? 'поставлен' : 'убран'}', style: Theme.of(context).textTheme.bodyLarge, ), backgroundColor: Colors.orangeAccent, duration: const Duration(seconds: 1), )); }); } void _navToDetails(BuildContext context, CardData data) { Navigator.push( context, CupertinoPageRoute(builder: (context) => DetailsPage(data)) ); } @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), child: Column( children: [ Padding( padding: const EdgeInsets.all(12), child: CupertinoSearchTextField( controller: searchController, onChanged: (search) { Debounce.run(() { context.read().add(HomeLoadDataEvent(search: search)); }); }, style: TextStyle(color: Colors.orange, fontFamily: 'Correction_Tape'), ), ), Expanded( child: BlocBuilder( builder: (context, state) { if (state.isLoading) { return const Center(child: CircularProgressIndicator()); } return RefreshIndicator( onRefresh: () async { // Добавим состояние загрузки context.read().add(HomeLoadDataEvent(search: searchController.text)); }, child: ListView.builder( controller: scrollController, padding: EdgeInsets.zero, itemCount: state.data?.data?.length ?? 0, itemBuilder: (context, index) { final cardData = state.data?.data?[index]; return cardData != null ? _Card.fromData( cardData, onLike: (title, isLiked) => _showSnackbar(context, title, isLiked), onTap: () => _navToDetails(context, cardData), ) : const SizedBox.shrink(); }, ), ); }, ), ), BlocBuilder( builder: (context, state) { if (state.isPaginationLoading) { return const Padding( padding: EdgeInsets.all(8.0), child: CircularProgressIndicator(), ); } return const SizedBox.shrink(); }, ), ], ), ); } @override void dispose() { searchController.dispose(); scrollController.dispose(); super.dispose(); } } class HomeData { final List? data; final int? nextPage; HomeData({this.data, this.nextPage}); }