- Added AddActivityBottomSheet for adding custom activities to trips. - Created Activity model to represent tourist activities. - Developed ActivityRepository for managing activities in Firestore. - Integrated ActivityPlacesService for searching activities via Google Places API. - Updated ShowTripDetailsContent to navigate to activities page. - Enhanced main.dart to include ActivityBloc and necessary repositories.
240 lines
5.7 KiB
Dart
240 lines
5.7 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import '../../models/activity.dart';
|
|
|
|
/// Base class for all activity-related states
|
|
abstract class ActivityState extends Equatable {
|
|
const ActivityState();
|
|
|
|
@override
|
|
List<Object?> get props => [];
|
|
}
|
|
|
|
/// Initial state when no activities have been loaded
|
|
class ActivityInitial extends ActivityState {
|
|
const ActivityInitial();
|
|
}
|
|
|
|
/// State when activities are being loaded
|
|
class ActivityLoading extends ActivityState {
|
|
const ActivityLoading();
|
|
}
|
|
|
|
/// State when activities are being searched
|
|
class ActivitySearching extends ActivityState {
|
|
const ActivitySearching();
|
|
}
|
|
|
|
/// State when activities have been loaded successfully
|
|
class ActivityLoaded extends ActivityState {
|
|
final List<Activity> activities;
|
|
final List<Activity> filteredActivities;
|
|
final String? activeFilter;
|
|
final double? minRating;
|
|
final bool showVotedOnly;
|
|
|
|
const ActivityLoaded({
|
|
required this.activities,
|
|
required this.filteredActivities,
|
|
this.activeFilter,
|
|
this.minRating,
|
|
this.showVotedOnly = false,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
activities,
|
|
filteredActivities,
|
|
activeFilter,
|
|
minRating,
|
|
showVotedOnly,
|
|
];
|
|
|
|
/// Creates a copy of the current state with optional modifications
|
|
ActivityLoaded copyWith({
|
|
List<Activity>? activities,
|
|
List<Activity>? filteredActivities,
|
|
String? activeFilter,
|
|
double? minRating,
|
|
bool? showVotedOnly,
|
|
}) {
|
|
return ActivityLoaded(
|
|
activities: activities ?? this.activities,
|
|
filteredActivities: filteredActivities ?? this.filteredActivities,
|
|
activeFilter: activeFilter ?? this.activeFilter,
|
|
minRating: minRating ?? this.minRating,
|
|
showVotedOnly: showVotedOnly ?? this.showVotedOnly,
|
|
);
|
|
}
|
|
|
|
/// Gets activities by category
|
|
List<Activity> getActivitiesByCategory(String category) {
|
|
return activities.where((activity) => activity.category == category).toList();
|
|
}
|
|
|
|
/// Gets top rated activities
|
|
List<Activity> getTopRatedActivities({int limit = 10}) {
|
|
final sorted = List<Activity>.from(activities);
|
|
sorted.sort((a, b) {
|
|
final aScore = a.totalVotes;
|
|
final bScore = b.totalVotes;
|
|
|
|
if (aScore != bScore) {
|
|
return bScore.compareTo(aScore);
|
|
}
|
|
|
|
return (b.rating ?? 0).compareTo(a.rating ?? 0);
|
|
});
|
|
|
|
return sorted.take(limit).toList();
|
|
}
|
|
}
|
|
|
|
/// State when search results are available
|
|
class ActivitySearchResults extends ActivityState {
|
|
final List<Activity> searchResults;
|
|
final String query;
|
|
final bool isLoading;
|
|
|
|
const ActivitySearchResults({
|
|
required this.searchResults,
|
|
required this.query,
|
|
this.isLoading = false,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [searchResults, query, isLoading];
|
|
|
|
/// Creates a copy with optional modifications
|
|
ActivitySearchResults copyWith({
|
|
List<Activity>? searchResults,
|
|
String? query,
|
|
bool? isLoading,
|
|
}) {
|
|
return ActivitySearchResults(
|
|
searchResults: searchResults ?? this.searchResults,
|
|
query: query ?? this.query,
|
|
isLoading: isLoading ?? this.isLoading,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// State when an operation has completed successfully
|
|
class ActivityOperationSuccess extends ActivityState {
|
|
final String message;
|
|
final String? operationType;
|
|
|
|
const ActivityOperationSuccess(
|
|
this.message, {
|
|
this.operationType,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [message, operationType];
|
|
}
|
|
|
|
/// State when an error has occurred
|
|
class ActivityError extends ActivityState {
|
|
final String message;
|
|
final String? errorCode;
|
|
final dynamic error;
|
|
|
|
const ActivityError(
|
|
this.message, {
|
|
this.errorCode,
|
|
this.error,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [message, errorCode, error];
|
|
}
|
|
|
|
/// State when voting is in progress
|
|
class ActivityVoting extends ActivityState {
|
|
final String activityId;
|
|
final List<Activity> activities;
|
|
|
|
const ActivityVoting({
|
|
required this.activityId,
|
|
required this.activities,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [activityId, activities];
|
|
}
|
|
|
|
/// State when activity is being updated
|
|
class ActivityUpdating extends ActivityState {
|
|
final String activityId;
|
|
final List<Activity> activities;
|
|
|
|
const ActivityUpdating({
|
|
required this.activityId,
|
|
required this.activities,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [activityId, activities];
|
|
}
|
|
|
|
/// State when activities are being added in batch
|
|
class ActivityBatchAdding extends ActivityState {
|
|
final List<Activity> activitiesToAdd;
|
|
final int progress;
|
|
final int total;
|
|
|
|
const ActivityBatchAdding({
|
|
required this.activitiesToAdd,
|
|
required this.progress,
|
|
required this.total,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [activitiesToAdd, progress, total];
|
|
|
|
/// Gets the progress as a percentage
|
|
double get progressPercentage => total > 0 ? progress / total : 0.0;
|
|
}
|
|
|
|
/// State when an activity has been successfully added
|
|
class ActivityAdded extends ActivityState {
|
|
final Activity activity;
|
|
final String message;
|
|
|
|
const ActivityAdded({
|
|
required this.activity,
|
|
required this.message,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [activity, message];
|
|
}
|
|
|
|
/// State when an activity has been successfully deleted
|
|
class ActivityDeleted extends ActivityState {
|
|
final String activityId;
|
|
final String message;
|
|
|
|
const ActivityDeleted({
|
|
required this.activityId,
|
|
required this.message,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [activityId, message];
|
|
}
|
|
|
|
/// State when vote has been successfully recorded
|
|
class ActivityVoteRecorded extends ActivityState {
|
|
final String activityId;
|
|
final int vote;
|
|
final String userId;
|
|
|
|
const ActivityVoteRecorded({
|
|
required this.activityId,
|
|
required this.vote,
|
|
required this.userId,
|
|
});
|
|
|
|
@override
|
|
List<Object> get props => [activityId, vote, userId];
|
|
} |