272 lines
8.5 KiB
Dart
272 lines
8.5 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/material.dart';
|
|
import '../widgets/product_card.dart';
|
|
|
|
class DailyBestSellsWidget extends StatefulWidget {
|
|
const DailyBestSellsWidget({super.key});
|
|
|
|
@override
|
|
_DailyBestSellsWidgetState createState() => _DailyBestSellsWidgetState();
|
|
}
|
|
|
|
class _DailyBestSellsWidgetState extends State<DailyBestSellsWidget> {
|
|
final PageController _pageController = PageController(viewportFraction: 0.85);
|
|
bool _isDragging = false;
|
|
Timer? _autoScrollTimer;
|
|
int _currentPage = 0;
|
|
int _selectedTabIndex = 0;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_startAutoScroll();
|
|
}
|
|
|
|
void _startAutoScroll() {
|
|
_autoScrollTimer = Timer.periodic(const Duration(seconds: 4), (_) {
|
|
if (!_isDragging && _pageController.hasClients) {
|
|
final nextPage = (_currentPage + 1) % _products.length;
|
|
_pageController.animateToPage(
|
|
nextPage,
|
|
duration: const Duration(milliseconds: 600),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
final List<Map<String, dynamic>> _products = [
|
|
{
|
|
'name': 'Seeds of Change Organic Quinoa, Brown',
|
|
'brand': 'Hodo Foods',
|
|
'rating': 4.5,
|
|
'originalPrice': 245.8,
|
|
'discountedPrice': 238.85,
|
|
'sold': 90,
|
|
'total': 120,
|
|
'imageUrl': 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-3-2.jpg',
|
|
'discount': 15,
|
|
},
|
|
{
|
|
'name': 'All Natural Italian-Style Chicken Meatballs',
|
|
'brand': 'Hodo Foods',
|
|
'rating': 4.5,
|
|
'originalPrice': 245.8,
|
|
'discountedPrice': 238.85,
|
|
'sold': 90,
|
|
'total': 120,
|
|
'imageUrl': 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-3-2.jpg',
|
|
'discount': 35,
|
|
},
|
|
{
|
|
'name': 'Organic Brown Rice and Quinoa Mix',
|
|
'brand': 'Green Harvest',
|
|
'rating': 4.8,
|
|
'originalPrice': 310.0,
|
|
'discountedPrice': 280.0,
|
|
'sold': 60,
|
|
'total': 100,
|
|
'imageUrl': 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-4-1.jpg',
|
|
'discount': 10,
|
|
},
|
|
{
|
|
'name': 'Gluten-Free Coconut Flakes',
|
|
'brand': 'Let\'s Do Organic',
|
|
'rating': 4.7,
|
|
'originalPrice': 299.99,
|
|
'discountedPrice': 250.0,
|
|
'sold': 110,
|
|
'total': 150,
|
|
'imageUrl': 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-5-1.jpg',
|
|
'discount': 25,
|
|
},
|
|
{
|
|
'name': 'Organic Almond Butter Crunch',
|
|
'brand': 'Nature\'s Best',
|
|
'rating': 4.6,
|
|
'originalPrice': 280.0,
|
|
'discountedPrice': 245.0,
|
|
'sold': 85,
|
|
'total': 100,
|
|
'imageUrl': 'https://nest-frontend-v6.vercel.app/assets/imgs/shop/product-6-1.jpg',
|
|
'discount': 12,
|
|
},
|
|
];
|
|
|
|
@override
|
|
void dispose() {
|
|
_autoScrollTimer?.cancel();
|
|
_pageController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Widget _buildTabs() {
|
|
final List<String> tabs = ["Featured", "Popular", "New added"];
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Row(
|
|
children: List.generate(tabs.length, (index) {
|
|
final bool isSelected = _selectedTabIndex == index;
|
|
return GestureDetector(
|
|
onTap: () {
|
|
setState(() => _selectedTabIndex = index);
|
|
},
|
|
child: Container(
|
|
margin: const EdgeInsets.only(right: 16),
|
|
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
|
decoration: BoxDecoration(
|
|
color: isSelected ? Colors.green[100] : Colors.white,
|
|
borderRadius: BorderRadius.circular(20),
|
|
border: Border.all(
|
|
color: isSelected ? Colors.green : Colors.grey.shade400,
|
|
width: 1,
|
|
),
|
|
),
|
|
child: Text(
|
|
tabs[index],
|
|
style: TextStyle(
|
|
color: isSelected ? Colors.green[800] : Colors.grey[700],
|
|
fontWeight: isSelected ? FontWeight.bold : FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_buildTabs(),
|
|
const SizedBox(height: 16),
|
|
SizedBox(
|
|
height: 400,
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
// PageView for one product at a time
|
|
NotificationListener<ScrollNotification>(
|
|
onNotification: (notification) {
|
|
if (notification is ScrollStartNotification) {
|
|
setState(() => _isDragging = true);
|
|
} else if (notification is ScrollEndNotification) {
|
|
setState(() => _isDragging = false);
|
|
} else if (notification is ScrollUpdateNotification) {
|
|
// Optional: update _currentPage during drag for indicators
|
|
}
|
|
return true;
|
|
},
|
|
child: PageView.builder(
|
|
controller: _pageController,
|
|
itemCount: _products.length,
|
|
onPageChanged: (index) {
|
|
setState(() => _currentPage = index);
|
|
},
|
|
itemBuilder: (context, index) {
|
|
final product = _products[index];
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: ProductCard(
|
|
productName: product['name']!,
|
|
brand: product['brand']!,
|
|
rating: product['rating']!,
|
|
originalPrice: product['originalPrice']!,
|
|
discountedPrice: product['discountedPrice']!,
|
|
sold: product['sold']!,
|
|
total: product['total']!,
|
|
imageUrl: product['imageUrl']!,
|
|
discount: product['discount']!,
|
|
onPressed: () {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(content: Text("Added to cart!")),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
|
|
// Left Arrow
|
|
Positioned(
|
|
left: 16,
|
|
child: _scrollArrowButton(Icons.arrow_back_ios, _goToPrevious),
|
|
),
|
|
|
|
// Right Arrow
|
|
Positioned(
|
|
right: 16,
|
|
child: _scrollArrowButton(Icons.arrow_forward_ios, _goToNext),
|
|
),
|
|
|
|
// Optional: Page indicators (dots) at bottom
|
|
// Positioned(
|
|
// bottom: 16,
|
|
// left: 0,
|
|
// right: 0,
|
|
// child: Row(
|
|
// mainAxisAlignment: MainAxisAlignment.center,
|
|
// children: List.generate(_products.length, (index) {
|
|
// return Container(
|
|
// width: 8,
|
|
// height: 8,
|
|
// margin: const EdgeInsets.symmetric(horizontal: 4),
|
|
// decoration: BoxDecoration(
|
|
// shape: BoxShape.circle,
|
|
// color: _currentPage == index ? Colors.green : Colors.grey[300],
|
|
// ),
|
|
// );
|
|
// }),
|
|
// ),
|
|
// ),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _scrollArrowButton(IconData icon, VoidCallback onPressed) {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.green.withOpacity(0.8),
|
|
shape: BoxShape.circle,
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.white.withOpacity(0.15),
|
|
blurRadius: 4,
|
|
spreadRadius: 2,
|
|
),
|
|
],
|
|
),
|
|
child: IconButton(
|
|
icon: Icon(icon, size: 24, color: Colors.black87),
|
|
onPressed: onPressed,
|
|
),
|
|
);
|
|
}
|
|
|
|
void _goToPrevious() {
|
|
if (_currentPage > 0) {
|
|
_pageController.animateToPage(
|
|
_currentPage - 1,
|
|
duration: const Duration(milliseconds: 500),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
}
|
|
|
|
void _goToNext() {
|
|
if (_currentPage < _products.length - 1) {
|
|
_pageController.animateToPage(
|
|
_currentPage + 1,
|
|
duration: const Duration(milliseconds: 500),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
}
|
|
} |