First of all im just trying do that plan bcse i whatch YouTube channel Mithc Koko and try add something new thats my plan:
IN PRODUCT PAGE :
- 5 stars (collecting if each user want to rate product)
- if user rate product 0-5 (the product position is sorted by rating in HomePage)
- when user search, do same thing but there user can chose how to sort search.(raiting, location, price)
for now i dont realisate ratingBar for rate food im stuck there how to calculate and saveload rating and sort in Page;
This my Food class :
import 'package:combi/models/rating_manager.dart';
class Food {
final String name;
final String restaurantName;
final String restaurantUid; // Add restaurantUid property
final String description;
final String imagePath;
final FoodCategory category;
final int price;
int popularity;
final bool favorites;
List<Addon> availableAddons;
Food({
required this.name,
required this.description,
required this.imagePath,
required this.price,
required this.availableAddons,
required this.restaurantName,
required this.restaurantUid, // Initialize restaurantUid when creating Food objects
this.popularity = 0,
this.favorites = false,
required this.category,
});
// Method to update popularity based on user rating
void updatePopularity(
int rating, int foodWeight, int restaurantWeight, int positionIndex) {
// Calculate the new popularity score
popularity = RatingManager.calculatePopularity(
popularity,
rating,
foodWeight,
restaurantWeight,
positionIndex,
);
}
// Method to toggle favorites
Food toggleFavorite() {
return Food(
name: name,
restaurantName: restaurantName,
restaurantUid:
restaurantUid, // Handle null value by providing a default value
description: description,
imagePath: imagePath,
category: category,
price: price,
popularity: popularity,
availableAddons: availableAddons,
favorites: !favorites, // Toggle the value
);
}
}
enum FoodCategory {
combo,
doner,
pizza,
chicken,
}
class Addon {
String name;
int price;
Addon({
required this.name,
required this.price,
});
}
new class RatingManager:
class RatingManager {
static int calculatePopularity(int currentPopularity, int rating,
int foodWeight, int restaurantWeight, int positionIndex) {
int newPopularity = (currentPopularity +
(rating * (foodWeight + restaurantWeight) * positionIndex))
.toInt();
return newPopularity;
}
}
and this how Menu load from firebase for HomePage:
class Restaurant extends ChangeNotifier {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final FirebaseAuth _auth;
final List<Food> _menu = [];
final String name;
int popularity;
final List<Food> _favoriteItems = []; // Add list of favorite foods
Restaurant({
required this.name,
this.popularity = 0,
required FirebaseAuth auth, // Pass FirebaseAuth instance as a parameter
}) : _auth = auth {
_loadMenu();
}
// Load menu from Firestore
Future<void> _loadMenu() async {
try {
QuerySnapshot querySnapshot = await _firestore.collection('foods').get();
List<Food> loadedMenu =
querySnapshot.docs.map((doc) => _foodFromSnapshot(doc)).toList();
_menu.addAll(loadedMenu);
notifyListeners();
// Check if the user is authenticated
if (_auth.currentUser != null) {
DocumentSnapshot userDoc = await _firestore
.collection("Users")
.doc(_auth.currentUser!.uid)
.get();
Map<String, dynamic> userData =
userDoc.data() as Map<String, dynamic>? ?? {};
String? userName = userData['name'];
String? userPhoneNumber = userData['phoneNumber'];
String? restaurantUid = userData['restaurantUid'];
// Update SharedPreferences with user's name and phone number if available
if (userName != null &&
userPhoneNumber != null &&
restaurantUid != null) {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('name', userName);
await prefs.setString('phoneNumber', userPhoneNumber);
await prefs.setString('restaurantUid', restaurantUid);
}
}
} catch (e) {
print('Error loading menu: $e');
}
}
// Getter for favorite items
List<FavoriteItem> get favoriteItems {
// Convert favorite foods to FavoriteItem objects with selected addons
return _favoriteItems
.map((food) => FavoriteItem(food: food, selectedAddons: []))
.toList();
}
void updatePopularity(int rating, int restaurantWeight) {
// Calculate the new popularity score
popularity = RatingManager.calculatePopularity(
popularity,
rating,
0, // Placeholder for food weight, as it's not provided in this method
restaurantWeight,
0, // Placeholder for position index, as it's not provided in this method
);
}
Food _foodFromSnapshot(DocumentSnapshot snapshot) {
Map<String, dynamic> data = snapshot.data() as Map<String, dynamic>;
String categoryString = data['category'] ?? '';
FoodCategory category =
_getFoodCategory(categoryString); // Convert string to enum
return Food(
name: data['name'] ?? '',
description: data['description'] ?? '',
imagePath: data['imagePath'] ?? '',
price: (data['price'] ?? 0).toInt(), // Convert double to int
category: category,
availableAddons: _addonsFromMapList(data['availableAddons'] ?? []),
restaurantName: data['restaurantName'] ?? '',
restaurantUid: data['restaurantUid'] ?? '', // Initialize restaurantUid
popularity: (data['popularity'] ?? 0).toInt(), // Convert double to int
favorites: data['favorites'] ?? false,
);
}
// Helper method to convert string to FoodCategory enum
FoodCategory _getFoodCategory(String categoryString) {
switch (categoryString.toLowerCase()) {
case 'combo':
return FoodCategory.combo;
case 'doner':
return FoodCategory.doner;
case 'pizza':
return FoodCategory.pizza;
case 'chicken':
return FoodCategory.chicken;
default:
return FoodCategory.combo; // Default to combo if category is unknown
}
}
// Helper method to convert list of maps to list of Addon objects
List<Addon> _addonsFromMapList(List<dynamic> mapList) {
return mapList
.map((addon) => Addon(
name: addon['name'] ?? '',
price: addon['price'] ?? 0,
))
.toList();
}
// user cart - real quic))
final List<CartItem> _cart = [];
// delivery address (can update/change)
String _deliveryAddress = 'город: Актобе';
// G E T T E R S
List<Food> get menu => _menu;
List<CartItem> get cart => _cart;
String get deliveryAddress => _deliveryAddress;
// O P E R A T I O N S
// add to cart
void addToCart(Food food, List<Addon> selectedAddons) {
// see if there is a cart item already with the same food and selected addons
CartItem? cartItem = _cart.firstWhereOrNull((item) {
// check if the food items are the same
bool isSameFood = item.food == food;
// check if the List of selected addons are the same
bool isSameAddons =
const ListEquality().equals(item.selectedAddons, selectedAddons);
return isSameFood && isSameAddons;
});
// if item already exist, increase it`s quantity
if (cartItem != null) {
cartItem.quantity++;
}
// otherwise, add a new cart item to the cart
else {
_cart.add(
CartItem(
food: food,
selectedAddons: selectedAddons,
),
);
}
notifyListeners();
}
// add to favorites
void addToFavorites(Food food, List<Addon> selectedAddons) {
// Check if the food with the same addons already exists in favorites
FavoriteItem? existingFavorite = _favoriteItems
.map((food) => FavoriteItem(food: food, selectedAddons: []))
.firstWhereOrNull((favoriteItem) {
// Check if the food items are the same
bool isSameFood = favoriteItem.food == food;
// Check if the list of selected addons are the same
bool isSameAddons = const ListEquality()
.equals(favoriteItem.selectedAddons, selectedAddons);
return isSameFood && isSameAddons;
});
// If the item already exists, do nothing
if (existingFavorite != null) {
return;
}
// Otherwise, add a new favorite item to the favorites list
_favoriteItems.add(food);
// Toggle favorite status
food.toggleFavorite();
// Notify listeners
notifyListeners();
}
// remove from cart
void removeFromCart(CartItem cartItem) {
int cartIndex = _cart.indexOf(cartItem);
if (cartIndex != -1) {
if (_cart[cartIndex].quantity > 1) {
_cart[cartIndex].quantity--;
} else {
_cart.removeAt(cartIndex);
}
}
notifyListeners();
}
// Remove from favorites
void removeFromFavorites(Food food) {
int favoriteIndex = _favoriteItems.indexOf(food);
if (favoriteIndex != -1) {
_favoriteItems.removeAt(favoriteIndex);
}
// Toggle favorite status
food.toggleFavorite();
notifyListeners();
}
// get total price
int getTotalPrice() {
int total = 0;
for (CartItem cartItem in _cart) {
int itemTotal = cartItem.food.price;
for (Addon addon in cartItem.selectedAddons) {
itemTotal += addon.price;
}
total += itemTotal * cartItem.quantity;
}
return total;
}
// get total number of items in cart
int getTotalItemCount() {
int totalItemCount = 0;
for (CartItem cartItem in _cart) {
totalItemCount += cartItem.quantity;
}
return totalItemCount;
}
// clear cart
void clearCart() {
_cart.clear();
notifyListeners();
}
// clear favorites
void clearFavorites() {
_cart.clear();
notifyListeners();
}
// update delivery address
void updateDeliveryAddress(String newAddress) {
_deliveryAddress = newAddress;
notifyListeners();
}
// H E L P E R S
// Update displayCartReceipt method
Future<String> displayCartReceipt() async {
try {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final receipt = StringBuffer();
receipt.writeln("Статус оплаты: "); //$paymentStatus
// Format the date to include up to seconds only
String formattedDate =
DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
// Append the formatted date to the receipt
receipt.writeln("Дата: $formattedDate");
receipt.writeln();
receipt.writeln(
"Restaurant Name: ${_menu.isNotEmpty ? _menu.first.restaurantName : 'Unknown'}"); // Fetch restaurantName from any item in the menu
// receipt.writeln(
// "Restaurant Uid: ${_menu.isNotEmpty ? _menu.first.restaurantUid : 'Unknown'}"); // Fetch restaurantUid from any item in the menu
receipt.writeln(
"<<-------------------------------------------------------------------------------->>");
// Add cart items details
for (final cartItem in _cart) {
receipt.writeln(
"${cartItem.quantity} x ${cartItem.food.name} - ${_formatPrice(cartItem.food.price)}");
if (cartItem.selectedAddons.isNotEmpty) {
receipt.writeln(
" Дополнения: ${_formatAddons(cartItem.selectedAddons)}");
}
receipt.writeln();
}
// Add total items and total price
receipt.writeln(
"<<-------------------------------------------------------------------------------->>");
receipt.writeln();
receipt.writeln("Общее количество: ${getTotalItemCount()}");
receipt.writeln("Общая сумма: ${_formatPrice(getTotalPrice())}");
receipt.writeln(
"<<-------------------------------------------------------------------------------->>");
receipt.writeln("Доставка по адресу: $deliveryAddress");
// Add saved name and phone number to the receipt
receipt.writeln();
receipt.writeln("Имя: ${prefs.getString('name') ?? 'Unknown'}");
receipt.writeln(
"Номер телефона: ${prefs.getString('phoneNumber') ?? 'Unknown'}");
return receipt.toString();
} catch (e) {
print('Error displaying cart receipt: $e');
return "Ошибка при отображении квитанции.";
}
}
// format double/int value into money
String _formatPrice(int price) {
return '${price.toStringAsFixed(2)}₸';
}
// format list of addons into a string summary
String _formatAddons(List<Addon> addons) {
return addons
.map((addon) => "${addon.name} (${_formatPrice(addon.price)})")
.join(", ");
}
Restaurant copyWith({
String? name,
int? popularity,
}) {
return Restaurant(
name: name ?? this.name,
popularity: popularity ?? this.popularity,
auth: FirebaseAuth.instance,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'name': name,
'popularity': popularity,
};
}
factory Restaurant.fromMap(Map<String, dynamic> map) {
return Restaurant(
name: map['name'] as String,
popularity: map['popularity'] as int,
auth: FirebaseAuth.instance,
);
}
String toJson() => json.encode(toMap());
factory Restaurant.fromJson(String source) =>
Restaurant.fromMap(json.decode(source) as Map<String, dynamic>);
@override
String toString() => 'Restaurant(name: $name, popularity: $popularity)';
@override
bool operator ==(covariant Restaurant other) {
if (identical(this, other)) return true;
return other.name == name && other.popularity == popularity;
}
@override
int get hashCode => name.hashCode ^ popularity.hashCode;
}
i do something wrong, i know. Maybe someone tell me easy way or example please? Thanks!
i was try do rate and just save number with product information (it works) but after days i think i can do better and sort this rated products (and now im here) hope some body help me bcse im bored after weeks drop this project and created new one, but still wanna try that idea