import 'dart:developer'; import 'dart:ui'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:fast_cached_network_image/fast_cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_in_store_app_version_checker/flutter_in_store_app_version_checker.dart'; import 'package:muaawana/utils/utils_singleton.dart'; import 'package:muaawana/widgets/missing_fields_dialog.dart'; import '../../../models/ads/Advertisement.dart'; import '../../../providers/bookmark_provider.dart'; import '../../../providers/home_provider.dart'; import '../../../providers/language_provider.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../config/app_constant.dart'; import '../../../config/lang_enum.dart'; import '../../../providers/map_provider.dart'; import '../../../utils/text_style.dart'; import '../../../utils/text_widget.dart'; import '../../../widgets/new_app_update_dialog.dart'; import '../Web View/Store/StorModel.dart'; import '../Web View/Store/StoreRequestProvider.dart'; import '../Web View/WebViewScreen.dart'; import '../booking/booking_product_screen.dart'; import 'all_services/service_detail.dart'; import 'widgets/products_widget.dart'; import 'widgets/services_widget.dart'; import 'widgets/category_widget.dart'; import '../../../config/style.dart'; import 'widgets/header_widget.dart'; import '../../../config/size.dart'; import 'widgets/shimmerLoader.dart'; class HomeScreenClient extends StatefulWidget { const HomeScreenClient({Key? key}) : super(key: key); @override State createState() => _HomeScreenClientState(); } class _HomeScreenClientState extends State { final hm = SizeConfig.heightMultiplier; final wm = SizeConfig.widthMultiplier; final tm = SizeConfig.textMultiplier; int _currentIndex = 0; final _versionChecker = InStoreAppVersionChecker(); final CarouselSliderController _controller = CarouselSliderController(); final TextEditingController _searchController = TextEditingController(); @override void initState() { _init(); if (util.user != null) { if (util.user!.phonenumber == null || util.user!.phonenumber!.isEmpty) { Future.delayed( const Duration(seconds: 1), () async => await showMissingDataDialog(), ); } } super.initState(); _checkVersion(); } @override void dispose() { super.dispose(); _searchController.dispose(); } void _init() { Future.microtask(() => context.read().fetchAds()); context.read().getProducts( 0, 20); context.read().setMapComponents(); context.read().initLoc(); } void _checkVersion() async { log("Entering version checker:"); _versionChecker.checkUpdate().then((value) { log(value.appURL.toString()); // Return the app url log(value.canUpdate.toString()); // Return true if update is available log(value.currentVersion.toString()); // Return current app version log(value.errorMessage .toString()); // Return error message if found else it will return null log(value.newVersion.toString()); // Return the new app version if (value.canUpdate) { Future.delayed( const Duration(seconds: 1), () async => await showUpdateAppDialog(), ); } }); } Future showUpdateAppDialog() async => await showDialog( barrierDismissible: false, context: context, builder: (context) => const NewAppUpdateDialog(), ); Future showMissingDataDialog() async => await showDialog( context: context, builder: (context) => const MissingFieldsDialog(), ); @override Widget build(BuildContext context) { final langProvider = Provider.of(context); return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, body: GestureDetector( onTap: () { FocusScope.of(context).unfocus(); }, child: SingleChildScrollView( child: Column( children: [ MySliverAppBar( textEditingController: _searchController, ), Consumer( builder: (context, categoryVisibilityProvider, _) { return const HomeCategoriesWidget(); }), Consumer( builder: (context, homeProvider, _) => homeProvider .adsLoader ? const AdsBannerShimmerWidget() : Consumer( builder: (context, homeProvider, _) { List imagesList = []; if (homeProvider.adsList.isNotEmpty) { imagesList = homeProvider.adsList .map((e) => Padding( padding: const EdgeInsets.all(1.0), child: AdsBanner(ad: e), )) .toList(); } return Padding( padding: EdgeInsetsDirectional.only(start: 23, end: 23), child: Column( children: [ CarouselSlider( items: imagesList, carouselController: _controller, options: CarouselOptions( clipBehavior: Clip.antiAliasWithSaveLayer, padEnds: false, aspectRatio: 220 / 100, viewportFraction: 1, initialPage: 0, enableInfiniteScroll: true, reverse: false, autoPlay: true, autoPlayInterval: const Duration(seconds: 5), autoPlayAnimationDuration: const Duration(milliseconds: 1000), enlargeCenterPage: false, onPageChanged: (index, reason) {setState(() { _currentIndex = index; });}, scrollDirection: Axis.horizontal, ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: homeProvider.adsList.asMap().entries.map((entry) { return Container( width: 8.0, height: 8.0, margin: const EdgeInsets.symmetric( vertical: 10.0, horizontal: 3.0), decoration: BoxDecoration( shape: BoxShape.circle, color: _currentIndex == entry.key ? Theme.of(context).colorScheme.onSurface : Theme.of(context).colorScheme.onSurface.withOpacity(0.3), ), ); }).toList(), ), ], ), ); }, ), ), Consumer( builder: (context, categoryVisibilityProvider, _) { return const HomeServicesWidget(); }, ), Consumer( builder: (context, categoryVisibilityProvider, _) { return const HomeProductsWidget(); }, ), Consumer( builder: (context, storeProvider, _) { if (storeProvider.isLoading) { return StoreCardShimmerWidget(); } final stores = storeProvider.requests; if (stores.isEmpty) { return Padding( padding: EdgeInsets.all(hm * 2), child: Txt( text: langProvider.translate("No stores available"), style: tS("lato_regular", 14, FontWeight.w400, AppStyle.textFieldHintColor), ), ); } return SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsetsDirectional.only(start: hm *2 ,bottom:hm * 1,top:hm * 2 ), child: Txt( text: langProvider.translate("Shop from here"), style: tS("lato_extra_bold", 20, FontWeight.bold, Theme.of(context).brightness == Brightness.dark? AppNewStyle.darkPrimaryButton:AppNewStyle.primary), ), ), ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemCount: stores.length, itemBuilder: (context, index) { final store = stores[index]; final faviconUrl ='https://www.google.com/s2/favicons?sz=64&domain_url=${store.url}'; return storCard(store,faviconUrl); }, ), ], ), ); }, ), const SizedBox(height: 100), ], ), ) ), ); } Widget storCard(StoreRequest store,String faviconUrl){ return Padding( padding: const EdgeInsets.all(8.0), child: InkWell( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => WebViewScreen(storeUrl: store.url ?? '',name:store.name ?? ''), ), ); }, child: Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(12), border: Border.all( color: Theme.of(context).dividerColor.withOpacity(0.2), width: 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(Theme.of(context).brightness == Brightness.dark ? 0.4 : 0.08), blurRadius: 8, offset: const Offset(0, 2), spreadRadius: 1, ), ], ), child: Padding( padding: EdgeInsets.all( wm * 5), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(store.name!,style: TextStyle( color: Theme.of(context).colorScheme.onSurface, fontSize: 18, fontFamily: 'Inter', fontWeight: FontWeight.w600, height: 1.22, ),), ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.network( faviconUrl, width: wm * 14, height: wm * 14, fit: BoxFit.cover, errorBuilder: (_, __, ___) => const Icon(Icons.store, size: 32), ), ), ], ), ), ), ), ); } } class AdsBanner extends StatelessWidget { final Advertisement ad; const AdsBanner({super.key, required this.ad}); @override Widget build(BuildContext context) { final wm = SizeConfig.widthMultiplier; return GestureDetector( onTap: () { if (ad.service == null && ad.product == null) { _launchUrl(Uri.https(ad.link!)); } else if (ad.service != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => ServiceDetailsScreen( service: ad.service!, ), ), ); } else if (ad.product != null) { Navigator.push( context, MaterialPageRoute( builder: (context) => BookingProductScreen( product: ad.product!, ), ), ); } }, child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Stack( children: [ SizedBox( width: wm * 100, height: wm * 148, child: ImageFiltered( imageFilter: ImageFilter.blur(sigmaX: 2.0, sigmaY: 2.0), child: ad.images != null && ad.images!.isNotEmpty ? FastCachedImage( url: "https://server.muaawana.com${ad.images?[0].url}", fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => const Icon(Icons.error), width: wm * 100, height: wm * 148, ) : SizedBox(), ), ), Align( alignment: Alignment.center, child: ad.images!.isEmpty ? Image.asset(Consts.adImageNotFound) : FastCachedImage( url: "https://server.muaawana.com${ad.images?[0].url}", errorBuilder: (context, error, stackTrace) => const Icon(Icons.error), loadingBuilder: (context, progress) { if (progress.isDownloading) { return const AdsBannerShimmerWidget(); } return const SizedBox(); // or your placeholder }, width: wm * 100, height: wm * 148, ), ), ], ), ), ); } Future _launchUrl(Uri url) async { if (!await launchUrl(url)) { throw Exception('Could not launch $url'); } } }