import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pmd/utils/debounce.dart'; import 'package:pmd/home_page/bloc/bloc.dart'; import 'package:pmd/home_page/bloc/events.dart'; import 'package:pmd/home_page/bloc/state.dart'; import 'package:pmd/models/card_data.dart'; import 'package:pmd/details_page/details_page.dart'; import 'package:pmd/data/repositories/api_interface.dart'; import 'package:pmd/data/repositories/mock_repository.dart'; import '../data/repositories/potter_repository.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 { final TextEditingController _searchController = TextEditingController(); final _scrollController = ScrollController(); @override void initState() { WidgetsBinding.instance.addPostFrameCallback((_) { context.read().add(const HomeLoadDataEvent()); }); _scrollController.addListener(_onNextPageListener); super.initState(); } @override void dispose() { _searchController.dispose(); _scrollController.dispose(); super.dispose(); } void _onNextPageListener() { if (_scrollController.offset >= _scrollController.position.maxScrollExtent) { final bloc = context.read(); if (!bloc.state.isPaginationLoading) { bloc.add(HomeLoadDataEvent( search: _searchController.text, nextPage: bloc.state.data?.nextPage)); } } } Future _onRefresh() { context .read() .add(HomeLoadDataEvent(search: _searchController.text)); return Future.value(null); } void _onSearchInputChange(search) { Debounce.run( action: () => context.read().add(HomeLoadDataEvent(search: search))); } void _showSnackBar(BuildContext context, String text) { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(text), duration: const Duration(seconds: 2), backgroundColor: Colors.black54, )); }); } void _navigateToDetailsPage(BuildContext context, CardData data) { Navigator.push( context, CupertinoPageRoute(builder: (context) => DetailsPage(data: data)), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Column( children: [ Padding( padding: const EdgeInsets.only(right: 30, left: 30, top: 20, bottom: 20), child: CupertinoSearchTextField( controller: _searchController, onChanged: _onSearchInputChange, ), ), BlocBuilder( builder: (context, state) => state.error != null ? Text( state.error ?? "", style: Theme.of(context) .textTheme .headlineSmall ?.copyWith(color: Colors.red), ) : state.isLoading ? const Padding( padding: EdgeInsets.only(top: 20), child: CircularProgressIndicator(), ) : Expanded( child: RefreshIndicator( onRefresh: _onRefresh, child: ListView.separated( controller: _scrollController, padding: const EdgeInsets.symmetric( vertical: 20, horizontal: 30), separatorBuilder: (context, index) => const SizedBox(height: 20), itemCount: state.data?.data?.length ?? 0, itemBuilder: (context, index) { final data = state.data?.data?[index]; return data == null ? const SizedBox.shrink() : _Card.fromData( data, onLike: (String text) => _showSnackBar(context, text), onTap: () => _navigateToDetailsPage(context, data), ); }, ), ), ), ), BlocBuilder( builder: (context, state) => state.isPaginationLoading ? const CircularProgressIndicator() : const SizedBox.shrink(), ), ], ), ); } }