0% found this document useful (0 votes)
7 views27 pages

Main

The document is a Flutter application for a restaurant called Grilli, featuring a user interface with a carousel slider, themed colors, and various sections such as services, menu, and testimonials. It includes a preloader animation and a responsive design that adapts to scrolling behavior. The app also provides contact options and a drawer for navigation.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views27 pages

Main

The document is a Flutter application for a restaurant called Grilli, featuring a user interface with a carousel slider, themed colors, and various sections such as services, menu, and testimonials. It includes a preloader animation and a responsive design that adapts to scrolling behavior. The app also provides contact options and a drawer for navigation.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 27

import 'package:flutter/material.

dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
runApp(const GrilliApp());
}

class GrilliApp extends StatelessWidget {


const GrilliApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Grilli - Amazing & Delicious Food',
theme: ThemeData(
primaryColor: const Color(0xFFDBA159), // gold-crayola
scaffoldBackgroundColor: const Color(0xFF1A2526), // eerie-black-1
textTheme: TextTheme(
displayLarge: GoogleFonts.forum(
fontSize: 48,
fontWeight: FontWeight.w400,
color: Colors.white,
),
headlineLarge: GoogleFonts.forum(
fontSize: 36,
fontWeight: FontWeight.w400,
color: Colors.white,
),
headlineMedium: GoogleFonts.forum(
fontSize: 28,
fontWeight: FontWeight.w400,
color: Colors.white,
),
titleLarge: GoogleFonts.dmSans(
fontSize: 22,
fontWeight: FontWeight.w700,
color: Colors.white,
),
titleMedium: GoogleFonts.dmSans(
fontSize: 21,
fontWeight: FontWeight.w400,
color: Colors.white,
),
bodyLarge: GoogleFonts.dmSans(
fontSize: 24,
color: Colors.white,
height: 1.85,
),
bodyMedium: GoogleFonts.dmSans(
fontSize: 16,
color: const Color(0xFFA6A6A6), // quick-silver
height: 1.6,
),
bodySmall: GoogleFonts.dmSans(
fontSize: 14,
color: const Color(0xFFA6A6A6),
height: 1.4,
),
labelLarge: GoogleFonts.dmSans(
fontSize: 14,
fontWeight: FontWeight.w700,
color: const Color(0xFFDBA159),
letterSpacing: 0.4,
),
labelMedium: GoogleFonts.dmSans(
fontSize: 12,
fontWeight: FontWeight.w700,
color: const Color(0xFFDBA159),
letterSpacing: 0.4,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFDBA159),
foregroundColor: Colors.black,
padding: const EdgeInsets.symmetric(horizontal: 45, vertical: 12),
textStyle: GoogleFonts.dmSans(
fontSize: 12,
fontWeight: FontWeight.w700,
letterSpacing: 3,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
side: const BorderSide(color: Color(0xFFDBA159), width: 2),
),
),
),
inputDecorationTheme: const InputDecorationTheme(
filled: true,
fillColor: Color(0xFF1D2728), // eerie-black-2
contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white10),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xFFDBA159)),
),
),
),
home: const HomeScreen(),
);
}
}

