create product page for mobile.
This commit is contained in:
parent
a8c8fa88b9
commit
09d4553e73
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<String> home = [initial, explore, setting];
|
||||
|
||||
static final GlobalKey<NavigatorState> navigatorKey =
|
||||
GlobalKey<NavigatorState>();
|
||||
|
||||
GoRouter createRouter = GoRouter(
|
||||
static GoRouter createRouter = GoRouter(
|
||||
navigatorKey: navigatorKey,
|
||||
initialLocation: home,
|
||||
initialLocation: initial,
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: home,
|
||||
builder: (BuildContext context, GoRouterState state) {
|
||||
return BlocConsumer<UserInfoCubit, UserInfoState>(
|
||||
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: <RouteBase>[],
|
||||
),
|
||||
// StatefulShellRoute.indexedStack(
|
||||
// builder: (context, state, navigationShell) =>
|
||||
// BlocBuilder<UserInfoCubit, UserInfoState>(
|
||||
// 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<UserInfoCubit, UserInfoState>(
|
||||
// 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: <RouteBase>[
|
||||
// GoRoute(
|
||||
// path: product,
|
||||
// builder: (BuildContext context, GoRouterState state) {
|
||||
// return ProductPage();
|
||||
// },
|
||||
// routes: <RouteBase>[],
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
|
||||
StatefulShellRoute.indexedStack(
|
||||
builder: (context, state, navigationShell) =>
|
||||
BlocBuilder<UserInfoCubit, UserInfoState>(
|
||||
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: <RouteBase>[],
|
||||
),
|
||||
]),
|
||||
]),
|
||||
StatefulShellBranch(routes: [
|
||||
GoRoute(
|
||||
path: explore,
|
||||
builder: (context, state) => ExploreScreen(),
|
||||
),
|
||||
]),
|
||||
StatefulShellBranch(routes: [
|
||||
GoRoute(
|
||||
path: setting,
|
||||
builder: (context, state) => SettingScreen(),
|
||||
),
|
||||
]),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PointerDeviceKind> get dragDevices => {
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.mouse,
|
||||
};
|
||||
}
|
||||
|
|
@ -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<MyApp> {
|
|||
return BlocBuilder<ThemModeCubit, ThemeMode>(
|
||||
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,
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ class _AuthPageState extends State<AuthPage> {
|
|||
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<AuthPage> {
|
|||
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<AuthPage> {
|
|||
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<AuthPage> {
|
|||
);
|
||||
}
|
||||
|
||||
CarouselSliderWidget<OnboardingBannerModel> carousle(
|
||||
{required final bool withNavs,
|
||||
required final bool autoPlay,
|
||||
required final bool enableInfiniteScroll,
|
||||
double? height}) {
|
||||
CarouselSliderWidget<OnboardingBannerModel> carousle({
|
||||
required final bool withNavs,
|
||||
required final bool autoPlay,
|
||||
required final bool enableInfiniteScroll,
|
||||
}) {
|
||||
return CarouselSliderWidget<OnboardingBannerModel>(
|
||||
height: height ?? MediaQuery.sizeOf(context).height,
|
||||
height: MediaQuery.sizeOf(context).height * 0.8,
|
||||
items: [
|
||||
OnboardingBannerModel(
|
||||
image: Assets.image.onboarding.banner1,
|
||||
|
|
|
|||
|
|
@ -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<HomePage> createState() => _HomePageState();
|
||||
|
|
@ -25,6 +29,7 @@ class _HomePageState extends State<HomePage> {
|
|||
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<HomePage> {
|
|||
),
|
||||
),
|
||||
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<ThemModeCubit>().changeTheme();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: body(),
|
||||
bottomNavigationBar: bottomNavigationBar(context),
|
||||
),
|
||||
|
|
@ -207,17 +192,24 @@ class _HomePageState extends State<HomePage> {
|
|||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<HomeScreen> {
|
|||
|
||||
@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: <Widget>[
|
||||
// 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<String>(
|
||||
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<String>(
|
||||
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<String>(
|
||||
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<ThemModeCubit>().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<String>(
|
||||
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<String>(
|
||||
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<String>(
|
||||
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,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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')),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ final ThemeData darkTheme = ThemeData(
|
|||
CustomColors(
|
||||
primarySwatch: darkPrimarySwatch,
|
||||
secondrySwatch: darkSecondarySwatch,
|
||||
primaryLightSurface: darkPrimarySwatch[900]!,
|
||||
primaryLightSurface: darkPrimarySwatch[600]!,
|
||||
),
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class CarouselSliderWidget<T> 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<T> extends StatefulWidget {
|
|||
this.autoPlay = true,
|
||||
this.enableInfiniteScroll = true,
|
||||
this.height = 200,
|
||||
this.viewportFraction = 0.9,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -46,11 +48,11 @@ class _CarouselSliderWidgetState<T> extends State<CarouselSliderWidget<T>> {
|
|||
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),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue