diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 5e6b542..9773e44 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Mon Feb 17 08:57:28 IRST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip diff --git a/lib/core/routes/app_router.dart b/lib/core/routes/app_router.dart index a8e84c9..3a52931 100644 --- a/lib/core/routes/app_router.dart +++ b/lib/core/routes/app_router.dart @@ -4,75 +4,102 @@ import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:go_router/go_router.dart'; import 'package:proxibuy/presentation/providers/cubit/user_info_cubit.dart'; import 'package:proxibuy/presentation/ui/screens/auth/auth_page.dart'; +import 'package:proxibuy/presentation/ui/screens/home/explore_screen.dart'; import 'package:proxibuy/presentation/ui/screens/home/home_page.dart'; +import 'package:proxibuy/presentation/ui/screens/home/home_screen.dart'; +import 'package:proxibuy/presentation/ui/screens/home/setting_screen.dart'; +import 'package:proxibuy/presentation/ui/screens/product/product_page.dart'; class AppRouter { static final initial = '/'; - static final home = '/home'; static final explore = '/explore'; static final setting = '/settings'; + static final product = '/product'; + + static List home = [initial, explore, setting]; static final GlobalKey navigatorKey = GlobalKey(); - GoRouter createRouter = GoRouter( + static GoRouter createRouter = GoRouter( navigatorKey: navigatorKey, - initialLocation: home, + initialLocation: initial, routes: [ - GoRoute( - path: home, - builder: (BuildContext context, GoRouterState state) { - return BlocConsumer( - listener: (context, state) { - if (state is UserInfoSuccess || state is UserInfoFail) { - FlutterNativeSplash.remove(); - } - }, - builder: (context, state) { - if (state is UserInfoSuccess) { - return const HomePage(); - } else { - return const AuthPage(); - } - }, - ); - }, - routes: [], - ), - // StatefulShellRoute.indexedStack( - // builder: (context, state, navigationShell) => - // BlocBuilder( - // builder: (context, state) { - // if (state is UserInfoSuccess) { - // return CustomBottomNav(child: navigationShell); - // } else { - // return AuthPage(); - // } - // }, - // ), - // branches: [ - // StatefulShellBranch(routes: [ - // GoRoute( - // path: initial, - // builder: (context, state) { - // return HomeScreen(); - // }, - // ), - // ]), - // StatefulShellBranch(routes: [ - // GoRoute( - // path: explore, - // builder: (context, state) => ExploreScreen(), - // ), - // ]), - // StatefulShellBranch(routes: [ - // GoRoute( - // path: setting, - // builder: (context, state) => SettingScreen(), - // ), - // ]), + // GoRoute( + // path: initial, + // builder: (BuildContext context, GoRouterState state) { + // return BlocConsumer( + // listener: (context, state) { + // if (state is UserInfoSuccess || state is UserInfoFail) { + // FlutterNativeSplash.remove(); + // } + // }, + // builder: (context, state) { + // if (state is UserInfoSuccess) { + // return const HomePage(); + // } else { + // return const AuthPage(); + // } + // }, + // ); + // }, + // routes: [ + // GoRoute( + // path: product, + // builder: (BuildContext context, GoRouterState state) { + // return ProductPage(); + // }, + // routes: [], + // ), // ], // ), + + StatefulShellRoute.indexedStack( + builder: (context, state, navigationShell) => + BlocBuilder( + builder: (context, userState) { + if (userState is UserInfoSuccess) { + if (home.contains(state.fullPath)) { + return HomePage(child: navigationShell); + } else { + return navigationShell; + } + } else { + return AuthPage(); + } + }, + ), + branches: [ + StatefulShellBranch(routes: [ + GoRoute( + path: initial, + builder: (context, state) { + return HomeScreen(); + }, + routes: [ + GoRoute( + path: product, + builder: (BuildContext context, GoRouterState state) { + return ProductPage(); + }, + routes: [], + ), + ]), + ]), + StatefulShellBranch(routes: [ + GoRoute( + path: explore, + builder: (context, state) => ExploreScreen(), + ), + ]), + StatefulShellBranch(routes: [ + GoRoute( + path: setting, + builder: (context, state) => SettingScreen(), + ), + ]), + ], + ), ], ); } diff --git a/lib/core/utils/my_custom_scroll_behavior.dart b/lib/core/utils/my_custom_scroll_behavior.dart new file mode 100644 index 0000000..8a87a3c --- /dev/null +++ b/lib/core/utils/my_custom_scroll_behavior.dart @@ -0,0 +1,11 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +class MyCustomScrollBehavior extends MaterialScrollBehavior { + // Override behavior methods and getters like dragDevices + @override + Set get dragDevices => { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + }; +} diff --git a/lib/main.dart b/lib/main.dart index 5040048..b52d27b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:proxibuy/core/routes/app_router.dart'; +import 'package:proxibuy/core/utils/my_custom_scroll_behavior.dart'; import 'package:proxibuy/data/storage/shared_preferences_helper.dart'; import 'package:proxibuy/presentation/providers/cubit/them_mode_cubit.dart'; import 'package:proxibuy/presentation/providers/cubit/user_info_cubit.dart'; @@ -43,11 +44,13 @@ class _MyAppState extends State { return BlocBuilder( builder: (context, themeState) { return MaterialApp.router( - routerConfig: AppRouter().createRouter, + routerConfig: AppRouter.createRouter, + restorationScopeId: 'app', title: 'Proxibuy', theme: appTheme, darkTheme: darkTheme, themeMode: themeState, + scrollBehavior: MyCustomScrollBehavior(), debugShowCheckedModeBanner: false, ); }, diff --git a/lib/presentation/ui/screens/auth/auth_page.dart b/lib/presentation/ui/screens/auth/auth_page.dart index c8ff015..c342b65 100644 --- a/lib/presentation/ui/screens/auth/auth_page.dart +++ b/lib/presentation/ui/screens/auth/auth_page.dart @@ -42,7 +42,10 @@ class _AuthPageState extends State { body: Responsive(context).builder( mobile: onBoarding ? carousle( - withNavs: true, autoPlay: false, enableInfiniteScroll: false) + withNavs: true, + autoPlay: false, + enableInfiniteScroll: false, + ) : auth(context), tablet: Row( children: [ @@ -50,10 +53,10 @@ class _AuthPageState extends State { child: Padding( padding: const EdgeInsets.all(50.0), child: carousle( - withNavs: false, - autoPlay: true, - enableInfiniteScroll: true, - height: MediaQuery.sizeOf(context).height * 0.8), + withNavs: false, + autoPlay: true, + enableInfiniteScroll: true, + ), ), ), Expanded( @@ -68,10 +71,10 @@ class _AuthPageState extends State { child: Padding( padding: const EdgeInsets.all(80.0), child: carousle( - withNavs: false, - autoPlay: true, - enableInfiniteScroll: true, - height: MediaQuery.sizeOf(context).height * 0.8), + withNavs: false, + autoPlay: true, + enableInfiniteScroll: true, + ), ), ), Expanded( @@ -182,13 +185,13 @@ class _AuthPageState extends State { ); } - CarouselSliderWidget carousle( - {required final bool withNavs, - required final bool autoPlay, - required final bool enableInfiniteScroll, - double? height}) { + CarouselSliderWidget carousle({ + required final bool withNavs, + required final bool autoPlay, + required final bool enableInfiniteScroll, + }) { return CarouselSliderWidget( - height: height ?? MediaQuery.sizeOf(context).height, + height: MediaQuery.sizeOf(context).height * 0.8, items: [ OnboardingBannerModel( image: Assets.image.onboarding.banner1, diff --git a/lib/presentation/ui/screens/home/home_page.dart b/lib/presentation/ui/screens/home/home_page.dart index 5441acc..5e62f0c 100644 --- a/lib/presentation/ui/screens/home/home_page.dart +++ b/lib/presentation/ui/screens/home/home_page.dart @@ -1,7 +1,9 @@ import 'package:bottom_navy_bar/bottom_navy_bar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; import 'package:proxibuy/core/gen/assets.gen.dart'; +import 'package:proxibuy/core/routes/app_router.dart'; import 'package:proxibuy/core/utils/empty_space.dart'; import 'package:proxibuy/data/models/screen_model.dart'; import 'package:proxibuy/presentation/providers/cubit/them_mode_cubit.dart'; @@ -12,7 +14,9 @@ import 'package:proxibuy/presentation/ui/theme/responsive.dart'; import 'package:proxibuy/presentation/ui/theme/theme.dart'; class HomePage extends StatefulWidget { - const HomePage({super.key}); + final Widget child; + + const HomePage({super.key, required this.child}); @override State createState() => _HomePageState(); @@ -25,6 +29,7 @@ class _HomePageState extends State { ScreenModel(title: 'Explore', icon: Assets.icon.outline.map), ScreenModel(title: 'Settings', icon: Assets.icon.outline.setting), ]; + @override Widget build(BuildContext context) { return Responsive(context).builder( @@ -37,26 +42,6 @@ class _HomePageState extends State { ), ), mobile: Scaffold( - appBar: AppBar( - title: Text( - "Proxibuy", - style: Theme.of(context).textTheme.headlineSmall, - ), - actions: [ - IconButton( - icon: Assets.icon.outline.notificationBing - .svg(color: Theme.of(context).colorScheme.onSurface), - onPressed: () {}, - ), - 12.w, - IconButton( - icon: Icon(Icons.brightness_6), - onPressed: () { - context.read().changeTheme(); - }, - ), - ], - ), body: body(), bottomNavigationBar: bottomNavigationBar(context), ), @@ -207,17 +192,24 @@ class _HomePageState extends State { ); } - IndexedStack body() { - return IndexedStack( - sizing: StackFit.expand, - index: selectedIndex, - children: [HomeScreen(), ExploreScreen(), SettingScreen()], - ); + Widget body() { + return widget.child; } void _onItemTapped(BuildContext context, int index) { setState(() { selectedIndex = index; }); + switch (index) { + case 0: + context.go(AppRouter.initial); + break; + case 1: + context.go(AppRouter.explore); + break; + case 2: + context.go(AppRouter.setting); + break; + } } } diff --git a/lib/presentation/ui/screens/home/home_screen.dart b/lib/presentation/ui/screens/home/home_screen.dart index 21422d1..c60abee 100644 --- a/lib/presentation/ui/screens/home/home_screen.dart +++ b/lib/presentation/ui/screens/home/home_screen.dart @@ -1,6 +1,14 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; import 'package:proxibuy/core/gen/assets.gen.dart'; +import 'package:proxibuy/core/routes/app_router.dart'; +import 'package:proxibuy/core/utils/empty_space.dart'; +import 'package:proxibuy/presentation/providers/cubit/them_mode_cubit.dart'; +import 'package:proxibuy/presentation/ui/theme/colors.dart'; import 'package:proxibuy/presentation/ui/theme/responsive.dart'; +import 'package:proxibuy/presentation/ui/widgets/carousel/carousel_slider_widget.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -17,58 +25,674 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { - final defaultBorder = OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: - BorderSide(color: Theme.of(context).colorScheme.surface, width: 2)); - return Responsive(context).builder( - mobile: Scaffold( - body: Padding( - padding: const EdgeInsets.all(16.0), + return Responsive(context) + .builder(mobile: mobile(context), desktop: desktop(context)); + } + + Scaffold desktop(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: 1600), child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - // ElevatedButton( - // onPressed: () async { - // final notifPer = await requestNotificationPermission(); - - // if (notifPer) { - // if (kIsWeb) { - // NotificationServiceWeb.showNotification(); - // } else { - // await NotificationSrviceAndroid.showCustomNotification(); - // } - // } - // }, - // child: Text('Show Notification')), - - Flexible( - child: Container( - constraints: BoxConstraints(maxWidth: 800), - child: TextField( - textInputAction: TextInputAction.search, - onSubmitted: (value) { - print(value); - }, - decoration: InputDecoration( - hintText: 'what are you looking for?', - suffixIcon: Padding( - padding: const EdgeInsets.all(12.0), - child: Assets.icon.outline.search.svg( - color: Theme.of(context).colorScheme.onSurface, - width: 16, - height: 16), + children: [ + 12.h, + titleDivider(context, title: 'what\'s on your mind?', top: 16), + SizedBox( + width: double.infinity, + height: 40, + child: ListView.builder( + itemCount: 20, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + padding: EdgeInsets.symmetric(horizontal: 10), + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Container( + width: 200, + height: 40, + margin: EdgeInsets.symmetric(horizontal: 6), + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface, ), - enabledBorder: defaultBorder, - border: defaultBorder), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.car_crash), + 8.w, + Text('Category') + ], + ), + ); + }, ), - )), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + titleDivider(context, + title: 'Top 10 Discount & Offers'), + CarouselSliderWidget( + items: ['1', '2', '3', '4'], + height: 320, + viewportFraction: 0.9, + onPageBuilder: (context, item) { + return ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://pixcap.com/cdn/library/templates/f1ee999f-4f9e-4b5d-83b5-51d04681a999/thumbnail/9158b87d-1079-4973-9514-ee4ada0adf54_transparent_1422_800.webp', + fit: BoxFit.cover, + width: double.infinity, + ), + ); + }, + ), + ], + ), + ), + 12.w, + Expanded( + child: flashSales(context), + ) + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: seasonalDiscounts(context)), + 12.w, + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + titleDivider(context, title: 'special discount'), + CarouselSliderWidget( + items: ['1', '2', '3', '4'], + height: 280, + viewportFraction: 0.9, + onPageBuilder: (context, item) { + return ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://pixcap.com/cdn/library/templates/f1ee999f-4f9e-4b5d-83b5-51d04681a999/thumbnail/9158b87d-1079-4973-9514-ee4ada0adf54_transparent_1422_800.webp', + fit: BoxFit.cover, + width: double.infinity, + ), + ); + }, + ), + ], + )), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + titleDivider(context, title: 'special discount'), + CarouselSliderWidget( + items: ['1', '2', '3', '4'], + height: 280, + viewportFraction: 0.9, + onPageBuilder: (context, item) { + return ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://pixcap.com/cdn/library/templates/f1ee999f-4f9e-4b5d-83b5-51d04681a999/thumbnail/9158b87d-1079-4973-9514-ee4ada0adf54_transparent_1422_800.webp', + fit: BoxFit.cover, + width: double.infinity, + ), + ); + }, + ), + ], + )), + 12.w, + Expanded(child: firstPurchaseDiscount(context)), + ], + ), + 64.h ], ), ), ), - desktop: Scaffold( - body: SizedBox(), - )); + ), + ); + } + + Scaffold mobile(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Padding( + padding: const EdgeInsets.only(left: 2.0), + child: SelectableText( + "Proxibuy", + style: Theme.of(context).textTheme.headlineSmall, + ), + ), + actions: [ + IconButton( + icon: Assets.icon.outline.notificationBing + .svg(color: Theme.of(context).colorScheme.onSurface), + onPressed: () {}, + ), + 12.w, + IconButton( + icon: Icon(Icons.brightness_6), + onPressed: () { + context.read().changeTheme(); + }, + ), + 10.w + ], + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + searchBar(context), + categories(context), + titleDivider(context, title: 'Top 10 Discount & Offers'), + CarouselSliderWidget( + items: ['1', '2', '3', '4'], + height: 180, + viewportFraction: 0.8, + onPageBuilder: (context, item) { + return ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://pixcap.com/cdn/library/templates/f1ee999f-4f9e-4b5d-83b5-51d04681a999/thumbnail/9158b87d-1079-4973-9514-ee4ada0adf54_transparent_1422_800.webp', + fit: BoxFit.cover, + width: double.infinity, + ), + ); + }, + ), + flashSales(context, top: 12), + titleDivider(context, title: 'special discount'), + CarouselSliderWidget( + items: ['1', '2', '3', '4'], + height: 180, + viewportFraction: 0.8, + onPageBuilder: (context, item) { + return ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://pixcap.com/cdn/library/templates/f1ee999f-4f9e-4b5d-83b5-51d04681a999/thumbnail/9158b87d-1079-4973-9514-ee4ada0adf54_transparent_1422_800.webp', + fit: BoxFit.cover, + width: double.infinity, + ), + ); + }, + ), + seasonalDiscounts(context, top: 12), + titleDivider(context, title: 'Crafting something for you'), + CarouselSliderWidget( + items: ['1', '2', '3', '4'], + height: 180, + viewportFraction: 0.8, + onPageBuilder: (context, item) { + return ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://pixcap.com/cdn/library/templates/f1ee999f-4f9e-4b5d-83b5-51d04681a999/thumbnail/9158b87d-1079-4973-9514-ee4ada0adf54_transparent_1422_800.webp', + fit: BoxFit.cover, + width: double.infinity, + ), + ); + }, + ), + firstPurchaseDiscount(context), + 12.h + ], + ), + ), + ); + } + + Column firstPurchaseDiscount(BuildContext context) { + return Column( + children: [ + titleDivider(context, title: 'First Purchase Discount'), + SizedBox( + width: double.infinity, + height: 280, + child: ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemCount: 20, + padding: EdgeInsets.symmetric(horizontal: 16), + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Container( + width: 180, + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.only( + topLeft: index == 0 ? Radius.circular(16) : Radius.zero, + bottomLeft: + index == 0 ? Radius.circular(16) : Radius.zero, + topRight: + index == 20 - 1 ? Radius.circular(16) : Radius.zero, + bottomRight: index == 20 - 1 + ? Radius.circular(16) + : Radius.zero)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.network( + 'https://s3-alpha-sig.figma.com/img/6ec2/c17a/beca4d2eb02da53e80d47f73d5f6b56d?Expires=1740960000&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=VvgWny6Sfh-HI0Yp2stzKejafivtWKDI9I5FKuSAQ8VqNLgiT4c5zB5m-PX174NFrSDvkocDlUIZ33gM~hrAafD8UreEvYfs30sB0ZrIPR7kSPcms~d9ArYJRsXSQ7w8-cv~RHWruGfbw462CrOdvJadQ3ZReRkK9CJsPCg2EcU9mr~hlcyx84QxGx0rw~FdBvHt99pzX0gDMWpr0kC9Om-eM45Fylmcb91d5AGh2sxtf0NXyNwt83jjfKC-VOZHt5wbjbZq3NQNGmrwWTwzLOauhjtgOsC32EbsPim3O~8CrKJAQ-TVOSXN4B15ygiFxZ1WX2z6l-LnjFghzv9Z3w__', + width: double.infinity, + height: 120, + fit: BoxFit.cover, + ), + ), + ), + 12.h, + SelectableText( + 'McDonald\'s', + style: Theme.of(context).textTheme.titleMedium?.copyWith( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + ), + 12.h, + SelectableText('Fast food', + maxLines: 1, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + overflow: TextOverflow.ellipsis, + )), + 8.h, + SelectableText('Up to 20% Off', + maxLines: 1, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + overflow: TextOverflow.ellipsis, + )), + 8.h, + Row( + children: [ + Icon( + Icons.star_border_outlined, + color: semanticGreen, + ), + 4.w, + Text('4.5'), + ], + ) + ], + ), + ); + }, + ), + ), + ], + ); + } + + Column seasonalDiscounts(BuildContext context, {final double top = 32}) { + return Column( + children: [ + titleDivider(context, title: 'Seasonal Discount', top: top), + SizedBox( + width: double.infinity, + height: 100 * 2 + 12, + child: GridView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + padding: EdgeInsets.symmetric(horizontal: 16), + physics: BouncingScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + mainAxisSpacing: 16, + crossAxisSpacing: 12, + childAspectRatio: 0.3, + crossAxisCount: 2), + itemBuilder: (context, index) { + return InkWell( + onTap: () { + context.go(AppRouter.product); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface), + child: Row( + children: [ + Image.network( + 'https://s3-alpha-sig.figma.com/img/55dd/f119/e880815733401c0400dc01734b64e83a?Expires=1740960000&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=HtKhelOfFUI1gplOzBHtfDP4ljCPECuypXWNc88VVBfYaQ2knCk0qPFwd4mjcH7Trru2W8S4hpDUeo-ztViRi~83USuULrSE0558MtBC~3TjS5S~Jm7eaDQO3YtvnsRtPK2xDamOJU80Xnkq0YPPkB~EVb8jVKF-b8JF2jdjEwon6fcltZDb7jTFJU8L9pYQQAhFxRV1QC8dOwnTT1zknm9iDNRDVGSj~VKwPpQX7daYzAf7b6DuLF4sk7DmX2fDdgF54pcYZjc1UOoubraM-sf-RKnh2JD8Vl~XK9-drzg8~t9CT99dxxHYp6udCLlya~dHNhIYjd5R4anoDQQLPg__', + width: 100, + height: 100, + fit: BoxFit.cover, + ), + 8.w, + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + 'boots', + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(overflow: TextOverflow.ellipsis), + maxLines: 1, + ), + 12.h, + Row( + children: [ + Icon( + Icons.shopping_bag_outlined, + size: 16, + ), + 8.w, + Expanded( + child: SelectableText( + 'Columbia Sportswear', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + ), + ), + ], + ), + 8.h, + Row( + children: [ + Icon( + CupertinoIcons.ticket, + size: 16, + ), + 8.w, + Expanded( + child: SelectableText( + '22 - 35% off', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + color: semanticRed, + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + ), + ), + ], + ) + ], + ), + )) + ], + ), + ), + ), + ); + }, + ), + ), + ], + ); + } + + Column flashSales(BuildContext context, {double top = 32}) { + return Column( + children: [ + titleDivider(context, title: 'Flash Sale', top: top), + SizedBox( + width: double.infinity, + height: 348, + child: ListView.builder( + itemCount: 20, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + padding: EdgeInsets.symmetric(horizontal: 10), + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return InkWell( + onTap: () { + context.go(AppRouter.product); + }, + child: Container( + width: 200, + margin: EdgeInsets.symmetric(horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.surface, + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Icon( + Icons.timer_outlined, + color: semanticRed, + size: 32, + ), + 12.w, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + 'Limited time deal', + style: + Theme.of(context).textTheme.titleMedium, + ), + SelectableText('08: 35”:48’', + style: Theme.of(context) + .textTheme + .titleSmall + ?.copyWith(color: semanticRed)) + ], + ) + ], + ), + ), + AspectRatio( + aspectRatio: 16 / 9, + child: Image.network( + 'https://s3-alpha-sig.figma.com/img/7919/da3d/6e638d21e4b8cec7cda36bd4fdec2012?Expires=1740960000&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=OiH30jVJjAo~EZTdnnGakp0gZzdPFWPHrthl4iSPv8X7d-pGh35sycz42ZvNekboa2Hyp22O4mx8YUOn~SUVHuIKsxmRblfb-vlGfCwqg9xZL16R8pQV6V~v8FpAvFIQL1id6EgfuL4VcnADASZ7m2XjJ6CDNd~c~-k5N4MwcKUxvFNBFt7OhLNdB9bXYuAT~sfiQAai3B~JDaikS0SD48irIGaXeBi4KNAtLlFGrrGDK3KLbyfetvXwRF5ml7G0RBzEbR26WvwkgdX39B7GjCxjQzBvExI6V-JM76oc2YZiSbQIE89Qpvu2ErP77Kc6dW4aOTPGQ5RJXxPzj2vWDA__', + width: double.infinity, + height: 100, + fit: BoxFit.cover, + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + 'Amul Cheese Slices', + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + ), + 12.h, + Row( + children: [ + Icon(Icons.location_on_outlined), + 8.w, + Expanded( + child: SelectableText( + 'Fresno (750m away)', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + )) + ], + ), + 8.h, + Row( + children: [ + Icon(Icons.monetization_on_outlined), + 8.w, + Expanded( + child: SelectableText( + '70 \$ - 53 \$ (13% off)', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + )) + ], + ), + 8.h, + Center( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: semanticGreen, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(16))), + onPressed: () {}, + child: Text( + 'Reservation', + )), + ) + ], + ), + ) + ], + )), + ); + }, + ), + ), + ], + ); + } + + Column categories(BuildContext context) { + return Column( + children: [ + titleDivider(context, title: 'what\'s on your mind?', top: 16), + SizedBox( + width: double.infinity, + height: 64, + child: ListView.builder( + itemCount: 20, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + padding: EdgeInsets.symmetric(horizontal: 10), + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Container( + width: 64, + height: 64, + margin: EdgeInsets.symmetric(horizontal: 6), + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).colorScheme.surface, + ), + child: Center( + child: Icon(Icons.abc), + ), + ); + }, + ), + ), + ], + ); + } + + Widget searchBar( + BuildContext context, + ) { + final defaultBorder = OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: + BorderSide(color: Theme.of(context).colorScheme.surface, width: 2)); + + return Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Flexible( + child: Container( + constraints: BoxConstraints(maxWidth: 800), + child: TextField( + textInputAction: TextInputAction.search, + onSubmitted: (value) { + print(value); + }, + decoration: InputDecoration( + hintText: 'what are you looking for?', + suffixIcon: Padding( + padding: const EdgeInsets.all(12.0), + child: Assets.icon.outline.search.svg( + color: Theme.of(context).colorScheme.onSurface, + width: 16, + height: 16), + ), + enabledBorder: defaultBorder, + border: defaultBorder), + ), + )), + ], + ), + ); + } + + Column titleDivider(BuildContext context, + {required final String title, + final double top = 32, + final double bottom = 16}) { + return Column( + children: [ + top.h, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + SelectableText( + title, + style: Theme.of(context).textTheme.titleMedium, + ), + 12.w, + Expanded( + child: Divider( + color: Theme.of(context).colorScheme.onSurface, + )), + ], + ), + ), + bottom.h, + ], + ); } } diff --git a/lib/presentation/ui/screens/product/product_page.dart b/lib/presentation/ui/screens/product/product_page.dart new file mode 100644 index 0000000..89d846d --- /dev/null +++ b/lib/presentation/ui/screens/product/product_page.dart @@ -0,0 +1,707 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:proxibuy/core/utils/empty_space.dart'; +import 'package:proxibuy/presentation/ui/theme/colors.dart'; +import 'package:proxibuy/presentation/ui/theme/responsive.dart'; + +class ProductPage extends StatelessWidget { + const ProductPage({super.key}); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Responsive(context).builder( + mobile: Scaffold( + body: SingleChildScrollView( + child: Column( + children: [ + Stack( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 46), + child: AspectRatio( + aspectRatio: 0.95, + child: Image.network( + 'https://s3-alpha-sig.figma.com/img/4361/9bde/26f7810ea7f22d8aa59a907d378c16ff?Expires=1740960000&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=DIm2QGXae9cxWDNV2UoJd4JWpvvmL~qKmEefvrtVw9XwKTVHwcfgqR3-s-5s7jqsTiT0iWDsYY10MeuSf2d4xXx9uTra~QEj3LbO1x4cRv4DBDJ-wkLGxliV07HVWl~CMl1MhzXyfUvWkrR30QQ5x3IslvBpfulMj88AYU5l97XPaNMOcMT8YqErdCdpiqdXBM9L2vUpCUbZGH~SfKCQyl1QcNhuCBTPODPWcK6kGU1ell3qwXC0-4JcLiiR-Kdo9asKy495iVtQ584fyZAdeN1R4oJnVGnAlUyN2HRQh6j518FCrJIzr7O0JajvrmwZ7j48nXjWPtG0SGp8Lq4l6A__', + width: double.infinity, + fit: BoxFit.cover, + )), + ), + Positioned( + left: 16, + right: 16, + top: 32, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + context.pop(); + }, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .surface + .withAlpha(180), + borderRadius: BorderRadius.circular(8)), + padding: EdgeInsets.all(8), + child: Icon(Icons.arrow_back_ios_new_rounded), + ), + ), + InkWell( + onTap: () { + context.pop(); + }, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .surface + .withAlpha(180), + borderRadius: BorderRadius.circular(8)), + padding: EdgeInsets.all(8), + child: Icon(Icons.bookmark_add_rounded), + ), + ), + ], + )), + Positioned( + right: 0, + left: 0, + bottom: 0, + child: SizedBox( + width: double.infinity, + height: 90, + child: ListView.builder( + itemCount: 20, + padding: EdgeInsets.symmetric(horizontal: 8), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 8), + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .surface + .withAlpha(200), + borderRadius: BorderRadius.circular(8)), + child: Image.network( + 'https://static.vecteezy.com/system/resources/previews/021/275/832/non_2x/running-shoes-illustration-with-fire-shape-yellow-and-red-isolated-on-transparan-background-free-png.png'), + ); + }, + ), + )) + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TabBar( + tabs: [ + Tab(text: 'Item'), + Tab(text: 'Shop'), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: SizedBox( + height: 1500, + child: TabBarView( + children: [itemTab(context), shopTab(context)], + ), + ), + ), + ], + ), + ), + ), + desktop: Scaffold(), + ), + ); + } + + Widget itemTab(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + 'Philadelphia Honey Pecan Cream Cheese Spread, 7.5 oz Tub', + style: Theme.of(context).textTheme.headlineSmall, + ), + 4.h, + SelectableText( + 'Brand: Philadelphia', + style: Theme.of(context).textTheme.titleSmall, + ), + 8.h, + Row( + children: [ + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_half_rounded), + 8.w, + Text( + '4.8', + style: Theme.of(context).textTheme.bodyMedium, + ) + ], + ), + 8.h, + SelectableText( + 'Currently available. 23 remain', + style: Theme.of(context).textTheme.titleSmall, + ), + 12.h, + Row( + children: [ + Icon(Icons.warning_amber_rounded), + 8.w, + Text( + 'Expire: 5 days', + style: Theme.of(context).textTheme.bodyMedium, + ) + ], + ), + 8.h, + Divider( + color: Theme.of(context).colorScheme.onSurface, + ), + 8.h, + SelectableText( + 'Nutrition summary', + style: Theme.of(context).textTheme.titleLarge, + ), + 4.h, + SelectableText( + '7 servings per container | 2 Tbsp (33g)', + style: Theme.of(context).textTheme.bodyLarge, + ), + 16.h, + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(16)), + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Flex( + direction: Axis.horizontal, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 1, + child: Column( + children: [ + SelectableText( + '80', + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith(color: Theme.of(context).primaryColor), + ), + SelectableText('Calories', + style: Theme.of(context).textTheme.labelLarge), + ], + ), + ), + Flexible( + flex: 1, + child: Column( + children: [ + SelectableText( + '100mg', + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith(color: Theme.of(context).primaryColor), + ), + SelectableText('Sodium', + style: Theme.of(context).textTheme.labelLarge), + ], + ), + ), + Flexible( + flex: 1, + child: Column( + children: [ + SelectableText( + '0g', + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith(color: Theme.of(context).primaryColor), + ), + SelectableText('Dietary Fiber', + style: Theme.of(context).textTheme.labelLarge), + ], + ), + ), + Flexible( + flex: 1, + child: Column( + children: [ + SelectableText( + '5g', + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith(color: Theme.of(context).primaryColor), + ), + SelectableText('Sugars', + style: Theme.of(context).textTheme.labelLarge), + ], + ), + ), + ], + ), + ), + 16.h, + Divider( + color: Theme.of(context).colorScheme.onSurface, + ), + 16.h, + Row( + children: [ + Container( + decoration: BoxDecoration( + color: semanticRed, borderRadius: BorderRadius.circular(8)), + padding: EdgeInsets.all(8), + child: Text( + 'HOT', + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(color: Colors.white), + ), + ), + 8.w, + SelectableText( + '(50%) 32.18 - 16.9 \$', + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(color: semanticRed), + ) + ], + ), + 16.h, + Center( + child: Text( + 'Top reviews from the United States', + style: Theme.of(context).textTheme.titleMedium, + )), + 8.h, + ListView.builder( + shrinkWrap: true, + itemCount: 3, + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return Column( + children: [ + ListTile( + contentPadding: EdgeInsets.zero, + title: SelectableText( + 'Kristin Watson', + style: Theme.of(context).textTheme.labelLarge, + ), + subtitle: SelectableText( + 'Verified Buyer', + style: Theme.of(context).textTheme.bodySmall, + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + ], + ), + ), + 16.h, + SelectableText( + 'This is πŸ’― one hundred percent the best !!! "Philadelphia cream cheese is absolutely amazingβ€”so creamy and versatile, it elevates every recipe, from cheesecakes to simple bagels. A must-have in my kitchen!"πŸ˜‹πŸ˜‹πŸ˜‹', + style: Theme.of(context).textTheme.bodyLarge, + ), + 16.h, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon(Icons.thumb_up_alt_outlined), + 8.w, + Text('Yes (2)'), + 12.w, + Icon(Icons.thumb_down_alt_outlined), + 8.w, + Text('No (0)'), + ], + ), + Text( + 'Nov 09, 2024', + style: Theme.of(context).textTheme.bodySmall, + ) + ], + ), + if (index != 3 - 1) + Divider( + color: Theme.of(context).colorScheme.onSurface, + ) + ], + ); + }, + ), + 12.h, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'See all reviws', + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(color: semanticRed), + ), + 4.w, + Icon( + Icons.arrow_forward, + color: semanticRed, + ) + ], + ) + ], + ), + ); + } + + Widget shopTab(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + 'Heinen\'s Grocery', + style: Theme.of(context).textTheme.headlineSmall, + ), + 8.h, + Row( + children: [ + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_rate_rounded), + Icon(Icons.star_half_rounded), + 8.w, + Text( + '4.8', + style: Theme.of(context).textTheme.bodyMedium, + ) + ], + ), + 8.h, + Row( + children: [ + Icon(Icons.location_on_outlined), + 8.w, + Text( + 'Shop 1, Cleveland, Ohio, United States', + style: Theme.of(context).textTheme.bodyMedium, + ) + ], + ), + 4.h, + Row( + children: [ + Icon(Icons.access_time_rounded), + 8.w, + Text( + 'Open now | 10:00 AM - 12:00 PM', + style: Theme.of(context).textTheme.bodyMedium, + ) + ], + ), + 16.h, + Row( + children: [ + SelectableText( + 'Facilities', + style: Theme.of(context).textTheme.titleMedium, + ), + 8.w, + Expanded( + child: Divider( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + ], + ), + 8.h, + Row( + children: [ + Icon(Icons.check_box_outlined), + 8.w, + Text( + 'Home Delivery', + style: Theme.of(context).textTheme.bodyMedium, + ) + ], + ), + 16.h, + SizedBox( + height: 46, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.surface), + onPressed: () {}, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.navigation_rounded), + 4.w, + Text('Direction') + ], + )), + ), + 16.h, + Container( + width: double.infinity, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(16)), + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '23 min (8.7 km)', + style: Theme.of(context).textTheme.titleLarge, + ), + 12.h, + SizedBox( + height: 46, + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: semanticGreen), + onPressed: () {}, + child: Text('Reservation')), + ), + ], + ), + ), + ], + ), + ), + 16.h, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + SelectableText( + 'List of offers', + style: Theme.of(context).textTheme.titleLarge, + ), + ], + ), + ), + 16.h, + SizedBox( + width: double.infinity, + height: 150, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + padding: EdgeInsets.symmetric(horizontal: 8), + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Container( + width: 300, + padding: EdgeInsets.all(12), + margin: EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(16)), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + 'https://s3-alpha-sig.figma.com/img/f773/0650/56608740ed0260647aa12c36f8b46534?Expires=1740960000&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=UxdqWfGI5Ix~S2728Qsiw0MHGST~we6M25cWRZ8YetaIGlC-ITXjDaX8LDssimYJt5XWmfyWqE0D4vRq1lP9Nmy3CfI~bLXaaBBSmQqAwdXDz1aVXFh7Q8ri5klxYoCjIF0HTp3nr4Scpf5d9PHU7L32s8JF0pz4dt8tyaCo-goeEOsjn8Q-LOBKNHVE6B8uRnW74GH12V7GNygxv1EV59dDD1vcXNcD7kS~2Ox7RejK159Ys7La1F-Evbt5sU7XFOMJuFbPVUgWA05wgrF1U1zdaz5b10Mu9~4PnErR~FjJTZPYcznatVYwuxWRWRAtpwjhjew2TL0DoOvlCKHbYw__', + width: 74, + height: 74, + fit: BoxFit.cover, + ), + ), + 12.w, + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SelectableText( + 'Kellogg\'s Corn Flakes', + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(overflow: TextOverflow.ellipsis), + maxLines: 1, + ), + 8.h, + SelectableText( + 'Classic cereal with a crispy texture an a mildly sweet flavor', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(overflow: TextOverflow.ellipsis), + maxLines: 2, + ), + ], + ), + ) + ], + ), + 12.h, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Container( + decoration: BoxDecoration( + color: semanticRed, + borderRadius: BorderRadius.circular(8)), + padding: EdgeInsets.all(8), + child: Text( + 'HOT', + style: Theme.of(context) + .textTheme + .titleSmall + ?.copyWith(color: Colors.white), + ), + ), + 8.w, + Text( + '(50%) / 16 - 8\$', + style: Theme.of(context).textTheme.titleSmall, + ) + ], + ), + Container( + decoration: BoxDecoration( + color: semanticGreen, + borderRadius: BorderRadius.circular(8)), + padding: EdgeInsets.all(8), + child: Text( + 'Reservation', + style: Theme.of(context) + .textTheme + .titleSmall + ?.copyWith(color: Colors.white), + ), + ), + ], + ) + ], + ), + ); + }, + ), + ), + 16.h, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + SelectableText( + 'Similar Business', + style: Theme.of(context).textTheme.titleLarge, + ), + ], + ), + ), + 16.h, + SizedBox( + width: double.infinity, + height: 270, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + padding: EdgeInsets.symmetric(horizontal: 8), + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return Container( + width: 240, + padding: EdgeInsets.all(12), + margin: EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(16)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: AspectRatio( + aspectRatio: 16 / 9, + child: Image.network( + 'https://s3-alpha-sig.figma.com/img/c720/df1c/d8288c0392372fb3dd15824b84b9d563?Expires=1740960000&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=CMct6yvsv~g0YEUDRp-D3prnQve4nZc5mB~oJ4jbRsH63ltvM4yoCKbTYJLCm~ONwb9e7TNoFO1Q1pO8sPz3TBB-gAFIX9j53fz40ypp0VsRXSOK91G7LBj82V974E1Yqxol2fhAZ8icTAaOZVJgJH-47EG3wQqujGieHbcOYCCBZoCPP0a~jKG~LsE-EtLmP0RdXOuqE9-o2gMzEBH2TMXLtWJXYtA6dS~XHPBIeUXn4Sa7Hy4ca3pGb6wXN4owNt4SeanQuxeR-CEgDYJTI~tU6LkW1N2TSPOt6iGn5Jbb4XdkFjKA7dkwijG9mEU9F3wy16aMj7a1Z1yEwAvlwg__', + height: 100, + fit: BoxFit.cover, + ), + ), + ), + 8.h, + SelectableText( + 'Milam\'s Markets', + style: Theme.of(context) + .textTheme + .titleMedium + ?.copyWith(overflow: TextOverflow.ellipsis), + maxLines: 1, + ), + 8.h, + Row( + children: [ + Icon(Icons.location_on_outlined), + 8.w, + SelectableText( + 'Miami Springs, Florida', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(overflow: TextOverflow.ellipsis), + maxLines: 1, + ) + ], + ), + 8.h, + SizedBox( + child: ElevatedButton( + onPressed: () {}, child: Text('See more about')), + ), + ], + ), + ); + }, + ), + ) + ], + ); + } +} diff --git a/lib/presentation/ui/theme/theme.dart b/lib/presentation/ui/theme/theme.dart index 0834cbb..b1a7292 100644 --- a/lib/presentation/ui/theme/theme.dart +++ b/lib/presentation/ui/theme/theme.dart @@ -90,7 +90,7 @@ final ThemeData darkTheme = ThemeData( CustomColors( primarySwatch: darkPrimarySwatch, secondrySwatch: darkSecondarySwatch, - primaryLightSurface: darkPrimarySwatch[900]!, + primaryLightSurface: darkPrimarySwatch[600]!, ), ], diff --git a/lib/presentation/ui/widgets/carousel/carousel_slider_widget.dart b/lib/presentation/ui/widgets/carousel/carousel_slider_widget.dart index fcca669..02fa72d 100644 --- a/lib/presentation/ui/widgets/carousel/carousel_slider_widget.dart +++ b/lib/presentation/ui/widgets/carousel/carousel_slider_widget.dart @@ -10,6 +10,7 @@ class CarouselSliderWidget extends StatefulWidget { ) onPageBuilder; final bool withNavs; final double height; + final double viewportFraction; final bool autoPlay; final bool enableInfiniteScroll; final Function()? onLastClick; @@ -23,6 +24,7 @@ class CarouselSliderWidget extends StatefulWidget { this.autoPlay = true, this.enableInfiniteScroll = true, this.height = 200, + this.viewportFraction = 0.9, }); @override @@ -46,11 +48,11 @@ class _CarouselSliderWidgetState extends State> { return widget.onPageBuilder(context, widget.items[index]); }, options: CarouselOptions( - height: widget.height * 0.75, + height: widget.height, autoPlay: widget.autoPlay, enableInfiniteScroll: widget.enableInfiniteScroll, enlargeCenterPage: true, - viewportFraction: 0.9, + viewportFraction: widget.viewportFraction, onPageChanged: (index, reason) => setState(() => activeIndex = index), ),