class HomeScreen extends StatefulWidget {


const HomeScreen({super.key});

@override
State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> with


SingleTickerProviderStateMixin {
bool _isLoaded = false;
int _currentSlide = 0;
final CarouselController _carouselController = CarouselController();
late AnimationController _preloaderController;
late Animation<double> _preloaderAnimation;
bool _isHeaderActive = false;
double _lastScrollPos = 0;

@override
void initState() {
super.initState();
_preloaderController = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
)..repeat();
_preloaderAnimation = Tween<double>(begin: 0, end:
360).animate(_preloaderController);

// Simulate preloader
Future.delayed(const Duration(seconds: 2), () {
setState(() {
_isLoaded = true;
});
});
}

@override
void dispose() {
_preloaderController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Stack(
children: [
if (!_isLoaded)
_buildPreloader()
else
Scaffold(
appBar: _buildTopBar(context),
drawer: _buildDrawer(context),
body: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollUpdateNotification) {
setState(() {
if (scrollNotification.metrics.pixels >= 50) {
_isHeaderActive = true;
if (_lastScrollPos < scrollNotification.metrics.pixels) {
_isHeaderActive = false; // Hide header when scrolling down
}
} else {
_isHeaderActive = false;
}
_lastScrollPos = scrollNotification.metrics.pixels;
});
}
return true;
},
child: SingleChildScrollView(
child: Column(
children: [
_buildHeroSlider(context),
_buildServiceSection(context),
_buildAboutSection(context),
_buildSpecialDishSection(context),
_buildMenuSection(context),
_buildTestimonialsSection(context),
_buildReservationSection(context),
_buildFeaturesSection(context),
_buildEventSection(context),
_buildFooterSection(context),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Scrollable.ensureVisible(context, duration: const
Duration(milliseconds: 500));
},
backgroundColor: const Color(0xFFDBA159),
child: const Icon(Icons.arrow_upward, color: Colors.black),
),
),
],
);
}

Widget _buildPreloader() {
return Container(
color: const Color(0xFFDBA159),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedBuilder(
animation: _preloaderAnimation,
builder: (context, child) {
return Transform.rotate(
angle: _preloaderAnimation.value * 3.14159 / 180,
child: Container(
width: 112,
height: 112,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 3,
),
),
child: Container(
margin: const EdgeInsets.all(3),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFF1C1810),
),
),
),
);
},
),
const SizedBox(height: 45),
Text(
'Grilli',
style: GoogleFonts.dmSans(
fontSize: 40,
fontWeight: FontWeight.w700,
letterSpacing: 16,
foreground: Paint()
..shader = const LinearGradient(
colors: [Colors.transparent, Color(0xFF1C1810),
Colors.transparent],
).createShader(const Rect.fromLTWH(0, 0, 500, 40)),
),
),
],
),
),
);
}

PreferredSizeWidget _buildTopBar(BuildContext context) {


return PreferredSize(
preferredSize: const Size.fromHeight(60),
child: AnimatedOpacity(
opacity: _isHeaderActive && !_isHeaderActive ? 0 : 1,
duration: const Duration(milliseconds: 250),
child: AppBar(
backgroundColor: _isHeaderActive ? const Color(0xFF212B2C) :
Colors.transparent,
elevation: 0,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.location_on, color: Color(0xFFDBA159)),
const SizedBox(width: 6),
Text(
'Restaurant St, Delicious City, London 9578, UK',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(width: 30),
const Icon(Icons.access_time, color: Color(0xFFDBA159)),
const SizedBox(width: 6),
Text(
'Daily : 8.00 am to 10.00 pm',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(width: 30),
GestureDetector(
onTap: () => _launchUrl('tel:+11234567890'),
child: Row(
children: [
const Icon(Icons.call, color: Color(0xFFDBA159)),
const SizedBox(width: 6),
Text(
'+1 123 456 7890',
style: Theme.of(context).textTheme.bodySmall?.copyWith(color:
const Color(0xFFDBA159)),
),
],
),
),
const SizedBox(width: 30),
GestureDetector(
onTap: () => _launchUrl('mailto:booking@restaurant.com'),
child: Row(
children: [
const Icon(Icons.mail, color: Color(0xFFDBA159)),
const SizedBox(width: 6),
Text(
'booking@restaurant.com',
style: Theme.of(context).textTheme.bodySmall?.copyWith(color:
const Color(0xFFDBA159)),
),
],
),
),
],
),
actions: [
Builder(
builder: (context) => IconButton(
icon: const Icon(Icons.menu, color: Colors.white),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
],
),
),
);
}

Widget _buildDrawer(BuildContext context) {


return Drawer(
backgroundColor: const Color(0xFF1C1810),
child: ListView(
padding: const EdgeInsets.all(30),
children: [
Image.asset('assets/images/logo.svg', height: 50, width: 160),
const SizedBox(height: 60),
_buildDrawerItem(context, 'Home', () => Navigator.pop(context)),
_buildDrawerItem(context, 'Menus', () => Navigator.pop(context)),
_buildDrawerItem(context, 'About Us', () => Navigator.pop(context)),
_buildDrawerItem(context, 'Our Chefs', () => Navigator.pop(context)),
_buildDrawerItem(context, 'Contact', () => Navigator.pop(context)),
const Divider(color: Colors.white24),
const SizedBox(height: 20),
Text(
'Visit Us',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 10),
Text(
'Restaurant St, Delicious City,\nLondon 9578, UK',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 10),
Text(
'Open: 9.30 am - 2.30pm',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 10),
GestureDetector(
onTap: () => _launchUrl('mailto:booking@grilli.com'),
child: Text(
'booking@grilli.com',
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: const
Color(0xFFDBA159)),
),
),
const SizedBox(height: 30),
Text(
'Booking Request',
style: Theme.of(context).textTheme.labelLarge,
),
GestureDetector(
onTap: () => _launchUrl('tel:+88123123456'),
child: Text(
'+88-123-123456',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: const Color(0xFFDBA159),
decoration: TextDecoration.underline,
),
),
),
],
),
);
}

