Files
Siro/siro_rider/lib/views/food/food_home_page.dart
T

271 lines
10 KiB
Dart

// food_home_page.dart — الصفحة الرئيسية لتبويب "طعام": تصفح المطاعم
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
import '../../main.dart';
import '../../controller/food/food_controller.dart';
import '../../controller/food/food_models.dart';
import '../widgets/my_scafold.dart';
import 'food_merchant_page.dart';
import 'food_cart_page.dart';
import 'food_order_history_page.dart';
class FoodHomePage extends StatelessWidget {
const FoodHomePage({super.key});
bool get _isAr => box.read(BoxName.lang) == 'ar';
@override
Widget build(BuildContext context) {
final c = Get.put(FoodController());
c.fetchMerchants();
return GetBuilder<FoodController>(
builder: (c) => MyScafolld(
title: _isAr ? 'طعام' : 'Food',
isleading: true,
action: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.history_rounded, color: AppColor.primaryColor),
onPressed: () => Get.to(() => const FoodOrderHistoryPage()),
),
Stack(
clipBehavior: Clip.none,
children: [
IconButton(
icon: Icon(Icons.shopping_cart_rounded, color: AppColor.primaryColor),
onPressed: () => Get.to(() => const FoodCartPage()),
),
if (c.cartItemsCount > 0)
Positioned(
right: 4,
top: 4,
child: Container(
padding: const EdgeInsets.all(4),
decoration: const BoxDecoration(color: AppColor.redColor, shape: BoxShape.circle),
constraints: const BoxConstraints(minWidth: 18, minHeight: 18),
child: Text(
c.cartItemsCount.toString(),
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold),
),
),
),
],
),
],
),
body: [
Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: _citySearchBar(c),
),
Expanded(
child: RefreshIndicator(
onRefresh: () => c.fetchMerchants(),
child: c.isLoadingMerchants
? const Center(child: CircularProgressIndicator())
: c.merchants.isEmpty
? _emptyState()
: ListView.builder(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 24),
itemCount: c.merchants.length,
itemBuilder: (_, i) => _merchantCard(c.merchants[i]),
),
),
),
],
),
],
),
);
}
Widget _citySearchBar(FoodController c) {
return Row(
children: [
Expanded(
child: InkWell(
onTap: () => _showCityPicker(c),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration: BoxDecoration(
color: AppColor.cardColor,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.borderColor),
),
child: Row(
children: [
Icon(Icons.location_on_rounded, color: AppColor.accentColor, size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(c.city, style: AppStyle.title, overflow: TextOverflow.ellipsis),
),
Icon(Icons.keyboard_arrow_down_rounded, color: AppColor.grayColor),
],
),
),
),
),
const SizedBox(width: 8),
InkWell(
onTap: () => _showSearchDialog(c),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColor.cardColor,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.borderColor),
),
child: Icon(Icons.search_rounded, color: AppColor.primaryColor),
),
),
],
);
}
void _showCityPicker(FoodController c) {
final controller = TextEditingController(text: c.city);
Get.dialog(
AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Text(_isAr ? 'اختر المدينة' : 'Select City'),
content: TextField(
controller: controller,
decoration: InputDecoration(hintText: _isAr ? 'اسم المدينة' : 'City name'),
),
actions: [
TextButton(onPressed: () => Get.back(), child: Text(_isAr ? 'إلغاء' : 'Cancel')),
ElevatedButton(
onPressed: () {
Get.back();
c.setCity(controller.text);
},
child: Text(_isAr ? 'تم' : 'Done'),
),
],
),
);
}
void _showSearchDialog(FoodController c) {
final controller = TextEditingController();
Get.dialog(
AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Text(_isAr ? 'بحث عن مطعم أو صنف' : 'Search restaurant or dish'),
content: TextField(
controller: controller,
autofocus: true,
decoration: InputDecoration(hintText: _isAr ? 'اكتب هنا...' : 'Type here...'),
),
actions: [
TextButton(onPressed: () => Get.back(), child: Text(_isAr ? 'إلغاء' : 'Cancel')),
ElevatedButton(
onPressed: () {
Get.back();
c.searchMerchants(controller.text);
},
child: Text(_isAr ? 'بحث' : 'Search'),
),
],
),
);
}
Widget _emptyState() {
return ListView(
padding: const EdgeInsets.all(24),
children: [
const SizedBox(height: 60),
Icon(Icons.restaurant_menu_rounded, size: 72, color: AppColor.grayColor),
const SizedBox(height: 16),
Text(
_isAr ? 'لا توجد مطاعم متاحة في هذه المدينة حالياً' : 'No restaurants available in this city yet',
textAlign: TextAlign.center,
style: AppStyle.title.copyWith(fontWeight: FontWeight.bold),
),
],
);
}
Widget _merchantCard(FoodMerchant m) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
color: AppColor.cardColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: AppColor.borderColor),
),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => Get.to(() => FoodMerchantPage(merchantId: m.id)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (m.coverUrl != null && m.coverUrl!.isNotEmpty)
Image.network(m.coverUrl!, height: 120, width: double.infinity, fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Container(height: 120, color: AppColor.borderColor)),
Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
CircleAvatar(
radius: 24,
backgroundColor: AppColor.accentColor.withOpacity(0.15),
backgroundImage: (m.logoUrl != null && m.logoUrl!.isNotEmpty)
? NetworkImage(m.logoUrl!)
: null,
child: (m.logoUrl == null || m.logoUrl!.isEmpty)
? Icon(Icons.restaurant_rounded, color: AppColor.accentColor)
: null,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(m.nameAr, style: AppStyle.title.copyWith(fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Row(
children: [
const Icon(Icons.star_rounded, color: Color(0xFFF59E0B), size: 16),
const SizedBox(width: 2),
Text(m.ratingAvg.toStringAsFixed(1), style: AppStyle.subtitle),
const SizedBox(width: 10),
Icon(Icons.access_time_rounded, size: 14, color: AppColor.grayColor),
const SizedBox(width: 2),
Text('${m.avgPrepMinutes} ${_isAr ? "د" : "min"}', style: AppStyle.subtitle),
],
),
],
),
),
if (!m.isOpen)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppColor.redColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Text(_isAr ? 'مغلق' : 'Closed',
style: TextStyle(color: AppColor.redColor, fontSize: 11, fontWeight: FontWeight.bold)),
),
],
),
),
],
),
),
);
}
}