Files
TravelMate/lib/models/activity.dart
2025-12-03 17:32:06 +01:00

262 lines
7.3 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
/// Modèle représentant une activité touristique liée à un voyage
class Activity {
final String id;
final String tripId;
final String name;
final String description;
final String category;
final String? imageUrl;
final double? rating;
final String? priceLevel;
final String? address;
final double? latitude;
final double? longitude;
final String? placeId; // Google Places ID
final String? website;
final String? phoneNumber;
final List<String> openingHours;
final Map<String, int> votes; // userId -> vote (1 pour pour, -1 pour contre)
final DateTime createdAt;
final DateTime updatedAt;
final DateTime? date; // Date prévue pour l'activité
final String? createdBy; // ID de l'utilisateur qui a créé l'activité
Activity({
required this.id,
required this.tripId,
required this.name,
required this.description,
required this.category,
this.imageUrl,
this.rating,
this.priceLevel,
this.address,
this.latitude,
this.longitude,
this.placeId,
this.website,
this.phoneNumber,
this.openingHours = const [],
this.votes = const {},
required this.createdAt,
required this.updatedAt,
this.date,
this.createdBy,
});
/// Calcule le score total des votes
int get totalVotes {
return votes.values.fold(0, (total, vote) => total + vote);
}
/// Calcule le nombre de votes positifs
int get positiveVotes {
return votes.values.where((vote) => vote > 0).length;
}
/// Calcule le nombre de votes négatifs
int get negativeVotes {
return votes.values.where((vote) => vote < 0).length;
}
/// Vérifie si l'utilisateur a voté
bool hasUserVoted(String userId) {
return votes.containsKey(userId);
}
/// Récupère le vote d'un utilisateur (-1, 0, 1)
int getUserVote(String userId) {
return votes[userId] ?? 0;
}
/// Vérifie si tous les participants du voyage ont voté positivement pour cette activité
bool isApprovedByAllParticipants(List<String> tripParticipants) {
if (tripParticipants.isEmpty) return false;
// Tous les participants doivent avoir voté
for (String participantId in tripParticipants) {
if (!votes.containsKey(participantId)) {
return false; // Quelqu'un n'a pas encore voté
}
if (votes[participantId] != 1) {
return false; // Quelqu'un a voté négativement ou neutre
}
}
return true; // Tous ont voté positivement
}
/// Crée une copie avec des modifications
Activity copyWith({
String? id,
String? tripId,
String? name,
String? description,
String? category,
String? imageUrl,
double? rating,
String? priceLevel,
String? address,
double? latitude,
double? longitude,
String? placeId,
String? website,
String? phoneNumber,
List<String>? openingHours,
Map<String, int>? votes,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? date,
bool clearDate = false,
String? createdBy,
}) {
return Activity(
id: id ?? this.id,
tripId: tripId ?? this.tripId,
name: name ?? this.name,
description: description ?? this.description,
category: category ?? this.category,
imageUrl: imageUrl ?? this.imageUrl,
rating: rating ?? this.rating,
priceLevel: priceLevel ?? this.priceLevel,
address: address ?? this.address,
latitude: latitude ?? this.latitude,
longitude: longitude ?? this.longitude,
placeId: placeId ?? this.placeId,
website: website ?? this.website,
phoneNumber: phoneNumber ?? this.phoneNumber,
openingHours: openingHours ?? this.openingHours,
votes: votes ?? this.votes,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
date: clearDate ? null : (date ?? this.date),
createdBy: createdBy ?? this.createdBy,
);
}
/// Conversion vers Map pour Firestore
Map<String, dynamic> toMap() {
return {
'id': id,
'tripId': tripId,
'name': name,
'description': description,
'category': category,
'imageUrl': imageUrl,
'rating': rating,
'priceLevel': priceLevel,
'address': address,
'latitude': latitude,
'longitude': longitude,
'placeId': placeId,
'website': website,
'phoneNumber': phoneNumber,
'openingHours': openingHours,
'votes': votes,
'createdAt': Timestamp.fromDate(createdAt),
'updatedAt': Timestamp.fromDate(updatedAt),
'date': date != null ? Timestamp.fromDate(date!) : null,
'createdBy': createdBy,
};
}
/// Création depuis Map Firestore
factory Activity.fromMap(Map<String, dynamic> map) {
return Activity(
id: map['id'] ?? '',
tripId: map['tripId'] ?? '',
name: map['name'] ?? '',
description: map['description'] ?? '',
category: map['category'] ?? '',
imageUrl: map['imageUrl'],
rating: map['rating']?.toDouble(),
priceLevel: map['priceLevel'],
address: map['address'],
latitude: map['latitude']?.toDouble(),
longitude: map['longitude']?.toDouble(),
placeId: map['placeId'],
website: map['website'],
phoneNumber: map['phoneNumber'],
openingHours: List<String>.from(map['openingHours'] ?? []),
votes: Map<String, int>.from(map['votes'] ?? {}),
createdAt: (map['createdAt'] as Timestamp).toDate(),
updatedAt: (map['updatedAt'] as Timestamp).toDate(),
date: map['date'] != null ? (map['date'] as Timestamp).toDate() : null,
createdBy: map['createdBy'],
);
}
/// Création depuis snapshot Firestore
factory Activity.fromSnapshot(DocumentSnapshot snapshot) {
final data = snapshot.data() as Map<String, dynamic>;
return Activity.fromMap({...data, 'id': snapshot.id});
}
@override
String toString() {
return 'Activity(id: $id, name: $name, category: $category, votes: $totalVotes)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Activity && other.id == id;
}
@override
int get hashCode => id.hashCode;
}
/// Énumération des catégories d'activités
enum ActivityCategory {
museum('Musée', 'museum'),
restaurant('Restaurant', 'restaurant'),
attraction('Attraction', 'tourist_attraction'),
entertainment('Divertissement', 'amusement_park'),
shopping('Shopping', 'shopping_mall'),
nature('Nature', 'park'),
culture('Culture', 'establishment'),
nightlife('Vie nocturne', 'night_club'),
sports('Sports', 'gym'),
relaxation('Détente', 'spa');
const ActivityCategory(this.displayName, this.googlePlaceType);
final String displayName;
final String googlePlaceType;
static ActivityCategory? fromGoogleType(String type) {
for (final category in ActivityCategory.values) {
if (category.googlePlaceType == type) {
return category;
}
}
return null;
}
}
/// Énumération des niveaux de prix
enum PriceLevel {
free('Gratuit', 0),
inexpensive('Bon marché', 1),
moderate('Modéré', 2),
expensive('Cher', 3),
veryExpensive('Très cher', 4);
const PriceLevel(this.displayName, this.level);
final String displayName;
final int level;
static PriceLevel? fromLevel(int level) {
for (final price in PriceLevel.values) {
if (price.level == level) {
return price;
}
}
return null;
}
}