Widget _buildDrawerItem(BuildContext context, String title, VoidCallback onTap) {


return ListTile(
title: Text(
title,
style: Theme.of(context).textTheme.labelMedium,
),
onTap: onTap,
trailing: const Icon(Icons.arrow_forward, color: Color(0xFFDBA159)),
);
}

Widget _buildHeroSlider(BuildContext context) {


final List<Map<String, String>> slides = [
{
'image': 'assets/images/hero-slider-1.jpg',
'subtitle': 'Traditional & Hygienic',
'title': 'For the love of\ndelicious food',
'text': 'Come with family & feel the joy of mouthwatering food',
},
{
'image': 'assets/images/hero-slider-2.jpg',
'subtitle': 'Delightful Experience',
'title': 'Flavors Inspired by\nthe Seasons',
'text': 'Come with family & feel the joy of mouthwatering food',
},
{
'image': 'assets/images/hero-slider-3.jpg',
'subtitle': 'Amazing & Delicious',
'title': 'Where every flavor\ntells a story',
'text': 'Come with family & feel the joy of mouthwatering food',
},
];

return Stack(
children: [
CarouselSlider(
carouselController: _carouselController,
options: CarouselOptions(
height: MediaQuery.of(context).size.height * 0.7,
autoPlay: true,
autoPlayInterval: const Duration(seconds: 7),
viewportFraction: 1.0,
onPageChanged: (index, reason) {
setState(() {
_currentSlide = index;
});
},
),
items: slides.map((slide) {
return Stack(
fit: StackFit.expand,
children: [
Image.asset(
slide['image']!,
fit: BoxFit.cover,
),
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromRGBO(0, 0, 0, 0.9),
Color.fromRGBO(0, 0, 0, 0.7),
Colors.transparent,
],
),
),
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
slide['subtitle']!.toUpperCase(),
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 20),
Text(
slide['title']!,
style: Theme.of(context).textTheme.displayLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
slide['text']!,
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {},
child: const Text('VIEW OUR MENU'),
),
],
),
),
],
);
}).toList(),
),
Positioned(
left: 30,
top: MediaQuery.of(context).size.height * 0.35,
child: IconButton(
icon: const Icon(Icons.chevron_left, color: Color(0xFFDBA159)),
onPressed: () => _carouselController.previousPage(),
),
),
Positioned(
right: 30,
top: MediaQuery.of(context).size.height * 0.35,
child: IconButton(
icon: const Icon(Icons.chevron_right, color: Color(0xFFDBA159)),
onPressed: () => _carouselController.nextPage(),
),
),
Positioned(
bottom: 15,
right: 15,
child: FloatingActionButton(
onPressed: () {},
backgroundColor: const Color(0xFFDBA159),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/images/hero-icon.png', height: 48, width: 48),
const Text(
'Book A Table',
style: TextStyle(fontSize: 10, color: Colors.black, fontWeight:
FontWeight.w700),
textAlign: TextAlign.center,
),
],
),
),
),
],
);
}

