1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 13:58:47 +00:00

Compass app (#2446)

This commit is contained in:
Eric Windmill
2024-09-27 18:49:27 -04:00
committed by GitHub
parent fcf2552cda
commit 46b5a26b26
326 changed files with 53272 additions and 0 deletions

3
compass_app/server/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/

View File

@@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

View File

@@ -0,0 +1,39 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:compass_server/middleware/auth.dart';
import 'package:compass_server/routes/booking.dart';
import 'package:compass_server/routes/continent.dart';
import 'package:compass_server/routes/destination.dart';
import 'package:compass_server/routes/login.dart';
import 'package:compass_server/routes/user.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/shelf_router.dart';
// Configure routes.
final _router = Router()
..get('/continent', continentHandler)
..mount('/destination', DestinationApi().router.call)
..mount('/booking', BookingApi().router.call)
..mount('/user', UserApi().router.call)
..mount('/login', LoginApi().router.call);
void main(List<String> args) async {
// Use any available host or container IP (usually `0.0.0.0`).
final ip = InternetAddress.anyIPv4;
// Configure a pipeline that logs requests.
final handler = Pipeline()
.addMiddleware(logRequests())
.addMiddleware(authRequests())
.addHandler(_router.call);
// For running in containers, we respect the PORT environment variable.
final port = int.parse(Platform.environment['PORT'] ?? '8080');
final server = await serve(handler, ip, port);
print('Server listening on port ${server.port}');
}

View File

@@ -0,0 +1,23 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'dart:io';
import '../model/activity/activity.dart';
import '../model/destination/destination.dart';
class Assets {
static const _activities = '../app/assets/activities.json';
static const _destinations = '../app/assets/destinations.json';
static final List<Destination> destinations =
(json.decode(File(Assets._destinations).readAsStringSync()) as List)
.map((element) => Destination.fromJson(element))
.toList();
static final List<Activity> activities =
(json.decode(File(Assets._activities).readAsStringSync()) as List)
.map((element) => Activity.fromJson(element))
.toList();
}

View File

@@ -0,0 +1,34 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../model/user/user.dart';
class Constants {
/// Email for the hardcoded login.
static const email = 'email@example.com';
/// Password for the hardcoded login.
static const password = 'password';
/// Token to be returned on successful login.
static const token =
' e1c37dfd973353b78bb71df050e2c6e72d53034e148920383968ae49b96f1fd2';
/// User id to be returned on successful login.
static const userId = '123';
/// User name for the hardcoded user.
static const name = 'Sofie';
/// For demo purposes we use a local asset.
static const picture = 'assets/user.jpg';
/// Hardcoded user.
static const user = User(
id: Constants.userId,
name: Constants.name,
email: Constants.email,
picture: Constants.picture,
);
}

View File

@@ -0,0 +1,30 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:shelf/shelf.dart';
import '../config/constants.dart';
/// Implements a simple auth Middleware.
///
/// This is provided as an example for Flutter architectural purposes only
/// and shouldn't be used as example on how to implement authentication
/// in production.
///
/// This Middleware checks if the token is present in the request headers,
/// otherwise returns a 401 Unauthorized response.
///
/// This token does not expire and is not secure.
Middleware authRequests() => (innerHandler) {
return (Request request) async {
if (request.url.path != 'login' &&
request.headers['Authorization'] != 'Bearer ${Constants.token}') {
// If the request is not a login request and the token is not present,
// return a 401 Unauthorized response.
return Response.unauthorized('Unauthorized');
}
return innerHandler(request);
};
};

View File

@@ -0,0 +1,56 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'activity.freezed.dart';
part 'activity.g.dart';
enum TimeOfDay {
any,
morning,
afternoon,
evening,
night,
}
@freezed
class Activity with _$Activity {
const factory Activity({
/// e.g. 'Glacier Trekking and Ice Climbing'
required String name,
/// e.g. 'Embark on a thrilling adventure exploring the awe-inspiring glaciers of Alaska. Hike across the icy terrain, marvel at the deep blue crevasses, and even try your hand at ice climbing for an unforgettable experience.'
required String description,
/// e.g. 'Matanuska Glacier or Mendenhall Glacier'
required String locationName,
/// Duration in days.
/// e.g. 8
required int duration,
/// e.g. 'morning'
required TimeOfDay timeOfDay,
/// e.g. false
required bool familyFriendly,
/// e.g. 4
required int price,
/// e.g. 'alaska'
required String destinationRef,
/// e.g. 'glacier-trekking-and-ice-climbing'
required String ref,
/// e.g. 'https://storage.googleapis.com/tripedia-images/activities/alaska_glacier-trekking-and-ice-climbing.jpg'
required String imageUrl,
}) = _Activity;
factory Activity.fromJson(Map<String, Object?> json) =>
_$ActivityFromJson(json);
}

View File

@@ -0,0 +1,425 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'activity.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
Activity _$ActivityFromJson(Map<String, dynamic> json) {
return _Activity.fromJson(json);
}
/// @nodoc
mixin _$Activity {
/// e.g. 'Glacier Trekking and Ice Climbing'
String get name => throw _privateConstructorUsedError;
/// e.g. 'Embark on a thrilling adventure exploring the awe-inspiring glaciers of Alaska. Hike across the icy terrain, marvel at the deep blue crevasses, and even try your hand at ice climbing for an unforgettable experience.'
String get description => throw _privateConstructorUsedError;
/// e.g. 'Matanuska Glacier or Mendenhall Glacier'
String get locationName => throw _privateConstructorUsedError;
/// Duration in days.
/// e.g. 8
int get duration => throw _privateConstructorUsedError;
/// e.g. 'morning'
TimeOfDay get timeOfDay => throw _privateConstructorUsedError;
/// e.g. false
bool get familyFriendly => throw _privateConstructorUsedError;
/// e.g. 4
int get price => throw _privateConstructorUsedError;
/// e.g. 'alaska'
String get destinationRef => throw _privateConstructorUsedError;
/// e.g. 'glacier-trekking-and-ice-climbing'
String get ref => throw _privateConstructorUsedError;
/// e.g. 'https://storage.googleapis.com/tripedia-images/activities/alaska_glacier-trekking-and-ice-climbing.jpg'
String get imageUrl => throw _privateConstructorUsedError;
/// Serializes this Activity to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of Activity
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ActivityCopyWith<Activity> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ActivityCopyWith<$Res> {
factory $ActivityCopyWith(Activity value, $Res Function(Activity) then) =
_$ActivityCopyWithImpl<$Res, Activity>;
@useResult
$Res call(
{String name,
String description,
String locationName,
int duration,
TimeOfDay timeOfDay,
bool familyFriendly,
int price,
String destinationRef,
String ref,
String imageUrl});
}
/// @nodoc
class _$ActivityCopyWithImpl<$Res, $Val extends Activity>
implements $ActivityCopyWith<$Res> {
_$ActivityCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Activity
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? name = null,
Object? description = null,
Object? locationName = null,
Object? duration = null,
Object? timeOfDay = null,
Object? familyFriendly = null,
Object? price = null,
Object? destinationRef = null,
Object? ref = null,
Object? imageUrl = null,
}) {
return _then(_value.copyWith(
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
description: null == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String,
locationName: null == locationName
? _value.locationName
: locationName // ignore: cast_nullable_to_non_nullable
as String,
duration: null == duration
? _value.duration
: duration // ignore: cast_nullable_to_non_nullable
as int,
timeOfDay: null == timeOfDay
? _value.timeOfDay
: timeOfDay // ignore: cast_nullable_to_non_nullable
as TimeOfDay,
familyFriendly: null == familyFriendly
? _value.familyFriendly
: familyFriendly // ignore: cast_nullable_to_non_nullable
as bool,
price: null == price
? _value.price
: price // ignore: cast_nullable_to_non_nullable
as int,
destinationRef: null == destinationRef
? _value.destinationRef
: destinationRef // ignore: cast_nullable_to_non_nullable
as String,
ref: null == ref
? _value.ref
: ref // ignore: cast_nullable_to_non_nullable
as String,
imageUrl: null == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$ActivityImplCopyWith<$Res>
implements $ActivityCopyWith<$Res> {
factory _$$ActivityImplCopyWith(
_$ActivityImpl value, $Res Function(_$ActivityImpl) then) =
__$$ActivityImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String name,
String description,
String locationName,
int duration,
TimeOfDay timeOfDay,
bool familyFriendly,
int price,
String destinationRef,
String ref,
String imageUrl});
}
/// @nodoc
class __$$ActivityImplCopyWithImpl<$Res>
extends _$ActivityCopyWithImpl<$Res, _$ActivityImpl>
implements _$$ActivityImplCopyWith<$Res> {
__$$ActivityImplCopyWithImpl(
_$ActivityImpl _value, $Res Function(_$ActivityImpl) _then)
: super(_value, _then);
/// Create a copy of Activity
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? name = null,
Object? description = null,
Object? locationName = null,
Object? duration = null,
Object? timeOfDay = null,
Object? familyFriendly = null,
Object? price = null,
Object? destinationRef = null,
Object? ref = null,
Object? imageUrl = null,
}) {
return _then(_$ActivityImpl(
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
description: null == description
? _value.description
: description // ignore: cast_nullable_to_non_nullable
as String,
locationName: null == locationName
? _value.locationName
: locationName // ignore: cast_nullable_to_non_nullable
as String,
duration: null == duration
? _value.duration
: duration // ignore: cast_nullable_to_non_nullable
as int,
timeOfDay: null == timeOfDay
? _value.timeOfDay
: timeOfDay // ignore: cast_nullable_to_non_nullable
as TimeOfDay,
familyFriendly: null == familyFriendly
? _value.familyFriendly
: familyFriendly // ignore: cast_nullable_to_non_nullable
as bool,
price: null == price
? _value.price
: price // ignore: cast_nullable_to_non_nullable
as int,
destinationRef: null == destinationRef
? _value.destinationRef
: destinationRef // ignore: cast_nullable_to_non_nullable
as String,
ref: null == ref
? _value.ref
: ref // ignore: cast_nullable_to_non_nullable
as String,
imageUrl: null == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ActivityImpl implements _Activity {
const _$ActivityImpl(
{required this.name,
required this.description,
required this.locationName,
required this.duration,
required this.timeOfDay,
required this.familyFriendly,
required this.price,
required this.destinationRef,
required this.ref,
required this.imageUrl});
factory _$ActivityImpl.fromJson(Map<String, dynamic> json) =>
_$$ActivityImplFromJson(json);
/// e.g. 'Glacier Trekking and Ice Climbing'
@override
final String name;
/// e.g. 'Embark on a thrilling adventure exploring the awe-inspiring glaciers of Alaska. Hike across the icy terrain, marvel at the deep blue crevasses, and even try your hand at ice climbing for an unforgettable experience.'
@override
final String description;
/// e.g. 'Matanuska Glacier or Mendenhall Glacier'
@override
final String locationName;
/// Duration in days.
/// e.g. 8
@override
final int duration;
/// e.g. 'morning'
@override
final TimeOfDay timeOfDay;
/// e.g. false
@override
final bool familyFriendly;
/// e.g. 4
@override
final int price;
/// e.g. 'alaska'
@override
final String destinationRef;
/// e.g. 'glacier-trekking-and-ice-climbing'
@override
final String ref;
/// e.g. 'https://storage.googleapis.com/tripedia-images/activities/alaska_glacier-trekking-and-ice-climbing.jpg'
@override
final String imageUrl;
@override
String toString() {
return 'Activity(name: $name, description: $description, locationName: $locationName, duration: $duration, timeOfDay: $timeOfDay, familyFriendly: $familyFriendly, price: $price, destinationRef: $destinationRef, ref: $ref, imageUrl: $imageUrl)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ActivityImpl &&
(identical(other.name, name) || other.name == name) &&
(identical(other.description, description) ||
other.description == description) &&
(identical(other.locationName, locationName) ||
other.locationName == locationName) &&
(identical(other.duration, duration) ||
other.duration == duration) &&
(identical(other.timeOfDay, timeOfDay) ||
other.timeOfDay == timeOfDay) &&
(identical(other.familyFriendly, familyFriendly) ||
other.familyFriendly == familyFriendly) &&
(identical(other.price, price) || other.price == price) &&
(identical(other.destinationRef, destinationRef) ||
other.destinationRef == destinationRef) &&
(identical(other.ref, ref) || other.ref == ref) &&
(identical(other.imageUrl, imageUrl) ||
other.imageUrl == imageUrl));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
name,
description,
locationName,
duration,
timeOfDay,
familyFriendly,
price,
destinationRef,
ref,
imageUrl);
/// Create a copy of Activity
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ActivityImplCopyWith<_$ActivityImpl> get copyWith =>
__$$ActivityImplCopyWithImpl<_$ActivityImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ActivityImplToJson(
this,
);
}
}
abstract class _Activity implements Activity {
const factory _Activity(
{required final String name,
required final String description,
required final String locationName,
required final int duration,
required final TimeOfDay timeOfDay,
required final bool familyFriendly,
required final int price,
required final String destinationRef,
required final String ref,
required final String imageUrl}) = _$ActivityImpl;
factory _Activity.fromJson(Map<String, dynamic> json) =
_$ActivityImpl.fromJson;
/// e.g. 'Glacier Trekking and Ice Climbing'
@override
String get name;
/// e.g. 'Embark on a thrilling adventure exploring the awe-inspiring glaciers of Alaska. Hike across the icy terrain, marvel at the deep blue crevasses, and even try your hand at ice climbing for an unforgettable experience.'
@override
String get description;
/// e.g. 'Matanuska Glacier or Mendenhall Glacier'
@override
String get locationName;
/// Duration in days.
/// e.g. 8
@override
int get duration;
/// e.g. 'morning'
@override
TimeOfDay get timeOfDay;
/// e.g. false
@override
bool get familyFriendly;
/// e.g. 4
@override
int get price;
/// e.g. 'alaska'
@override
String get destinationRef;
/// e.g. 'glacier-trekking-and-ice-climbing'
@override
String get ref;
/// e.g. 'https://storage.googleapis.com/tripedia-images/activities/alaska_glacier-trekking-and-ice-climbing.jpg'
@override
String get imageUrl;
/// Create a copy of Activity
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ActivityImplCopyWith<_$ActivityImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,43 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'activity.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ActivityImpl _$$ActivityImplFromJson(Map<String, dynamic> json) =>
_$ActivityImpl(
name: json['name'] as String,
description: json['description'] as String,
locationName: json['locationName'] as String,
duration: (json['duration'] as num).toInt(),
timeOfDay: $enumDecode(_$TimeOfDayEnumMap, json['timeOfDay']),
familyFriendly: json['familyFriendly'] as bool,
price: (json['price'] as num).toInt(),
destinationRef: json['destinationRef'] as String,
ref: json['ref'] as String,
imageUrl: json['imageUrl'] as String,
);
Map<String, dynamic> _$$ActivityImplToJson(_$ActivityImpl instance) =>
<String, dynamic>{
'name': instance.name,
'description': instance.description,
'locationName': instance.locationName,
'duration': instance.duration,
'timeOfDay': _$TimeOfDayEnumMap[instance.timeOfDay]!,
'familyFriendly': instance.familyFriendly,
'price': instance.price,
'destinationRef': instance.destinationRef,
'ref': instance.ref,
'imageUrl': instance.imageUrl,
};
const _$TimeOfDayEnumMap = {
TimeOfDay.any: 'any',
TimeOfDay.morning: 'morning',
TimeOfDay.afternoon: 'afternoon',
TimeOfDay.evening: 'evening',
TimeOfDay.night: 'night',
};

View File

@@ -0,0 +1,35 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'booking.freezed.dart';
part 'booking.g.dart';
@freezed
class Booking with _$Booking {
const factory Booking({
/// Booking ID. Generated when stored in server.
int? id,
/// Start date of the trip
required DateTime startDate,
/// End date of the trip
required DateTime endDate,
/// Booking name
/// Should be "Destination, Continent"
required String name,
/// Destination of the trip
required String destinationRef,
/// List of chosen activities
required List<String> activitiesRef,
}) = _Booking;
factory Booking.fromJson(Map<String, Object?> json) =>
_$BookingFromJson(json);
}

View File

@@ -0,0 +1,312 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'booking.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
Booking _$BookingFromJson(Map<String, dynamic> json) {
return _Booking.fromJson(json);
}
/// @nodoc
mixin _$Booking {
/// Booking ID. Generated when stored in server.
int? get id => throw _privateConstructorUsedError;
/// Start date of the trip
DateTime get startDate => throw _privateConstructorUsedError;
/// End date of the trip
DateTime get endDate => throw _privateConstructorUsedError;
/// Booking name
/// Should be "Destination, Continent"
String get name => throw _privateConstructorUsedError;
/// Destination of the trip
String get destinationRef => throw _privateConstructorUsedError;
/// List of chosen activities
List<String> get activitiesRef => throw _privateConstructorUsedError;
/// Serializes this Booking to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of Booking
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$BookingCopyWith<Booking> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $BookingCopyWith<$Res> {
factory $BookingCopyWith(Booking value, $Res Function(Booking) then) =
_$BookingCopyWithImpl<$Res, Booking>;
@useResult
$Res call(
{int? id,
DateTime startDate,
DateTime endDate,
String name,
String destinationRef,
List<String> activitiesRef});
}
/// @nodoc
class _$BookingCopyWithImpl<$Res, $Val extends Booking>
implements $BookingCopyWith<$Res> {
_$BookingCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Booking
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? startDate = null,
Object? endDate = null,
Object? name = null,
Object? destinationRef = null,
Object? activitiesRef = null,
}) {
return _then(_value.copyWith(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int?,
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
destinationRef: null == destinationRef
? _value.destinationRef
: destinationRef // ignore: cast_nullable_to_non_nullable
as String,
activitiesRef: null == activitiesRef
? _value.activitiesRef
: activitiesRef // ignore: cast_nullable_to_non_nullable
as List<String>,
) as $Val);
}
}
/// @nodoc
abstract class _$$BookingImplCopyWith<$Res> implements $BookingCopyWith<$Res> {
factory _$$BookingImplCopyWith(
_$BookingImpl value, $Res Function(_$BookingImpl) then) =
__$$BookingImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int? id,
DateTime startDate,
DateTime endDate,
String name,
String destinationRef,
List<String> activitiesRef});
}
/// @nodoc
class __$$BookingImplCopyWithImpl<$Res>
extends _$BookingCopyWithImpl<$Res, _$BookingImpl>
implements _$$BookingImplCopyWith<$Res> {
__$$BookingImplCopyWithImpl(
_$BookingImpl _value, $Res Function(_$BookingImpl) _then)
: super(_value, _then);
/// Create a copy of Booking
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? startDate = null,
Object? endDate = null,
Object? name = null,
Object? destinationRef = null,
Object? activitiesRef = null,
}) {
return _then(_$BookingImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int?,
startDate: null == startDate
? _value.startDate
: startDate // ignore: cast_nullable_to_non_nullable
as DateTime,
endDate: null == endDate
? _value.endDate
: endDate // ignore: cast_nullable_to_non_nullable
as DateTime,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
destinationRef: null == destinationRef
? _value.destinationRef
: destinationRef // ignore: cast_nullable_to_non_nullable
as String,
activitiesRef: null == activitiesRef
? _value._activitiesRef
: activitiesRef // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$BookingImpl implements _Booking {
const _$BookingImpl(
{this.id,
required this.startDate,
required this.endDate,
required this.name,
required this.destinationRef,
required final List<String> activitiesRef})
: _activitiesRef = activitiesRef;
factory _$BookingImpl.fromJson(Map<String, dynamic> json) =>
_$$BookingImplFromJson(json);
/// Booking ID. Generated when stored in server.
@override
final int? id;
/// Start date of the trip
@override
final DateTime startDate;
/// End date of the trip
@override
final DateTime endDate;
/// Booking name
/// Should be "Destination, Continent"
@override
final String name;
/// Destination of the trip
@override
final String destinationRef;
/// List of chosen activities
final List<String> _activitiesRef;
/// List of chosen activities
@override
List<String> get activitiesRef {
if (_activitiesRef is EqualUnmodifiableListView) return _activitiesRef;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_activitiesRef);
}
@override
String toString() {
return 'Booking(id: $id, startDate: $startDate, endDate: $endDate, name: $name, destinationRef: $destinationRef, activitiesRef: $activitiesRef)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$BookingImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.startDate, startDate) ||
other.startDate == startDate) &&
(identical(other.endDate, endDate) || other.endDate == endDate) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.destinationRef, destinationRef) ||
other.destinationRef == destinationRef) &&
const DeepCollectionEquality()
.equals(other._activitiesRef, _activitiesRef));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, id, startDate, endDate, name,
destinationRef, const DeepCollectionEquality().hash(_activitiesRef));
/// Create a copy of Booking
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$BookingImplCopyWith<_$BookingImpl> get copyWith =>
__$$BookingImplCopyWithImpl<_$BookingImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$BookingImplToJson(
this,
);
}
}
abstract class _Booking implements Booking {
const factory _Booking(
{final int? id,
required final DateTime startDate,
required final DateTime endDate,
required final String name,
required final String destinationRef,
required final List<String> activitiesRef}) = _$BookingImpl;
factory _Booking.fromJson(Map<String, dynamic> json) = _$BookingImpl.fromJson;
/// Booking ID. Generated when stored in server.
@override
int? get id;
/// Start date of the trip
@override
DateTime get startDate;
/// End date of the trip
@override
DateTime get endDate;
/// Booking name
/// Should be "Destination, Continent"
@override
String get name;
/// Destination of the trip
@override
String get destinationRef;
/// List of chosen activities
@override
List<String> get activitiesRef;
/// Create a copy of Booking
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$BookingImplCopyWith<_$BookingImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,29 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'booking.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$BookingImpl _$$BookingImplFromJson(Map<String, dynamic> json) =>
_$BookingImpl(
id: (json['id'] as num?)?.toInt(),
startDate: DateTime.parse(json['startDate'] as String),
endDate: DateTime.parse(json['endDate'] as String),
name: json['name'] as String,
destinationRef: json['destinationRef'] as String,
activitiesRef: (json['activitiesRef'] as List<dynamic>)
.map((e) => e as String)
.toList(),
);
Map<String, dynamic> _$$BookingImplToJson(_$BookingImpl instance) =>
<String, dynamic>{
'id': instance.id,
'startDate': instance.startDate.toIso8601String(),
'endDate': instance.endDate.toIso8601String(),
'name': instance.name,
'destinationRef': instance.destinationRef,
'activitiesRef': instance.activitiesRef,
};

View File

@@ -0,0 +1,23 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'continent.freezed.dart';
part 'continent.g.dart';
@freezed
class Continent with _$Continent {
const factory Continent({
/// e.g. 'Europe'
required String name,
/// e.g. 'https://rstr.in/google/tripedia/TmR12QdlVTT'
required String imageUrl,
}) = _Continent;
factory Continent.fromJson(Map<String, Object?> json) =>
_$ContinentFromJson(json);
}

View File

@@ -0,0 +1,191 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'continent.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
Continent _$ContinentFromJson(Map<String, dynamic> json) {
return _Continent.fromJson(json);
}
/// @nodoc
mixin _$Continent {
/// e.g. 'Europe'
String get name => throw _privateConstructorUsedError;
/// e.g. 'https://rstr.in/google/tripedia/TmR12QdlVTT'
String get imageUrl => throw _privateConstructorUsedError;
/// Serializes this Continent to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of Continent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ContinentCopyWith<Continent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ContinentCopyWith<$Res> {
factory $ContinentCopyWith(Continent value, $Res Function(Continent) then) =
_$ContinentCopyWithImpl<$Res, Continent>;
@useResult
$Res call({String name, String imageUrl});
}
/// @nodoc
class _$ContinentCopyWithImpl<$Res, $Val extends Continent>
implements $ContinentCopyWith<$Res> {
_$ContinentCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Continent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? name = null,
Object? imageUrl = null,
}) {
return _then(_value.copyWith(
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
imageUrl: null == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$ContinentImplCopyWith<$Res>
implements $ContinentCopyWith<$Res> {
factory _$$ContinentImplCopyWith(
_$ContinentImpl value, $Res Function(_$ContinentImpl) then) =
__$$ContinentImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String name, String imageUrl});
}
/// @nodoc
class __$$ContinentImplCopyWithImpl<$Res>
extends _$ContinentCopyWithImpl<$Res, _$ContinentImpl>
implements _$$ContinentImplCopyWith<$Res> {
__$$ContinentImplCopyWithImpl(
_$ContinentImpl _value, $Res Function(_$ContinentImpl) _then)
: super(_value, _then);
/// Create a copy of Continent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? name = null,
Object? imageUrl = null,
}) {
return _then(_$ContinentImpl(
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
imageUrl: null == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ContinentImpl implements _Continent {
const _$ContinentImpl({required this.name, required this.imageUrl});
factory _$ContinentImpl.fromJson(Map<String, dynamic> json) =>
_$$ContinentImplFromJson(json);
/// e.g. 'Europe'
@override
final String name;
/// e.g. 'https://rstr.in/google/tripedia/TmR12QdlVTT'
@override
final String imageUrl;
@override
String toString() {
return 'Continent(name: $name, imageUrl: $imageUrl)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ContinentImpl &&
(identical(other.name, name) || other.name == name) &&
(identical(other.imageUrl, imageUrl) ||
other.imageUrl == imageUrl));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, name, imageUrl);
/// Create a copy of Continent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ContinentImplCopyWith<_$ContinentImpl> get copyWith =>
__$$ContinentImplCopyWithImpl<_$ContinentImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ContinentImplToJson(
this,
);
}
}
abstract class _Continent implements Continent {
const factory _Continent(
{required final String name,
required final String imageUrl}) = _$ContinentImpl;
factory _Continent.fromJson(Map<String, dynamic> json) =
_$ContinentImpl.fromJson;
/// e.g. 'Europe'
@override
String get name;
/// e.g. 'https://rstr.in/google/tripedia/TmR12QdlVTT'
@override
String get imageUrl;
/// Create a copy of Continent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ContinentImplCopyWith<_$ContinentImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'continent.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ContinentImpl _$$ContinentImplFromJson(Map<String, dynamic> json) =>
_$ContinentImpl(
name: json['name'] as String,
imageUrl: json['imageUrl'] as String,
);
Map<String, dynamic> _$$ContinentImplToJson(_$ContinentImpl instance) =>
<String, dynamic>{
'name': instance.name,
'imageUrl': instance.imageUrl,
};

View File

@@ -0,0 +1,38 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'destination.freezed.dart';
part 'destination.g.dart';
@freezed
class Destination with _$Destination {
const factory Destination({
/// e.g. 'alaska'
required String ref,
/// e.g. 'Alaska'
required String name,
/// e.g. 'United States'
required String country,
/// e.g. 'North America'
required String continent,
/// e.g. 'Alaska is a haven for outdoor enthusiasts ...'
required String knownFor,
/// e.g. ['Mountain', 'Off-the-beaten-path', 'Wildlife watching']
required List<String> tags,
/// e.g. 'https://storage.googleapis.com/tripedia-images/destinations/alaska.jpg'
required String imageUrl,
}) = _Destination;
factory Destination.fromJson(Map<String, Object?> json) =>
_$DestinationFromJson(json);
}

View File

@@ -0,0 +1,339 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'destination.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
Destination _$DestinationFromJson(Map<String, dynamic> json) {
return _Destination.fromJson(json);
}
/// @nodoc
mixin _$Destination {
/// e.g. 'alaska'
String get ref => throw _privateConstructorUsedError;
/// e.g. 'Alaska'
String get name => throw _privateConstructorUsedError;
/// e.g. 'United States'
String get country => throw _privateConstructorUsedError;
/// e.g. 'North America'
String get continent => throw _privateConstructorUsedError;
/// e.g. 'Alaska is a haven for outdoor enthusiasts ...'
String get knownFor => throw _privateConstructorUsedError;
/// e.g. ['Mountain', 'Off-the-beaten-path', 'Wildlife watching']
List<String> get tags => throw _privateConstructorUsedError;
/// e.g. 'https://storage.googleapis.com/tripedia-images/destinations/alaska.jpg'
String get imageUrl => throw _privateConstructorUsedError;
/// Serializes this Destination to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of Destination
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$DestinationCopyWith<Destination> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $DestinationCopyWith<$Res> {
factory $DestinationCopyWith(
Destination value, $Res Function(Destination) then) =
_$DestinationCopyWithImpl<$Res, Destination>;
@useResult
$Res call(
{String ref,
String name,
String country,
String continent,
String knownFor,
List<String> tags,
String imageUrl});
}
/// @nodoc
class _$DestinationCopyWithImpl<$Res, $Val extends Destination>
implements $DestinationCopyWith<$Res> {
_$DestinationCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Destination
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? ref = null,
Object? name = null,
Object? country = null,
Object? continent = null,
Object? knownFor = null,
Object? tags = null,
Object? imageUrl = null,
}) {
return _then(_value.copyWith(
ref: null == ref
? _value.ref
: ref // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
country: null == country
? _value.country
: country // ignore: cast_nullable_to_non_nullable
as String,
continent: null == continent
? _value.continent
: continent // ignore: cast_nullable_to_non_nullable
as String,
knownFor: null == knownFor
? _value.knownFor
: knownFor // ignore: cast_nullable_to_non_nullable
as String,
tags: null == tags
? _value.tags
: tags // ignore: cast_nullable_to_non_nullable
as List<String>,
imageUrl: null == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$DestinationImplCopyWith<$Res>
implements $DestinationCopyWith<$Res> {
factory _$$DestinationImplCopyWith(
_$DestinationImpl value, $Res Function(_$DestinationImpl) then) =
__$$DestinationImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String ref,
String name,
String country,
String continent,
String knownFor,
List<String> tags,
String imageUrl});
}
/// @nodoc
class __$$DestinationImplCopyWithImpl<$Res>
extends _$DestinationCopyWithImpl<$Res, _$DestinationImpl>
implements _$$DestinationImplCopyWith<$Res> {
__$$DestinationImplCopyWithImpl(
_$DestinationImpl _value, $Res Function(_$DestinationImpl) _then)
: super(_value, _then);
/// Create a copy of Destination
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? ref = null,
Object? name = null,
Object? country = null,
Object? continent = null,
Object? knownFor = null,
Object? tags = null,
Object? imageUrl = null,
}) {
return _then(_$DestinationImpl(
ref: null == ref
? _value.ref
: ref // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
country: null == country
? _value.country
: country // ignore: cast_nullable_to_non_nullable
as String,
continent: null == continent
? _value.continent
: continent // ignore: cast_nullable_to_non_nullable
as String,
knownFor: null == knownFor
? _value.knownFor
: knownFor // ignore: cast_nullable_to_non_nullable
as String,
tags: null == tags
? _value._tags
: tags // ignore: cast_nullable_to_non_nullable
as List<String>,
imageUrl: null == imageUrl
? _value.imageUrl
: imageUrl // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$DestinationImpl implements _Destination {
const _$DestinationImpl(
{required this.ref,
required this.name,
required this.country,
required this.continent,
required this.knownFor,
required final List<String> tags,
required this.imageUrl})
: _tags = tags;
factory _$DestinationImpl.fromJson(Map<String, dynamic> json) =>
_$$DestinationImplFromJson(json);
/// e.g. 'alaska'
@override
final String ref;
/// e.g. 'Alaska'
@override
final String name;
/// e.g. 'United States'
@override
final String country;
/// e.g. 'North America'
@override
final String continent;
/// e.g. 'Alaska is a haven for outdoor enthusiasts ...'
@override
final String knownFor;
/// e.g. ['Mountain', 'Off-the-beaten-path', 'Wildlife watching']
final List<String> _tags;
/// e.g. ['Mountain', 'Off-the-beaten-path', 'Wildlife watching']
@override
List<String> get tags {
if (_tags is EqualUnmodifiableListView) return _tags;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_tags);
}
/// e.g. 'https://storage.googleapis.com/tripedia-images/destinations/alaska.jpg'
@override
final String imageUrl;
@override
String toString() {
return 'Destination(ref: $ref, name: $name, country: $country, continent: $continent, knownFor: $knownFor, tags: $tags, imageUrl: $imageUrl)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$DestinationImpl &&
(identical(other.ref, ref) || other.ref == ref) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.country, country) || other.country == country) &&
(identical(other.continent, continent) ||
other.continent == continent) &&
(identical(other.knownFor, knownFor) ||
other.knownFor == knownFor) &&
const DeepCollectionEquality().equals(other._tags, _tags) &&
(identical(other.imageUrl, imageUrl) ||
other.imageUrl == imageUrl));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, ref, name, country, continent,
knownFor, const DeepCollectionEquality().hash(_tags), imageUrl);
/// Create a copy of Destination
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$DestinationImplCopyWith<_$DestinationImpl> get copyWith =>
__$$DestinationImplCopyWithImpl<_$DestinationImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$DestinationImplToJson(
this,
);
}
}
abstract class _Destination implements Destination {
const factory _Destination(
{required final String ref,
required final String name,
required final String country,
required final String continent,
required final String knownFor,
required final List<String> tags,
required final String imageUrl}) = _$DestinationImpl;
factory _Destination.fromJson(Map<String, dynamic> json) =
_$DestinationImpl.fromJson;
/// e.g. 'alaska'
@override
String get ref;
/// e.g. 'Alaska'
@override
String get name;
/// e.g. 'United States'
@override
String get country;
/// e.g. 'North America'
@override
String get continent;
/// e.g. 'Alaska is a haven for outdoor enthusiasts ...'
@override
String get knownFor;
/// e.g. ['Mountain', 'Off-the-beaten-path', 'Wildlife watching']
@override
List<String> get tags;
/// e.g. 'https://storage.googleapis.com/tripedia-images/destinations/alaska.jpg'
@override
String get imageUrl;
/// Create a copy of Destination
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$DestinationImplCopyWith<_$DestinationImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,29 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'destination.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$DestinationImpl _$$DestinationImplFromJson(Map<String, dynamic> json) =>
_$DestinationImpl(
ref: json['ref'] as String,
name: json['name'] as String,
country: json['country'] as String,
continent: json['continent'] as String,
knownFor: json['knownFor'] as String,
tags: (json['tags'] as List<dynamic>).map((e) => e as String).toList(),
imageUrl: json['imageUrl'] as String,
);
Map<String, dynamic> _$$DestinationImplToJson(_$DestinationImpl instance) =>
<String, dynamic>{
'ref': instance.ref,
'name': instance.name,
'country': instance.country,
'continent': instance.continent,
'knownFor': instance.knownFor,
'tags': instance.tags,
'imageUrl': instance.imageUrl,
};

View File

@@ -0,0 +1,24 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'login_request.freezed.dart';
part 'login_request.g.dart';
/// Simple data class to hold login request data.
@freezed
class LoginRequest with _$LoginRequest {
const factory LoginRequest({
/// Email address.
required String email,
/// Plain text password.
required String password,
}) = _LoginRequest;
factory LoginRequest.fromJson(Map<String, Object?> json) =>
_$LoginRequestFromJson(json);
}

View File

@@ -0,0 +1,192 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'login_request.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
LoginRequest _$LoginRequestFromJson(Map<String, dynamic> json) {
return _LoginRequest.fromJson(json);
}
/// @nodoc
mixin _$LoginRequest {
/// Email address.
String get email => throw _privateConstructorUsedError;
/// Plain text password.
String get password => throw _privateConstructorUsedError;
/// Serializes this LoginRequest to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of LoginRequest
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$LoginRequestCopyWith<LoginRequest> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $LoginRequestCopyWith<$Res> {
factory $LoginRequestCopyWith(
LoginRequest value, $Res Function(LoginRequest) then) =
_$LoginRequestCopyWithImpl<$Res, LoginRequest>;
@useResult
$Res call({String email, String password});
}
/// @nodoc
class _$LoginRequestCopyWithImpl<$Res, $Val extends LoginRequest>
implements $LoginRequestCopyWith<$Res> {
_$LoginRequestCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of LoginRequest
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? email = null,
Object? password = null,
}) {
return _then(_value.copyWith(
email: null == email
? _value.email
: email // ignore: cast_nullable_to_non_nullable
as String,
password: null == password
? _value.password
: password // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$LoginRequestImplCopyWith<$Res>
implements $LoginRequestCopyWith<$Res> {
factory _$$LoginRequestImplCopyWith(
_$LoginRequestImpl value, $Res Function(_$LoginRequestImpl) then) =
__$$LoginRequestImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String email, String password});
}
/// @nodoc
class __$$LoginRequestImplCopyWithImpl<$Res>
extends _$LoginRequestCopyWithImpl<$Res, _$LoginRequestImpl>
implements _$$LoginRequestImplCopyWith<$Res> {
__$$LoginRequestImplCopyWithImpl(
_$LoginRequestImpl _value, $Res Function(_$LoginRequestImpl) _then)
: super(_value, _then);
/// Create a copy of LoginRequest
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? email = null,
Object? password = null,
}) {
return _then(_$LoginRequestImpl(
email: null == email
? _value.email
: email // ignore: cast_nullable_to_non_nullable
as String,
password: null == password
? _value.password
: password // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$LoginRequestImpl implements _LoginRequest {
const _$LoginRequestImpl({required this.email, required this.password});
factory _$LoginRequestImpl.fromJson(Map<String, dynamic> json) =>
_$$LoginRequestImplFromJson(json);
/// Email address.
@override
final String email;
/// Plain text password.
@override
final String password;
@override
String toString() {
return 'LoginRequest(email: $email, password: $password)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LoginRequestImpl &&
(identical(other.email, email) || other.email == email) &&
(identical(other.password, password) ||
other.password == password));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, email, password);
/// Create a copy of LoginRequest
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LoginRequestImplCopyWith<_$LoginRequestImpl> get copyWith =>
__$$LoginRequestImplCopyWithImpl<_$LoginRequestImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$LoginRequestImplToJson(
this,
);
}
}
abstract class _LoginRequest implements LoginRequest {
const factory _LoginRequest(
{required final String email,
required final String password}) = _$LoginRequestImpl;
factory _LoginRequest.fromJson(Map<String, dynamic> json) =
_$LoginRequestImpl.fromJson;
/// Email address.
@override
String get email;
/// Plain text password.
@override
String get password;
/// Create a copy of LoginRequest
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LoginRequestImplCopyWith<_$LoginRequestImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'login_request.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$LoginRequestImpl _$$LoginRequestImplFromJson(Map<String, dynamic> json) =>
_$LoginRequestImpl(
email: json['email'] as String,
password: json['password'] as String,
);
Map<String, dynamic> _$$LoginRequestImplToJson(_$LoginRequestImpl instance) =>
<String, dynamic>{
'email': instance.email,
'password': instance.password,
};

View File

@@ -0,0 +1,24 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'login_response.freezed.dart';
part 'login_response.g.dart';
/// LoginResponse model.
@freezed
class LoginResponse with _$LoginResponse {
const factory LoginResponse({
/// The token to be used for authentication.
required String token,
/// The user id.
required String userId,
}) = _LoginResponse;
factory LoginResponse.fromJson(Map<String, Object?> json) =>
_$LoginResponseFromJson(json);
}

View File

@@ -0,0 +1,191 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'login_response.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
LoginResponse _$LoginResponseFromJson(Map<String, dynamic> json) {
return _LoginResponse.fromJson(json);
}
/// @nodoc
mixin _$LoginResponse {
/// The token to be used for authentication.
String get token => throw _privateConstructorUsedError;
/// The user id.
String get userId => throw _privateConstructorUsedError;
/// Serializes this LoginResponse to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of LoginResponse
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$LoginResponseCopyWith<LoginResponse> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $LoginResponseCopyWith<$Res> {
factory $LoginResponseCopyWith(
LoginResponse value, $Res Function(LoginResponse) then) =
_$LoginResponseCopyWithImpl<$Res, LoginResponse>;
@useResult
$Res call({String token, String userId});
}
/// @nodoc
class _$LoginResponseCopyWithImpl<$Res, $Val extends LoginResponse>
implements $LoginResponseCopyWith<$Res> {
_$LoginResponseCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of LoginResponse
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? token = null,
Object? userId = null,
}) {
return _then(_value.copyWith(
token: null == token
? _value.token
: token // ignore: cast_nullable_to_non_nullable
as String,
userId: null == userId
? _value.userId
: userId // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$LoginResponseImplCopyWith<$Res>
implements $LoginResponseCopyWith<$Res> {
factory _$$LoginResponseImplCopyWith(
_$LoginResponseImpl value, $Res Function(_$LoginResponseImpl) then) =
__$$LoginResponseImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String token, String userId});
}
/// @nodoc
class __$$LoginResponseImplCopyWithImpl<$Res>
extends _$LoginResponseCopyWithImpl<$Res, _$LoginResponseImpl>
implements _$$LoginResponseImplCopyWith<$Res> {
__$$LoginResponseImplCopyWithImpl(
_$LoginResponseImpl _value, $Res Function(_$LoginResponseImpl) _then)
: super(_value, _then);
/// Create a copy of LoginResponse
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? token = null,
Object? userId = null,
}) {
return _then(_$LoginResponseImpl(
token: null == token
? _value.token
: token // ignore: cast_nullable_to_non_nullable
as String,
userId: null == userId
? _value.userId
: userId // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$LoginResponseImpl implements _LoginResponse {
const _$LoginResponseImpl({required this.token, required this.userId});
factory _$LoginResponseImpl.fromJson(Map<String, dynamic> json) =>
_$$LoginResponseImplFromJson(json);
/// The token to be used for authentication.
@override
final String token;
/// The user id.
@override
final String userId;
@override
String toString() {
return 'LoginResponse(token: $token, userId: $userId)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$LoginResponseImpl &&
(identical(other.token, token) || other.token == token) &&
(identical(other.userId, userId) || other.userId == userId));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, token, userId);
/// Create a copy of LoginResponse
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$LoginResponseImplCopyWith<_$LoginResponseImpl> get copyWith =>
__$$LoginResponseImplCopyWithImpl<_$LoginResponseImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$LoginResponseImplToJson(
this,
);
}
}
abstract class _LoginResponse implements LoginResponse {
const factory _LoginResponse(
{required final String token,
required final String userId}) = _$LoginResponseImpl;
factory _LoginResponse.fromJson(Map<String, dynamic> json) =
_$LoginResponseImpl.fromJson;
/// The token to be used for authentication.
@override
String get token;
/// The user id.
@override
String get userId;
/// Create a copy of LoginResponse
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$LoginResponseImplCopyWith<_$LoginResponseImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'login_response.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$LoginResponseImpl _$$LoginResponseImplFromJson(Map<String, dynamic> json) =>
_$LoginResponseImpl(
token: json['token'] as String,
userId: json['userId'] as String,
);
Map<String, dynamic> _$$LoginResponseImplToJson(_$LoginResponseImpl instance) =>
<String, dynamic>{
'token': instance.token,
'userId': instance.userId,
};

View File

@@ -0,0 +1,27 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
part 'user.g.dart';
@freezed
abstract class User with _$User {
const factory User({
/// The user's ID.
required String id,
/// The user's name.
required String name,
/// The user's email.
required String email,
/// The user's picture URL.
required String picture,
}) = _User;
factory User.fromJson(Map<String, Object?> json) => _$UserFromJson(json);
}

View File

@@ -0,0 +1,236 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'user.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
User _$UserFromJson(Map<String, dynamic> json) {
return _User.fromJson(json);
}
/// @nodoc
mixin _$User {
/// The user's ID.
String get id => throw _privateConstructorUsedError;
/// The user's name.
String get name => throw _privateConstructorUsedError;
/// The user's email.
String get email => throw _privateConstructorUsedError;
/// The user's picture URL.
String get picture => throw _privateConstructorUsedError;
/// Serializes this User to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of User
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$UserCopyWith<User> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $UserCopyWith<$Res> {
factory $UserCopyWith(User value, $Res Function(User) then) =
_$UserCopyWithImpl<$Res, User>;
@useResult
$Res call({String id, String name, String email, String picture});
}
/// @nodoc
class _$UserCopyWithImpl<$Res, $Val extends User>
implements $UserCopyWith<$Res> {
_$UserCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of User
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? name = null,
Object? email = null,
Object? picture = null,
}) {
return _then(_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
email: null == email
? _value.email
: email // ignore: cast_nullable_to_non_nullable
as String,
picture: null == picture
? _value.picture
: picture // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> {
factory _$$UserImplCopyWith(
_$UserImpl value, $Res Function(_$UserImpl) then) =
__$$UserImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String id, String name, String email, String picture});
}
/// @nodoc
class __$$UserImplCopyWithImpl<$Res>
extends _$UserCopyWithImpl<$Res, _$UserImpl>
implements _$$UserImplCopyWith<$Res> {
__$$UserImplCopyWithImpl(_$UserImpl _value, $Res Function(_$UserImpl) _then)
: super(_value, _then);
/// Create a copy of User
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? name = null,
Object? email = null,
Object? picture = null,
}) {
return _then(_$UserImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
email: null == email
? _value.email
: email // ignore: cast_nullable_to_non_nullable
as String,
picture: null == picture
? _value.picture
: picture // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$UserImpl implements _User {
const _$UserImpl(
{required this.id,
required this.name,
required this.email,
required this.picture});
factory _$UserImpl.fromJson(Map<String, dynamic> json) =>
_$$UserImplFromJson(json);
/// The user's ID.
@override
final String id;
/// The user's name.
@override
final String name;
/// The user's email.
@override
final String email;
/// The user's picture URL.
@override
final String picture;
@override
String toString() {
return 'User(id: $id, name: $name, email: $email, picture: $picture)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$UserImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.email, email) || other.email == email) &&
(identical(other.picture, picture) || other.picture == picture));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, id, name, email, picture);
/// Create a copy of User
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
__$$UserImplCopyWithImpl<_$UserImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$UserImplToJson(
this,
);
}
}
abstract class _User implements User {
const factory _User(
{required final String id,
required final String name,
required final String email,
required final String picture}) = _$UserImpl;
factory _User.fromJson(Map<String, dynamic> json) = _$UserImpl.fromJson;
/// The user's ID.
@override
String get id;
/// The user's name.
@override
String get name;
/// The user's email.
@override
String get email;
/// The user's picture URL.
@override
String get picture;
/// Create a copy of User
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,22 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$UserImpl _$$UserImplFromJson(Map<String, dynamic> json) => _$UserImpl(
id: json['id'] as String,
name: json['name'] as String,
email: json['email'] as String,
picture: json['picture'] as String,
);
Map<String, dynamic> _$$UserImplToJson(_$UserImpl instance) =>
<String, dynamic>{
'id': instance.id,
'name': instance.name,
'email': instance.email,
'picture': instance.picture,
};

View File

@@ -0,0 +1,116 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import '../config/assets.dart';
import '../model/booking/booking.dart';
/// Allows the user to save and restore bookings.
///
/// Bookings are stored in memory for demo purposes,
/// so they are lost when the server stops.
///
/// For demo purposes, this API includes a default pre-generated booking.
///
/// The [Booking.id] is also the index in the bookings list.
class BookingApi {
BookingApi() {
// Create a default booking
var destination = Assets.destinations.first;
final activitiesRef = Assets.activities
.where((activity) => activity.destinationRef == destination.ref)
.map((activity) => activity.ref)
.toList();
_bookings.add(
Booking(
id: _sequentialId++,
name: '${destination.name}, ${destination.continent}',
startDate: DateTime(2024, 7, 20),
endDate: DateTime(2024, 8, 15),
destinationRef: destination.ref,
activitiesRef: activitiesRef,
),
);
}
// Bookings are kept in memory for demo purposes.
// To keep things simple, the id is also the index in the list.
final List<Booking> _bookings = List.empty(growable: true);
// Used to generate IDs for bookings
int _sequentialId = 0;
Router get router {
final router = Router();
// Get User bookings
router.get('/', (Request request) {
return Response.ok(
json.encode(_bookings),
headers: {'Content-Type': 'application/json'},
);
});
// Get a booking by id
router.get('/<id>', (Request request, String id) {
final bookingId = int.parse(id);
final booking =
_bookings.firstWhereOrNull((booking) => booking.id == bookingId);
if (booking == null) {
return Response.notFound('Invalid id');
}
return Response.ok(
json.encode(booking),
headers: {'Content-Type': 'application/json'},
);
});
// Save a new booking
router.post('/', (Request request) async {
final body = await request.readAsString();
final booking = Booking.fromJson(json.decode(body));
if (booking.id != null) {
// POST endpoint only allows newly created bookings
return Response.badRequest(
body: 'Booking already has id, use PUT instead.');
}
// Add ID to new booking
final bookingWithId = booking.copyWith(id: _sequentialId++);
// Store booking
_bookings.add(bookingWithId);
// Respond with newly created booking
return Response(
201, // created
body: json.encode(bookingWithId),
headers: {'Content-Type': 'application/json'},
);
});
// Delete booking
router.delete('/<id>', (Request request, String id) async {
final bookingId = int.parse(id);
final booking =
_bookings.firstWhereOrNull((booking) => booking.id == bookingId);
if (booking == null) {
return Response.notFound('Invalid id');
}
_bookings.remove(booking);
// 240: no content
return Response(204);
});
return router;
}
}

View File

@@ -0,0 +1,44 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:shelf/shelf.dart';
import '../model/continent/continent.dart';
final _continents = [
Continent(
name: 'Europe',
imageUrl: 'https://rstr.in/google/tripedia/TmR12QdlVTT',
),
Continent(
name: 'Asia',
imageUrl: 'https://rstr.in/google/tripedia/VJ8BXlQg8O1',
),
Continent(
name: 'South America',
imageUrl: 'https://rstr.in/google/tripedia/flm_-o1aI8e',
),
Continent(
name: 'Africa',
imageUrl: 'https://rstr.in/google/tripedia/-nzi8yFOBpF',
),
Continent(
name: 'North America',
imageUrl: 'https://rstr.in/google/tripedia/jlbgFDrSUVE',
),
Continent(
name: 'Oceania',
imageUrl: 'https://rstr.in/google/tripedia/vxyrDE-fZVL',
),
Continent(
name: 'Australia',
imageUrl: 'https://rstr.in/google/tripedia/z6vy6HeRyvZ',
),
];
Response continentHandler(Request req) {
return Response.ok(jsonEncode(_continents));
}

View File

@@ -0,0 +1,35 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import '../config/assets.dart';
class DestinationApi {
Router get router {
final router = Router();
router.get('/', (Request request) {
return Response.ok(
json.encode(Assets.destinations),
headers: {'Content-Type': 'application/json'},
);
});
router.get('/<id>/activity', (Request request, String id) {
final list = Assets.activities
.where((activity) => activity.destinationRef == id)
.toList();
return Response.ok(
json.encode(list),
headers: {'Content-Type': 'application/json'},
);
});
return router;
}
}

View File

@@ -0,0 +1,50 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:compass_server/config/constants.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import '../model/login_request/login_request.dart';
import '../model/login_response/login_response.dart';
/// Implements a simple login API.
///
/// This is provided as an example for Flutter architectural purposes only
/// and shouldn't be used as example on how to implement authentication
/// in production.
///
/// This API only accepts a fixed email and password for demonstration purposes,
/// then returns a hardcoded token and a user id.
///
/// This token does not expire and is not secure.
class LoginApi {
Router get router {
final router = Router();
router.post('/', (Request request) async {
final body = await request.readAsString();
final loginRequest = LoginRequest.fromJson(json.decode(body));
if (loginRequest.email == Constants.email &&
loginRequest.password == Constants.password) {
return Response.ok(
json.encode(
LoginResponse(
token: Constants.token,
userId: Constants.userId,
),
),
headers: {'Content-Type': 'application/json'},
);
}
return Response.unauthorized('Invalid credentials');
});
return router;
}
}

View File

@@ -0,0 +1,27 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'package:compass_server/config/constants.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
/// Implements a simple user API.
///
/// This API only returns a hardcoded user for demonstration purposes.
class UserApi {
Router get router {
final router = Router();
router.get('/', (Request request) async {
return Response.ok(
json.encode(Constants.user),
headers: {'Content-Type': 'application/json'},
);
});
return router;
}
}

View File

@@ -0,0 +1,23 @@
name: compass_server
description: A server app using the shelf package and Docker.
publish_to: 'none'
version: 1.0.0
environment:
sdk: ^3.4.3
dependencies:
args: ^2.4.0
shelf: ^1.4.0
shelf_router: ^1.1.0
freezed_annotation: ^2.4.4
json_annotation: ^4.9.0
collection: ^1.19.0
dev_dependencies:
http: ^1.1.0
lints: ^3.0.0
test: ^1.24.0
build_runner: ^2.4.11
freezed: ^2.5.7
json_serializable: ^6.8.0

View File

@@ -0,0 +1,230 @@
// Copyright 2024 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'dart:io';
import 'package:compass_server/config/constants.dart';
import 'package:compass_server/model/activity/activity.dart';
import 'package:compass_server/model/booking/booking.dart';
import 'package:compass_server/model/continent/continent.dart';
import 'package:compass_server/model/destination/destination.dart';
import 'package:compass_server/model/login_request/login_request.dart';
import 'package:compass_server/model/login_response/login_response.dart';
import 'package:compass_server/model/user/user.dart';
import 'package:http/http.dart';
import 'package:test/test.dart';
void main() {
final port = '8080';
final host = 'http://127.0.0.1:$port';
late Process p;
var headers = {
'Authorization': 'Bearer ${Constants.token}',
};
setUp(() async {
p = await Process.start(
'dart',
['run', 'bin/compass_server.dart'],
environment: {'PORT': port},
);
// Wait for server to start and print to stdout.
await p.stdout.first;
});
tearDown(() => p.kill());
test('Get Continent end-point', () async {
// Query /continent end-point
final response = await get(
Uri.parse('$host/continent'),
headers: headers,
);
expect(response.statusCode, 200);
// Parse json response list
final list = jsonDecode(response.body) as List<dynamic>;
// Parse items
final continents = list.map((element) => Continent.fromJson(element));
expect(continents.length, 7);
expect(continents.first.name, 'Europe');
});
test('Get Destination end-point', () async {
// Query /destination end-point
final response = await get(
Uri.parse('$host/destination'),
headers: headers,
);
expect(response.statusCode, 200);
// Parse json response list
final list = jsonDecode(response.body) as List<dynamic>;
// Parse items
final destination = list.map((element) => Destination.fromJson(element));
expect(destination.length, 137);
expect(destination.first.name, 'Alaska');
});
test('Get Activities end-point', () async {
// Query /destination/alaska/activity end-point
final response = await get(
Uri.parse('$host/destination/alaska/activity'),
headers: headers,
);
expect(response.statusCode, 200);
// Parse json response list
final list = jsonDecode(response.body) as List<dynamic>;
// Parse items
final activity = list.map((element) => Activity.fromJson(element));
expect(activity.length, 20);
expect(activity.first.name, 'Glacier Trekking and Ice Climbing');
});
test('Get bookings end-point', () async {
final response = await get(
Uri.parse('$host/booking'),
headers: headers,
);
expect(response.statusCode, 200);
// Parse json response list
final list = jsonDecode(response.body) as List<dynamic>;
// Parse items
final bookings = list.map((element) => Booking.fromJson(element));
expect(bookings.length, 1);
expect(bookings.first.id, 0);
});
test('Get booking with id 0', () async {
final response = await get(
Uri.parse('$host/booking/0'),
headers: headers,
);
expect(response.statusCode, 200);
final booking = Booking.fromJson(jsonDecode(response.body));
// Got booking with id 0
expect(booking.id, 0);
});
test('Store a booking', () async {
final response = await post(
Uri.parse('$host/booking'),
headers: headers,
body: jsonEncode(
Booking(
name: "DESTINATION, CONTINENT",
startDate: DateTime(2024, 1, 1),
endDate: DateTime(2024, 2, 2),
destinationRef: 'REF',
activitiesRef: ['ACT1', 'ACT2'],
),
),
);
expect(response.statusCode, 201);
final booking = Booking.fromJson(jsonDecode(response.body));
// New ID should be 1
expect(booking.id, 1);
});
test('Delete a booking', () async {
// First create a booking
final response = await post(
Uri.parse('$host/booking'),
headers: headers,
body: jsonEncode(
Booking(
name: "DESTINATION, CONTINENT",
startDate: DateTime(2024, 1, 1),
endDate: DateTime(2024, 2, 2),
destinationRef: 'REF',
activitiesRef: ['ACT1', 'ACT2'],
),
),
);
expect(response.statusCode, 201);
final booking = Booking.fromJson(jsonDecode(response.body));
// Then delete it
final deleteResponse = await delete(
Uri.parse('$host/booking/${booking.id}'),
headers: headers,
);
expect(deleteResponse.statusCode, 204);
});
test('Delete a booking is not found', () async {
final response = await delete(
Uri.parse('$host/booking/42'),
headers: headers,
);
expect(response.statusCode, 404);
});
test('Get user', () async {
final response = await get(
Uri.parse('$host/user'),
headers: headers,
);
expect(response.statusCode, 200);
final user = User.fromJson(jsonDecode(response.body));
// Should get the hardcoded user
expect(user, Constants.user);
});
test('404', () async {
final response = await get(
Uri.parse('$host/foobar'),
headers: headers,
);
expect(response.statusCode, 404);
});
test('Login with valid credentials', () async {
final response = await post(
Uri.parse('$host/login'),
body: jsonEncode(
LoginRequest(
email: Constants.email,
password: Constants.password,
),
),
);
expect(response.statusCode, 200);
final loginResponse = LoginResponse.fromJson(jsonDecode(response.body));
expect(loginResponse.token, Constants.token);
expect(loginResponse.userId, Constants.userId);
});
test('Login with wrong credentials', () async {
final response = await post(
Uri.parse('$host/login'),
body: jsonEncode(
LoginRequest(
email: 'INVALID',
password: 'INVALID',
),
),
);
expect(response.statusCode, 401);
});
test('Unauthorized request', () async {
// Query /continent end-point
// No auth headers
final response = await get(
Uri.parse('$host/continent'),
);
expect(response.statusCode, 401);
});
}