import 'package:dio/dio.dart'; import 'package:flappy_search_bar/flappy_search_bar.dart'; import 'package:flutter/material.dart'; import '../../constants.dart'; import '../../events/eventbus.dart'; import '../../events/events.dart'; import '../../generated/l10n.dart'; import '../../models/business.dart'; import '../../models/product.dart'; import '../../pages/product_detail_page.dart'; import '../../utils/http_util.dart'; import '../../utils/utils.dart'; import '../../widgets/general/bottom_nav.dart'; import '../../widgets/general/breadcrumbs.dart'; import '../../widgets/general/navigationbar.dart'; import 'product_item.dart'; class ProductSearch extends StatefulWidget { final Business business; const ProductSearch(this.business, {Key key}) : super(key: key); @override State createState() => ProductSearchState(); } class ProductSearchState extends State { double sideSpace = 0; double mainSpace = 1200; double rate = 1; int page = 1; int numPerPage = 10; int lastResultSize = 0; double lastBottomPosition = 0; String lastKeyword = ''; SearchBarController _controller = SearchBarController(); @override Widget build(BuildContext context) { if (MediaQuery.of(context).size.width <= 1200) { mainSpace = MediaQuery.of(context).size.width; sideSpace = 0; } else { mainSpace = 1200; sideSpace = (MediaQuery.of(context).size.width - 1200) / 2; } rate = mainSpace / 1200; return Scaffold( appBar: MiniNavigationBar( title: S.of(context).search_product, back: true, breadCrumbs: [ BreadCrumb(S.of(context).search_product, null), ], breadCrumbHeight: Constants.BREADCRUMB_HEIGHT, ), drawer: null, body: SafeArea( child: Container( child: Row( children: [ Container( width: sideSpace, ), Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: NotificationListener( child: SearchBar( searchBarController: _controller, minimumChars: 2, hintText: S.of(context).enter_keyword, cancellationWidget: Text( S.of(context).cancel, ), onSearch: search, onItemFound: (Product searchProduct, int index) { return ProductItem( searchProduct, widget.business, horizontal: true, ); }, onError: (error) { return Center( child: Text("$error"), ); }, emptyWidget: Center( child: Text( S.of(context).empty_result_change_keyword, ), ), ), onNotification: (notification) { if (notification.metrics.atEdge) { print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}'); if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) { if (notification.metrics.pixels > lastBottomPosition) { lastBottomPosition = notification.metrics.pixels; page += 1; _controller.replayLastSearch(); } } } return true; }, ), ), ), Container( width: sideSpace, ), ], ), ), ), bottomNavigationBar: BottomNav(), ); } Future> search(String keyword) async { if (lastKeyword != keyword) { page = 1; } lastKeyword = keyword; var result = await HttpUtil.httpGet('v1/search-store-product2', queryParameters: { 'store_id': widget.business.id, 'keyword': keyword, 'page': page, 'num_per_page': numPerPage, }, returnError: true, ); if (result is DioError) { if (result.response != null) { throw RuntimeError(result.response.data); } else { throw RuntimeError(result.message); } } else if (result != null && result is List) { lastBottomPosition = 0; var r = result.map((e) => Product.fromJson(e)).toList(); lastResultSize = r.length; if (lastResultSize < numPerPage) { page = 1; } return r; } return []; } @override void initState() { super.initState(); eventBus.on().listen((event) { if (mounted) { setState(() {}); } }); } void _showProductDetail(Product p) { Navigator.push( context, MaterialPageRoute( builder: (context) => ProductDetailPage( product: p, business: widget.business, )), ); } }