Widget _buildServiceSection(BuildContext context) {


final List<Map<String, String>> services = [
{
'image': 'assets/images/service-1.jpg',
'title': 'Breakfast',
},
{
'image': 'assets/images/service-2.jpg',
'title': 'Appetizers',
},
{
'image': 'assets/images/service-3.jpg',
'title': 'Drinks',
},
];

return Container(
color: const Color(0xFF1C1810),
padding: const EdgeInsets.symmetric(vertical: 70),
child: Column(
children: [
Text(
'Flavors For Royalty',
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 12),
Text(
'We Offer Top Notch',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 16),
Text(
'Lorem Ipsum is simply dummy text of the printing and typesetting
industry lorem Ipsum has been the industrys standard dummy text ever.',
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: MediaQuery.of(context).size.width > 992 ? 3 : 2,
crossAxisSpacing: 40,
mainAxisSpacing: 40,
childAspectRatio: 0.85,
children: services.map((service) {
return Card(
color: const Color(0xFF1C1810),
child: Column(
children: [
GestureDetector(
onTap: () {},
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Image.asset(
service['image']!,
width: 285,
height: 336,
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 12),
Text(
service['title']!,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 12),
TextButton(
onPressed: () {},
child: Text(
'View Menu',
style: Theme.of(context).textTheme.labelMedium,
),
),
],
),
);
}).toList(),
),
Positioned(
bottom: 0,
left: 0,
child: Image.asset('assets/images/shape-1.png', width: 246, height:
412),
),
Positioned(
top: 0,
right: 0,
child: Image.asset('assets/images/shape-2.png', width: 343, height:
345),
),
],
),
);
}

Widget _buildAboutSection(BuildContext context) {


return Container(
padding: const EdgeInsets.symmetric(vertical: 100),
child: Column(
children: [
Text(
'Our Story',
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 12),
Text(
'Every Flavor Tells a Story',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 15),
Text(
'Lorem Ipsum is simply dummy text of the printingand typesetting
industry lorem Ipsum has been the industrys standard dummy text ever since the when
an unknown printer took a galley of type and scrambled it to make a type specimen
book It has survived not only five centuries, but also the leap into.',
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 30),
Text(
'Book Through Call',
style: Theme.of(context).textTheme.labelLarge,
),
GestureDetector(
onTap: () => _launchUrl('tel:+804001234567'),
child: Text(
'+80 (400) 123 4567',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: const Color(0xFFDBA159),
decoration: TextDecoration.underline,
),
),
),
const SizedBox(height: 26),
ElevatedButton(
onPressed: () {},
child: const Text('READ MORE'),
),
const SizedBox(height: 120),
Stack(
children: [
Image.asset('assets/images/about-banner.jpg', width: 570, height:
570),
Positioned(
bottom: -120,
left: 0,
child: Image.asset('assets/images/about-abs-image.jpg', width: 285,
height: 285),
),
Positioned(
top: -65,
right: 0,
child: Image.asset('assets/images/badge-2.png', width: 133, height:
134),
),
],
),
Positioned(
left: 0,
child: Image.asset('assets/images/shape-3.png', width: 197, height:
194),
),
],
),
);
}

Widget _buildSpecialDishSection(BuildContext context) {


return Container(
color: const Color(0xFF1C1810),
child: Row(
children: [
Expanded(
child: Image.asset('assets/images/special-dish-banner.jpg', fit:
BoxFit.cover),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 70, horizontal: 25),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset('assets/images/badge-1.png', width: 28, height: 41),
const SizedBox(height: 12),
Text(
'Special Dish',
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 12),
Text(
'Lobster Tortellini',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 16),
Text(
'Lorem Ipsum is simply dummy text of the printingand
typesetting industry lorem Ipsum has been the industrys standard dummy text ever
since the when an unknown printer took a galley of type.',
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 40),
Row(
children: [
Text(
'\$40.00',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: const Color(0xFF575351),
decoration: TextDecoration.lineThrough,
),
),
const SizedBox(width: 20),
Text(
'\$20.00',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: const Color(0xFFDBA159),
),
),
],
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {},
child: const Text('VIEW ALL MENU'),
),
],
),
),
),
Positioned(
top: 45,
right: 0,
child: Image.asset('assets/images/shape-4.png', width: 179, height:
359),
),
Positioned(
bottom: 0,
right: 0,
child: Image.asset('assets/images/shape-9.png', width: 351, height:
462),
),
],
),
);
}

Widget _buildMenuSection(BuildContext context) {


final List<Map<String, dynamic>> menuItems = [
{
'image': 'assets/images/menu-1.png',
'title': 'Greek Salad',
'price': '\$25.50',
'description': 'Tomatoes, green bell pepper, sliced cucumber onion, olives,
and feta cheese.',
'badge': 'Seasonal',
},
{
'image': 'assets/images/menu-2.png',
'title': 'Lasagne',
'price': '\$40.00',
'description': 'Vegetables, cheeses, ground meats, tomato sauce, seasonings
and spices.',
},
{
'image': 'assets/images/menu-3.png',
'title': 'Butternut Pumpkin',
'price': '\$10.00',
'description': 'Typesetting industry lorem Lorem Ipsum is simply dummy text
of the priand.',
},
{
'image': 'assets/images/menu-4.png',
'title': 'Tokusen Wagyu',
'price': '\$39.00',
'description': 'Vegetables, cheeses, ground meats, tomato sauce, seasonings
and spices.',
'badge': 'New',
},
{
'image': 'assets/images/menu-5.png',
'title': 'Olivas Rellenas',
'price': '\$25.00',
'description': 'Avocados with crab meat, red onion, crab salad stuffed red
bell pepper and green bell pepper.',
},
{
'image': 'assets/images/menu-6.png',
'title': 'Opu Fish',
'price': '\$49.00',
'description': 'Vegetables, cheeses, ground meats, tomato sauce, seasonings
and spices.',
},
];

return Container(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const SizedBox(height: 70),
Text(
'Special Selection',
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 12),
Text(
'Delicious Menu',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 40),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: MediaQuery.of(context).size.width > 992 ? 3 : 2,
crossAxisSpacing: 40,
mainAxisSpacing: 40,
childAspectRatio: 0.7,
),
itemCount: menuItems.length,
itemBuilder: (context, index) {
final item = menuItems[index];
return Card(
color: const Color(0xFF1C1810),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Image.asset(
item['image'],
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
item['title'],
style: Theme.of(context).textTheme.titleMedium,
),
if (item['badge'] != null) ...[
const SizedBox(width: 10),
Container(
padding: const EdgeInsets.symmetric(horizontal:
10, vertical: 2),
color: const Color(0xFFDBA159),
child: Text(
item['badge'],
style: const TextStyle(
fontSize: 12,
color: Colors.black,
fontFamily: 'Forum',
),
),
),
],
],
),
const SizedBox(height: 10),
Text(
item['price'],
style: const TextStyle(
fontSize: 16,
color: Color(0xFFDBA159),
),
),
const SizedBox(height: 10),
Text(
item['description'],
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
),
],
),
);
},
),
const SizedBox(height: 50),
Text(
'During winter daily from 7:00 pm to 9:00 pm',
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 26),
ElevatedButton(
onPressed: () {},
child: const Text('VIEW ALL MENU'),
),
Positioned(
top: 0,
left: 0,
child: Image.asset('assets/images/shape-5.png', width: 921, height:
1036),
),
Positioned(
bottom: 0,
right: 0,
child: Image.asset('assets/images/shape-6.png', width: 343, height:
345),
),
],
),
);
}

Widget _buildTestimonialsSection(BuildContext context) {


return Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/testimonial-bg.jpg'),
fit: BoxFit.cover,
),
),
padding: const EdgeInsets.symmetric(vertical: 340),
child: Column(
children: [
Text(
'“',
style: GoogleFonts.forum(
fontSize: 70,
color: Colors.white,
height: 0.7,
),
),
Text(
'I wanted to thank you for inviting me down for that amazing dinner the
other night. The food was extraordinary.',
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (index) => Container(
margin: const EdgeInsets.symmetric(horizontal: 1),
width: 8,
height: 8,
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFFDBA159)),
shape: BoxShape.circle,
),
)),
),
const SizedBox(height: 50),
CircleAvatar(
radius: 50,
backgroundImage: const AssetImage('assets/images/testi-avatar.jpg'),
),
const SizedBox(height: 15),
Text(
'Sam Jhonson',
style: Theme.of(context).textTheme.labelMedium,
),
],
),
);
}

Widget _buildReservationSection(BuildContext context) {


return Container(
padding: const EdgeInsets.symmetric(vertical: 70),
child: Card(
color: const Color(0xFF1C1810),
margin: const EdgeInsets.only(top: 70),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 40),
child: Column(
children: [
Text(
'Online Reservation',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 40),
Text(
'Booking request +88-123-123456 or fill out the order form',
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: TextFormField(
decoration: const InputDecoration(hintText: 'Your
Name'),
),
),
const SizedBox(width: 20),
Expanded(
child: TextFormField(
decoration: const InputDecoration(hintText: 'Phone
Number'),
keyboardType: TextInputType.phone,
),
),
],
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: DropdownButtonFormField<String>(
decoration: const InputDecoration(
prefixIcon: Icon(Icons.person_outline, color:
Colors.white),
hintText: '1 Person',
),
items: const [
DropdownMenuItem(value: '1-person', child: Text('1
Person')),
DropdownMenuItem(value: '2-person', child: Text('2
Person')),
DropdownMenuItem(value: '3-person', child: Text('3
Person')),
DropdownMenuItem(value: '4-person', child: Text('4
Person')),
DropdownMenuItem(value: '5-person', child: Text('5
Person')),
DropdownMenuItem(value: '6-person', child: Text('6
Person')),
DropdownMenuItem(value: '7-person', child: Text('7
Person')),
],
onChanged: (value) {},
),
),
const SizedBox(width: 20),
Expanded(
child: TextFormField(
decoration: const InputDecoration(
prefixIcon: Icon(Icons.calendar_today, color:
Colors.white),
hintText: 'Reservation Date',
),
onTap: () async {
DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2026),
);
if (picked != null) {
// Handle date
}
},
),
),
const SizedBox(width: 20),
Expanded(
child: DropdownButtonFormField<String>(
decoration: const InputDecoration(
prefixIcon: Icon(Icons.access_time, color:
Colors.white),
hintText: '08:00 am',
),
items: const [
DropdownMenuItem(value: '08:00am', child: Text('08:00
am')),
DropdownMenuItem(value: '09:00am', child: Text('09:00
am')),
DropdownMenuItem(value: '10:00am', child: Text('10:00
am')),
DropdownMenuItem(value: '11:00am', child: Text('11:00
am')),
DropdownMenuItem(value: '12:00am', child: Text('12:00
am')),
DropdownMenuItem(value: '01:00pm', child: Text('01:00
pm')),
DropdownMenuItem(value: '02:00pm', child: Text('02:00
pm')),
DropdownMenuItem(value: '03:00pm', child: Text('03:00
pm')),
DropdownMenuItem(value: '04:00pm', child: Text('04:00
pm')),
DropdownMenuItem(value: '05:00pm', child: Text('05:00
pm')),
DropdownMenuItem(value: '06:00pm', child: Text('06:00
pm')),
DropdownMenuItem(value: '07:00pm', child: Text('07:00
pm')),
DropdownMenuItem(value: '08:00pm', child: Text('08:00
pm')),
DropdownMenuItem(value: '09:00pm', child: Text('09:00
pm')),
DropdownMenuItem(value: '10:00pm', child: Text('10:00
pm')),
],
onChanged: (value) {},
),
),
],
),
const SizedBox(height: 20),
TextFormField(
decoration: const InputDecoration(hintText: 'Message'),
maxLines: 5,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
child: const Text('BOOK A TABLE'),
style: ElevatedButton.styleFrom(minimumSize: const
Size(double.infinity, 56)),
),
],
),
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/form-pattern.png'),
fit: BoxFit.cover,
),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 40),
child: Column(
children: [
Text(
'Contact Us',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 40),
Text(
'Booking Request',
style: Theme.of(context).textTheme.labelLarge,
),
GestureDetector(
onTap: () => _launchUrl('tel:+88123123456'),
child: Text(
'+88-123-123456',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: const Color(0xFFDBA159),
decoration: TextDecoration.underline,
),
),
),
const SizedBox(height: 20),
const Divider(color: Colors.white24),
const SizedBox(height: 20),
Text(
'Location',
style: Theme.of(context).textTheme.labelLarge,
),
Text(
'Restaurant St, Delicious City,\nLondon 9578, UK',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 25),
Text(
'Lunch Time',
style: Theme.of(context).textTheme.labelLarge,
),
Text(
'Monday to Sunday\n11.00 am - 2.30pm',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 25),
Text(
'Dinner Time',
style: Theme.of(context).textTheme.labelLarge,
),
Text(
'Monday to Sunday\n05.00 pm - 10.00pm',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
],
),
),
);
}

Widget _buildFeaturesSection(BuildContext context) {


final List<Map<String, String>> features = [
{
'icon': 'assets/images/features-icon-1.png',
'title': 'Hygienic Food',
'text': 'Lorem Ipsum is simply dummy printing and typesetting.',
},
{
'icon': 'assets/images/features-icon-2.png',
'title': 'Fresh Environment',
'text': 'Lorem Ipsum is simply dummy printing and typesetting.',
},
{
'icon': 'assets/images/features-icon-3.png',
'title': 'Skilled Chefs',
'text': 'Lorem Ipsum is simply dummy printing and typesetting.',
},
{
'icon': 'assets/images/features-icon-4.png',
'title': 'Event & Party',
'text': 'Lorem Ipsum is simply dummy printing and typesetting.',
},
];

return Container(
padding: const EdgeInsets.symmetric(vertical: 100),
child: Column(
children: [
Text(
'Why Choose Us',
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 12),
Text(
'Our Strength',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 40),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: MediaQuery.of(context).size.width > 1200 ? 4 : 2,
crossAxisSpacing: 40,
mainAxisSpacing: 40,
childAspectRatio: 0.85,
children: features.asMap().entries.map((entry) {
final index = entry.key;
final feature = entry.value;
return Card(
color: index % 2 == 0 ? const Color(0xFF151D1E) : const
Color(0xFF1C1810),
child: Column(
children: [
Image.asset(feature['icon']!, width: 100, height: 80),
const SizedBox(height: 20),
Text(
feature['title']!,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 10),
Text(
feature['text']!,
style: Theme.of(context).textTheme.bodyMedium,
textAlign: TextAlign.center,
),
],
),
);
}).toList(),
),
Positioned(
top: -100,
right: 0,
child: Image.asset('assets/images/shape-7.png', width: 208, height:
178),
),
Positioned(
bottom: 80,
left: 0,
child: Image.asset('assets/images/shape-8.png', width: 120, height:
115),
),
],
),
);
}

Widget _buildEventSection(BuildContext context) {


final List<Map<String, String>> events = [
{
'image': 'assets/images/event-1.jpg',
'date': '15/09/2022',
'subtitle': 'Food, Flavour',
'title': 'Flavour so good you’ll try to eat with your eyes.',
},
{
'image': 'assets/images/event-2.jpg',
'date': '08/09/2022',
'subtitle': 'Healthy Food',
'title': 'Flavour so good you’ll try to eat with your eyes.',
},
{
'image': 'assets/images/event-3.jpg',
'date': '03/09/2022',
'subtitle': 'Recipe',
'title': 'Flavour so good you’ll try to eat with your eyes.',
},
];

return Container(
color: const Color(0xFF1C1810),
padding: const EdgeInsets.symmetric(vertical: 100),
child: Column(
children: [
Text(
'Recent Updates',
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 12),
Text(
'Upcoming Event',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 40),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: MediaQuery.of(context).size.width > 992 ? 3 : 2,
crossAxisSpacing: 40,
mainAxisSpacing: 40,
childAspectRatio: 0.7,
children: events.map((event) {
return Card(
color: const Color(0xFF1C1810),
child: Stack(
children: [
Image.asset(
event['image']!,
width: 350,
height: 450,
fit: BoxFit.cover,
),
Positioned(
top: 30,
left: 25,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10,
vertical: 5),
color: Colors.black,
child: Text(
event['date']!,
style: Theme.of(context).textTheme.labelMedium,
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.fromLTRB(35, 35, 35, 25),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromRGBO(0, 0, 0, 0.9),
Color.fromRGBO(0, 0, 0, 0.7),
Colors.transparent,
],
),
),
child: Column(
children: [
Text(
event['subtitle']!,
style: Theme.of(context).textTheme.labelMedium,
),
const SizedBox(height: 5),
Text(
event['title']!,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
],
),
),
),
],
),
);
}).toList(),
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: () {},
child: const Text('VIEW OUR BLOG'),
),
],
),
);
}

Widget _buildFooterSection(BuildContext context) {


return Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/footer-bg.jpg'),
fit: BoxFit.cover,
),
),
padding: const EdgeInsets.symmetric(vertical: 70),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(40),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/footer-form-bg.png'),
fit: BoxFit.cover,
),
),
child: Column(
children: [
Image.asset('assets/images/logo.svg', height: 50, width:
160),
const SizedBox(height: 40),
Text(
'Restaurant St, Delicious City, London 9578, UK',
style: Theme.of(context).textTheme.bodySmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
GestureDetector(
onTap: () => _launchUrl('mailto:booking@grilli.com'),
child: Text(
'booking@grilli.com',
style:
Theme.of(context).textTheme.bodySmall?.copyWith(color: const Color(0xFFDBA159)),
),
),
const SizedBox(height: 6),
GestureDetector(
onTap: () => _launchUrl('tel:+88123123456'),
child: Text(
'Booking Request : +88-123-123456',
style:
Theme.of(context).textTheme.bodySmall?.copyWith(color: const Color(0xFFDBA159)),
),
),
const SizedBox(height: 6),
Text(
'Open : 09:00 am - 01:00 pm',
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 40),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (index) => Container(
margin: const EdgeInsets.symmetric(horizontal: 1),
width: 8,
height: 8,
decoration: BoxDecoration(
border: Border.all(color: const Color(0xFFDBA159)),
shape: BoxShape.circle,
),
)),
),
const SizedBox(height: 25),
Text(
'Get News & Offers',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 10),
Text(
'Subscribe us & Get 25% Off.',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: const Color(0xFFDBA159),
),
),
const SizedBox(height: 30),
Row(
children: [
Expanded(
child: TextFormField(
decoration: const InputDecoration(
prefixIcon: Icon(Icons.mail_outline, color:
Colors.white),
hintText: 'Your email',
),
),
),
ElevatedButton(
onPressed: () {},
child: const Text('SUBSCRIBE'),
),
],
),
],
),
),
),
Expanded(
child: Column(
children: [
_buildFooterLink('Home'),
_buildFooterLink('Menus'),
_buildFooterLink('About Us'),
_buildFooterLink('Our Chefs'),
_buildFooterLink('Contact'),
],
),
),
Expanded(
child: Column(
children: [
_buildFooterLink('Facebook'),
_buildFooterLink('Instagram'),
_buildFooterLink('Twitter'),
_buildFooterLink('Youtube'),
_buildFooterLink('Google Map'),
],
),
),
],
),
const SizedBox(height: 70),
Text(
'© 2022 Grilli. All Rights Reserved | Crafted by codewithsadee',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
);
}

Widget _buildFooterLink(String title) {


return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: GestureDetector(
onTap: () {},
child: Text(
title,
style: Theme.of(context).textTheme.labelMedium?.copyWith(color: const
Color(0xFFA6A6A6)),
),
),
);
}

Future<void> _launchUrl(String url) async {


final Uri uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
}
}
}

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy