mirror of
https://github.com/flutter/samples.git
synced 2025-11-10 14:58:34 +00:00
Compass app (#2446)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
// 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 '../../../domain/models/activity/activity.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
/// Data source for activities.
|
||||
abstract class ActivityRepository {
|
||||
/// Get activities by [Destination] ref.
|
||||
Future<Result<List<Activity>>> getByDestination(String ref);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// 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 '../../../domain/models/activity/activity.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/local/local_data_service.dart';
|
||||
import 'activity_repository.dart';
|
||||
|
||||
/// Local implementation of ActivityRepository
|
||||
/// Uses data from assets folder
|
||||
class ActivityRepositoryLocal implements ActivityRepository {
|
||||
ActivityRepositoryLocal({
|
||||
required LocalDataService localDataService,
|
||||
}) : _localDataService = localDataService;
|
||||
|
||||
final LocalDataService _localDataService;
|
||||
|
||||
@override
|
||||
Future<Result<List<Activity>>> getByDestination(String ref) async {
|
||||
try {
|
||||
final activities = (await _localDataService.getActivities())
|
||||
.where((activity) => activity.destinationRef == ref)
|
||||
.toList();
|
||||
|
||||
return Result.ok(activities);
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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 '../../../domain/models/activity/activity.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/api/api_client.dart';
|
||||
import 'activity_repository.dart';
|
||||
|
||||
/// Remote data source for [Activity].
|
||||
/// Implements basic local caching.
|
||||
/// See: https://docs.flutter.dev/get-started/fwe/local-caching
|
||||
class ActivityRepositoryRemote implements ActivityRepository {
|
||||
ActivityRepositoryRemote({
|
||||
required ApiClient apiClient,
|
||||
}) : _apiClient = apiClient;
|
||||
|
||||
final ApiClient _apiClient;
|
||||
|
||||
final Map<String, List<Activity>> _cachedData = {};
|
||||
|
||||
@override
|
||||
Future<Result<List<Activity>>> getByDestination(String ref) async {
|
||||
if (!_cachedData.containsKey(ref)) {
|
||||
// No cached data, request activities
|
||||
final result = await _apiClient.getActivityByDestination(ref);
|
||||
if (result is Ok) {
|
||||
_cachedData[ref] = result.asOk.value;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// Return cached data if available
|
||||
return Result.ok(_cachedData[ref]!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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:flutter/foundation.dart';
|
||||
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
abstract class AuthRepository extends ChangeNotifier {
|
||||
/// Returns true when the user is logged in
|
||||
/// Returns [Future] because it will load a stored auth state the first time.
|
||||
Future<bool> get isAuthenticated;
|
||||
|
||||
/// Perform login
|
||||
Future<Result<void>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
});
|
||||
|
||||
/// Perform logout
|
||||
Future<Result<void>> logout();
|
||||
}
|
||||
@@ -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 '../../../utils/result.dart';
|
||||
import 'auth_repository.dart';
|
||||
|
||||
class AuthRepositoryDev extends AuthRepository {
|
||||
/// User is always authenticated in dev scenarios
|
||||
@override
|
||||
Future<bool> get isAuthenticated => Future.value(true);
|
||||
|
||||
/// Login is always successful in dev scenarios
|
||||
@override
|
||||
Future<Result<void>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
}) async {
|
||||
return Result.ok(null);
|
||||
}
|
||||
|
||||
/// Logout is always successful in dev scenarios
|
||||
@override
|
||||
Future<Result<void>> logout() async {
|
||||
return Result.ok(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// 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:logging/logging.dart';
|
||||
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/api/api_client.dart';
|
||||
import '../../services/api/auth_api_client.dart';
|
||||
import '../../services/api/model/login_request/login_request.dart';
|
||||
import '../../services/api/model/login_response/login_response.dart';
|
||||
import '../../services/shared_preferences_service.dart';
|
||||
import 'auth_repository.dart';
|
||||
|
||||
class AuthRepositoryRemote extends AuthRepository {
|
||||
AuthRepositoryRemote({
|
||||
required ApiClient apiClient,
|
||||
required AuthApiClient authApiClient,
|
||||
required SharedPreferencesService sharedPreferencesService,
|
||||
}) : _apiClient = apiClient,
|
||||
_authApiClient = authApiClient,
|
||||
_sharedPreferencesService = sharedPreferencesService {
|
||||
_apiClient.authHeaderProvider = _authHeaderProvider;
|
||||
}
|
||||
|
||||
final AuthApiClient _authApiClient;
|
||||
final ApiClient _apiClient;
|
||||
final SharedPreferencesService _sharedPreferencesService;
|
||||
|
||||
bool? _isAuthenticated;
|
||||
String? _authToken;
|
||||
final _log = Logger('AuthRepositoryRemote');
|
||||
|
||||
/// Fetch token from shared preferences
|
||||
Future<void> _fetch() async {
|
||||
final result = await _sharedPreferencesService.fetchToken();
|
||||
switch (result) {
|
||||
case Ok<String?>():
|
||||
_authToken = result.value;
|
||||
_isAuthenticated = result.value != null;
|
||||
case Error<String?>():
|
||||
_log.severe(
|
||||
'Failed to fech Token from SharedPreferences',
|
||||
result.error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> get isAuthenticated async {
|
||||
// Status is cached
|
||||
if (_isAuthenticated != null) {
|
||||
return _isAuthenticated!;
|
||||
}
|
||||
// No status cached, fetch from storage
|
||||
await _fetch();
|
||||
return _isAuthenticated ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> login({
|
||||
required String email,
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _authApiClient.login(
|
||||
LoginRequest(
|
||||
email: email,
|
||||
password: password,
|
||||
),
|
||||
);
|
||||
switch (result) {
|
||||
case Ok<LoginResponse>():
|
||||
_log.info('User logged int');
|
||||
// Set auth status
|
||||
_isAuthenticated = true;
|
||||
_authToken = result.value.token;
|
||||
// Store in Shared preferences
|
||||
return await _sharedPreferencesService.saveToken(result.value.token);
|
||||
case Error<LoginResponse>():
|
||||
_log.warning('Error logging in: ${result.error}');
|
||||
return Result.error(result.error);
|
||||
}
|
||||
} finally {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> logout() async {
|
||||
_log.info('User logged out');
|
||||
try {
|
||||
// Clear stored auth token
|
||||
final result = await _sharedPreferencesService.saveToken(null);
|
||||
if (result is Error<void>) {
|
||||
_log.severe('Failed to clear stored auth token');
|
||||
}
|
||||
|
||||
// Clear token in ApiClient
|
||||
_authToken = null;
|
||||
|
||||
// Clear authenticated status
|
||||
_isAuthenticated = false;
|
||||
return result;
|
||||
} finally {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
String? _authHeaderProvider() =>
|
||||
_authToken != null ? 'Bearer $_authToken' : null;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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 '../../../domain/models/booking/booking.dart';
|
||||
import '../../../domain/models/booking/booking_summary.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
abstract class BookingRepository {
|
||||
/// Returns the list of [BookingSummary] for the current user.
|
||||
Future<Result<List<BookingSummary>>> getBookingsList();
|
||||
|
||||
/// Returns a full [Booking] given the id.
|
||||
Future<Result<Booking>> getBooking(int id);
|
||||
|
||||
/// Creates a new [Booking].
|
||||
Future<Result<void>> createBooking(Booking booking);
|
||||
|
||||
/// Delete booking
|
||||
Future<Result<void>> delete(int id);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// 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:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import '../../../domain/models/booking/booking.dart';
|
||||
import '../../../domain/models/booking/booking_summary.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
import '../../services/local/local_data_service.dart';
|
||||
import 'booking_repository.dart';
|
||||
|
||||
class BookingRepositoryLocal implements BookingRepository {
|
||||
BookingRepositoryLocal({
|
||||
required LocalDataService localDataService,
|
||||
}) : _localDataService = localDataService;
|
||||
|
||||
// Only create default booking once
|
||||
bool _isInitialized = false;
|
||||
// Used to generate IDs for bookings
|
||||
int _sequentialId = 0;
|
||||
|
||||
final _bookings = List<Booking>.empty(growable: true);
|
||||
final LocalDataService _localDataService;
|
||||
|
||||
@override
|
||||
Future<Result<void>> createBooking(Booking booking) async {
|
||||
// Bookings created come without id, we need to assign one
|
||||
final bookingWithId = booking.copyWith(id: _sequentialId++);
|
||||
_bookings.add(bookingWithId);
|
||||
return Result.ok(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<Booking>> getBooking(int id) async {
|
||||
final booking = _bookings.firstWhereOrNull((booking) => booking.id == id);
|
||||
if (booking == null) {
|
||||
return Result.error(Exception('Booking not found'));
|
||||
}
|
||||
return Result.ok(booking);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<List<BookingSummary>>> getBookingsList() async {
|
||||
// Initialize the repository with a default booking
|
||||
if (!_isInitialized) {
|
||||
await _createDefaultBooking();
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
return Result.ok(_createSummaries());
|
||||
}
|
||||
|
||||
List<BookingSummary> _createSummaries() {
|
||||
return _bookings
|
||||
.map(
|
||||
(booking) => BookingSummary(
|
||||
id: booking.id!,
|
||||
name:
|
||||
'${booking.destination.name}, ${booking.destination.continent}',
|
||||
startDate: booking.startDate,
|
||||
endDate: booking.endDate,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<void> _createDefaultBooking() async {
|
||||
// create a default booking the first time
|
||||
if (_bookings.isEmpty) {
|
||||
final destination = (await _localDataService.getDestinations()).first;
|
||||
final activities = (await _localDataService.getActivities())
|
||||
.where((activity) => activity.destinationRef == destination.ref)
|
||||
.take(4)
|
||||
.toList();
|
||||
|
||||
_bookings.add(
|
||||
Booking(
|
||||
id: _sequentialId++,
|
||||
startDate: DateTime(2024, 1, 1),
|
||||
endDate: DateTime(2024, 2, 1),
|
||||
destination: destination,
|
||||
activity: activities,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> delete(int id) async {
|
||||
_bookings.removeWhere((booking) => booking.id == id);
|
||||
return Result.ok(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// 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 '../../../domain/models/activity/activity.dart';
|
||||
import '../../../domain/models/booking/booking.dart';
|
||||
import '../../../domain/models/booking/booking_summary.dart';
|
||||
import '../../../domain/models/destination/destination.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/api/api_client.dart';
|
||||
import '../../services/api/model/booking/booking_api_model.dart';
|
||||
import 'booking_repository.dart';
|
||||
|
||||
class BookingRepositoryRemote implements BookingRepository {
|
||||
BookingRepositoryRemote({
|
||||
required ApiClient apiClient,
|
||||
}) : _apiClient = apiClient;
|
||||
|
||||
final ApiClient _apiClient;
|
||||
|
||||
List<Destination>? _cachedDestinations;
|
||||
|
||||
@override
|
||||
Future<Result<void>> createBooking(Booking booking) async {
|
||||
try {
|
||||
final BookingApiModel bookingApiModel = BookingApiModel(
|
||||
startDate: booking.startDate,
|
||||
endDate: booking.endDate,
|
||||
name: '${booking.destination.name}, ${booking.destination.continent}',
|
||||
destinationRef: booking.destination.ref,
|
||||
activitiesRef:
|
||||
booking.activity.map((activity) => activity.ref).toList(),
|
||||
);
|
||||
return _apiClient.postBooking(bookingApiModel);
|
||||
} on Exception catch (e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<Booking>> getBooking(int id) async {
|
||||
try {
|
||||
// Get booking by ID from server
|
||||
final resultBooking = await _apiClient.getBooking(id);
|
||||
if (resultBooking is Error<BookingApiModel>) {
|
||||
return Result.error(resultBooking.error);
|
||||
}
|
||||
final booking = resultBooking.asOk.value;
|
||||
|
||||
// Load destinations if not loaded yet
|
||||
if (_cachedDestinations == null) {
|
||||
final resultDestination = await _apiClient.getDestinations();
|
||||
if (resultDestination is Error<List<Destination>>) {
|
||||
return Result.error(resultDestination.error);
|
||||
}
|
||||
_cachedDestinations = resultDestination.asOk.value;
|
||||
}
|
||||
|
||||
// Get destination for booking
|
||||
final destination = _cachedDestinations!.firstWhere(
|
||||
(destination) => destination.ref == booking.destinationRef);
|
||||
|
||||
final resultActivities =
|
||||
await _apiClient.getActivityByDestination(destination.ref);
|
||||
|
||||
if (resultActivities is Error<List<Activity>>) {
|
||||
return Result.error(resultActivities.error);
|
||||
}
|
||||
final activities = resultActivities.asOk.value
|
||||
.where((activity) => booking.activitiesRef.contains(activity.ref))
|
||||
.toList();
|
||||
|
||||
return Result.ok(
|
||||
Booking(
|
||||
id: booking.id,
|
||||
startDate: booking.startDate,
|
||||
endDate: booking.endDate,
|
||||
destination: destination,
|
||||
activity: activities,
|
||||
),
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<List<BookingSummary>>> getBookingsList() async {
|
||||
try {
|
||||
final result = await _apiClient.getBookings();
|
||||
if (result is Error<List<BookingApiModel>>) {
|
||||
return Result.error(result.error);
|
||||
}
|
||||
final bookingsApi = result.asOk.value;
|
||||
return Result.ok(bookingsApi
|
||||
.map(
|
||||
(bookingApi) => BookingSummary(
|
||||
id: bookingApi.id!,
|
||||
name: bookingApi.name,
|
||||
startDate: bookingApi.startDate,
|
||||
endDate: bookingApi.endDate,
|
||||
),
|
||||
)
|
||||
.toList());
|
||||
} on Exception catch (e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<void>> delete(int id) async {
|
||||
try {
|
||||
return _apiClient.deleteBooking(id);
|
||||
} on Exception catch (e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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 '../../../domain/models/continent/continent.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
/// Data source with all possible continents.
|
||||
abstract class ContinentRepository {
|
||||
/// Get complete list of continents.
|
||||
Future<Result<List<Continent>>> getContinents();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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 '../../../domain/models/continent/continent.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/local/local_data_service.dart';
|
||||
import 'continent_repository.dart';
|
||||
|
||||
/// Local data source with all possible continents.
|
||||
class ContinentRepositoryLocal implements ContinentRepository {
|
||||
ContinentRepositoryLocal({
|
||||
required LocalDataService localDataService,
|
||||
}) : _localDataService = localDataService;
|
||||
|
||||
final LocalDataService _localDataService;
|
||||
|
||||
@override
|
||||
Future<Result<List<Continent>>> getContinents() async {
|
||||
return Future.value(Result.ok(_localDataService.getContinents()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 '../../../domain/models/continent/continent.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/api/api_client.dart';
|
||||
import 'continent_repository.dart';
|
||||
|
||||
/// Remote data source for [Continent].
|
||||
/// Implements basic local caching.
|
||||
/// See: https://docs.flutter.dev/get-started/fwe/local-caching
|
||||
class ContinentRepositoryRemote implements ContinentRepository {
|
||||
ContinentRepositoryRemote({
|
||||
required ApiClient apiClient,
|
||||
}) : _apiClient = apiClient;
|
||||
|
||||
final ApiClient _apiClient;
|
||||
|
||||
List<Continent>? _cachedData;
|
||||
|
||||
@override
|
||||
Future<Result<List<Continent>>> getContinents() async {
|
||||
if (_cachedData == null) {
|
||||
// No cached data, request continents
|
||||
final result = await _apiClient.getContinents();
|
||||
if (result is Ok) {
|
||||
// Store value if result Ok
|
||||
_cachedData = result.asOk.value;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// Return cached data if available
|
||||
return Result.ok(_cachedData!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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 '../../../domain/models/destination/destination.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
/// Data source with all possible destinations
|
||||
abstract class DestinationRepository {
|
||||
/// Get complete list of destinations
|
||||
Future<Result<List<Destination>>> getDestinations();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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 '../../../domain/models/destination/destination.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/local/local_data_service.dart';
|
||||
import 'destination_repository.dart';
|
||||
|
||||
/// Local implementation of DestinationRepository
|
||||
/// Uses data from assets folder
|
||||
class DestinationRepositoryLocal implements DestinationRepository {
|
||||
DestinationRepositoryLocal({
|
||||
required LocalDataService localDataService,
|
||||
}) : _localDataService = localDataService;
|
||||
|
||||
final LocalDataService _localDataService;
|
||||
|
||||
/// Obtain list of destinations from local assets
|
||||
@override
|
||||
Future<Result<List<Destination>>> getDestinations() async {
|
||||
try {
|
||||
return Result.ok(await _localDataService.getDestinations());
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 '../../../domain/models/destination/destination.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/api/api_client.dart';
|
||||
import 'destination_repository.dart';
|
||||
|
||||
/// Remote data source for [Destination].
|
||||
/// Implements basic local caching.
|
||||
/// See: https://docs.flutter.dev/get-started/fwe/local-caching
|
||||
class DestinationRepositoryRemote implements DestinationRepository {
|
||||
DestinationRepositoryRemote({
|
||||
required ApiClient apiClient,
|
||||
}) : _apiClient = apiClient;
|
||||
|
||||
final ApiClient _apiClient;
|
||||
|
||||
List<Destination>? _cachedData;
|
||||
|
||||
@override
|
||||
Future<Result<List<Destination>>> getDestinations() async {
|
||||
if (_cachedData == null) {
|
||||
// No cached data, request destinations
|
||||
final result = await _apiClient.getDestinations();
|
||||
if (result is Ok) {
|
||||
// Store value if result Ok
|
||||
_cachedData = result.asOk.value;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// Return cached data if available
|
||||
return Result.ok(_cachedData!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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 '../../../domain/models/itinerary_config/itinerary_config.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
/// Data source for the current [ItineraryConfig]
|
||||
abstract class ItineraryConfigRepository {
|
||||
/// Get current [ItineraryConfig], may be empty if no configuration started.
|
||||
/// Method is async to support writing to database, file, etc.
|
||||
Future<Result<ItineraryConfig>> getItineraryConfig();
|
||||
|
||||
/// Sets [ItineraryConfig], overrides the previous one stored.
|
||||
/// Returns Result.Ok if set is successful.
|
||||
Future<Result<void>> setItineraryConfig(ItineraryConfig itineraryConfig);
|
||||
}
|
||||
@@ -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:async';
|
||||
|
||||
import '../../../domain/models/itinerary_config/itinerary_config.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import 'itinerary_config_repository.dart';
|
||||
|
||||
/// In-memory implementation of [ItineraryConfigRepository].
|
||||
class ItineraryConfigRepositoryMemory implements ItineraryConfigRepository {
|
||||
ItineraryConfig? _itineraryConfig;
|
||||
|
||||
@override
|
||||
Future<Result<ItineraryConfig>> getItineraryConfig() async {
|
||||
return Result.ok(_itineraryConfig ?? const ItineraryConfig());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<bool>> setItineraryConfig(
|
||||
ItineraryConfig itineraryConfig,
|
||||
) async {
|
||||
_itineraryConfig = itineraryConfig;
|
||||
return Result.ok(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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 '../../../domain/models/user/user.dart';
|
||||
import '../../../utils/result.dart';
|
||||
|
||||
/// Data source for user related data
|
||||
abstract class UserRepository {
|
||||
/// Get current user
|
||||
Future<Result<User>> getUser();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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 '../../../domain/models/user/user.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/local/local_data_service.dart';
|
||||
import 'user_repository.dart';
|
||||
|
||||
class UserRepositoryLocal implements UserRepository {
|
||||
UserRepositoryLocal({
|
||||
required LocalDataService localDataService,
|
||||
}) : _localDataService = localDataService;
|
||||
|
||||
final LocalDataService _localDataService;
|
||||
|
||||
@override
|
||||
Future<Result<User>> getUser() async {
|
||||
return Result.ok(_localDataService.getUser());
|
||||
}
|
||||
}
|
||||
@@ -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 '../../../domain/models/user/user.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import '../../services/api/api_client.dart';
|
||||
import '../../services/api/model/user/user_api_model.dart';
|
||||
import 'user_repository.dart';
|
||||
|
||||
class UserRepositoryRemote implements UserRepository {
|
||||
UserRepositoryRemote({
|
||||
required ApiClient apiClient,
|
||||
}) : _apiClient = apiClient;
|
||||
|
||||
final ApiClient _apiClient;
|
||||
|
||||
User? _cachedData;
|
||||
|
||||
@override
|
||||
Future<Result<User>> getUser() async {
|
||||
if (_cachedData != null) {
|
||||
return Future.value(Result.ok(_cachedData!));
|
||||
}
|
||||
|
||||
final result = await _apiClient.getUser();
|
||||
switch (result) {
|
||||
case Ok<UserApiModel>():
|
||||
final user = User(
|
||||
name: result.value.name,
|
||||
picture: result.value.picture,
|
||||
);
|
||||
_cachedData = user;
|
||||
return Result.ok(user);
|
||||
case Error<UserApiModel>():
|
||||
return Result.error(result.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
210
compass_app/app/lib/data/services/api/api_client.dart
Normal file
210
compass_app/app/lib/data/services/api/api_client.dart
Normal file
@@ -0,0 +1,210 @@
|
||||
// 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 '../../../domain/models/activity/activity.dart';
|
||||
import '../../../domain/models/continent/continent.dart';
|
||||
import '../../../domain/models/destination/destination.dart';
|
||||
import '../../../utils/result.dart';
|
||||
import 'model/booking/booking_api_model.dart';
|
||||
import 'model/user/user_api_model.dart';
|
||||
|
||||
/// Adds the `Authentication` header to a header configuration.
|
||||
typedef AuthHeaderProvider = String? Function();
|
||||
|
||||
class ApiClient {
|
||||
ApiClient({
|
||||
String? host,
|
||||
int? port,
|
||||
HttpClient Function()? clientFactory,
|
||||
}) : _host = host ?? 'localhost',
|
||||
_port = port ?? 8080,
|
||||
_clientFactory = clientFactory ?? (() => HttpClient());
|
||||
|
||||
final String _host;
|
||||
final int _port;
|
||||
final HttpClient Function() _clientFactory;
|
||||
|
||||
AuthHeaderProvider? _authHeaderProvider;
|
||||
|
||||
set authHeaderProvider(AuthHeaderProvider authHeaderProvider) {
|
||||
_authHeaderProvider = authHeaderProvider;
|
||||
}
|
||||
|
||||
Future<void> _authHeader(HttpHeaders headers) async {
|
||||
final header = _authHeaderProvider?.call();
|
||||
if (header != null) {
|
||||
headers.add(HttpHeaders.authorizationHeader, header);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<List<Continent>>> getContinents() async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.get(_host, _port, '/continent');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final json = jsonDecode(stringData) as List<dynamic>;
|
||||
return Result.ok(
|
||||
json.map((element) => Continent.fromJson(element)).toList());
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<List<Destination>>> getDestinations() async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.get(_host, _port, '/destination');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final json = jsonDecode(stringData) as List<dynamic>;
|
||||
return Result.ok(
|
||||
json.map((element) => Destination.fromJson(element)).toList());
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<List<Activity>>> getActivityByDestination(String ref) async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request =
|
||||
await client.get(_host, _port, '/destination/$ref/activity');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final json = jsonDecode(stringData) as List<dynamic>;
|
||||
final activities =
|
||||
json.map((element) => Activity.fromJson(element)).toList();
|
||||
return Result.ok(activities);
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<List<BookingApiModel>>> getBookings() async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.get(_host, _port, '/booking');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final json = jsonDecode(stringData) as List<dynamic>;
|
||||
final bookings =
|
||||
json.map((element) => BookingApiModel.fromJson(element)).toList();
|
||||
return Result.ok(bookings);
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<BookingApiModel>> getBooking(int id) async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.get(_host, _port, '/booking/$id');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final booking = BookingApiModel.fromJson(jsonDecode(stringData));
|
||||
return Result.ok(booking);
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<BookingApiModel>> postBooking(BookingApiModel booking) async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.post(_host, _port, '/booking');
|
||||
await _authHeader(request.headers);
|
||||
request.write(jsonEncode(booking));
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 201) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final booking = BookingApiModel.fromJson(jsonDecode(stringData));
|
||||
return Result.ok(booking);
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<UserApiModel>> getUser() async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.get(_host, _port, '/user');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
final user = UserApiModel.fromJson(jsonDecode(stringData));
|
||||
return Result.ok(user);
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<void>> deleteBooking(int id) async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.delete(_host, _port, '/booking/$id');
|
||||
await _authHeader(request.headers);
|
||||
final response = await request.close();
|
||||
// Response 204 "No Content", delete was successful
|
||||
if (response.statusCode == 204) {
|
||||
return Result.ok(null);
|
||||
} else {
|
||||
return Result.error(const HttpException("Invalid response"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
43
compass_app/app/lib/data/services/api/auth_api_client.dart
Normal file
43
compass_app/app/lib/data/services/api/auth_api_client.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 '../../../utils/result.dart';
|
||||
import 'model/login_request/login_request.dart';
|
||||
import 'model/login_response/login_response.dart';
|
||||
|
||||
class AuthApiClient {
|
||||
AuthApiClient({
|
||||
String? host,
|
||||
int? port,
|
||||
HttpClient Function()? clientFactory,
|
||||
}) : _host = host ?? 'localhost',
|
||||
_port = port ?? 8080,
|
||||
_clientFactory = clientFactory ?? (() => HttpClient());
|
||||
|
||||
final String _host;
|
||||
final int _port;
|
||||
final HttpClient Function() _clientFactory;
|
||||
|
||||
Future<Result<LoginResponse>> login(LoginRequest loginRequest) async {
|
||||
final client = _clientFactory();
|
||||
try {
|
||||
final request = await client.post(_host, _port, '/login');
|
||||
request.write(jsonEncode(loginRequest));
|
||||
final response = await request.close();
|
||||
if (response.statusCode == 200) {
|
||||
final stringData = await response.transform(utf8.decoder).join();
|
||||
return Result.ok(LoginResponse.fromJson(jsonDecode(stringData)));
|
||||
} else {
|
||||
return Result.error(const HttpException("Login error"));
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
return Result.error(error);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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_api_model.freezed.dart';
|
||||
part 'booking_api_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class BookingApiModel with _$BookingApiModel {
|
||||
const factory BookingApiModel({
|
||||
/// 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,
|
||||
}) = _BookingApiModel;
|
||||
|
||||
factory BookingApiModel.fromJson(Map<String, Object?> json) =>
|
||||
_$BookingApiModelFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
// 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_api_model.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');
|
||||
|
||||
BookingApiModel _$BookingApiModelFromJson(Map<String, dynamic> json) {
|
||||
return _BookingApiModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$BookingApiModel {
|
||||
/// 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 BookingApiModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of BookingApiModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$BookingApiModelCopyWith<BookingApiModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $BookingApiModelCopyWith<$Res> {
|
||||
factory $BookingApiModelCopyWith(
|
||||
BookingApiModel value, $Res Function(BookingApiModel) then) =
|
||||
_$BookingApiModelCopyWithImpl<$Res, BookingApiModel>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int? id,
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
String name,
|
||||
String destinationRef,
|
||||
List<String> activitiesRef});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$BookingApiModelCopyWithImpl<$Res, $Val extends BookingApiModel>
|
||||
implements $BookingApiModelCopyWith<$Res> {
|
||||
_$BookingApiModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of BookingApiModel
|
||||
/// 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 _$$BookingApiModelImplCopyWith<$Res>
|
||||
implements $BookingApiModelCopyWith<$Res> {
|
||||
factory _$$BookingApiModelImplCopyWith(_$BookingApiModelImpl value,
|
||||
$Res Function(_$BookingApiModelImpl) then) =
|
||||
__$$BookingApiModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int? id,
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
String name,
|
||||
String destinationRef,
|
||||
List<String> activitiesRef});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$BookingApiModelImplCopyWithImpl<$Res>
|
||||
extends _$BookingApiModelCopyWithImpl<$Res, _$BookingApiModelImpl>
|
||||
implements _$$BookingApiModelImplCopyWith<$Res> {
|
||||
__$$BookingApiModelImplCopyWithImpl(
|
||||
_$BookingApiModelImpl _value, $Res Function(_$BookingApiModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of BookingApiModel
|
||||
/// 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(_$BookingApiModelImpl(
|
||||
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 _$BookingApiModelImpl implements _BookingApiModel {
|
||||
const _$BookingApiModelImpl(
|
||||
{this.id,
|
||||
required this.startDate,
|
||||
required this.endDate,
|
||||
required this.name,
|
||||
required this.destinationRef,
|
||||
required final List<String> activitiesRef})
|
||||
: _activitiesRef = activitiesRef;
|
||||
|
||||
factory _$BookingApiModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$BookingApiModelImplFromJson(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 'BookingApiModel(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 _$BookingApiModelImpl &&
|
||||
(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 BookingApiModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$BookingApiModelImplCopyWith<_$BookingApiModelImpl> get copyWith =>
|
||||
__$$BookingApiModelImplCopyWithImpl<_$BookingApiModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$BookingApiModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _BookingApiModel implements BookingApiModel {
|
||||
const factory _BookingApiModel(
|
||||
{final int? id,
|
||||
required final DateTime startDate,
|
||||
required final DateTime endDate,
|
||||
required final String name,
|
||||
required final String destinationRef,
|
||||
required final List<String> activitiesRef}) = _$BookingApiModelImpl;
|
||||
|
||||
factory _BookingApiModel.fromJson(Map<String, dynamic> json) =
|
||||
_$BookingApiModelImpl.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 BookingApiModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$BookingApiModelImplCopyWith<_$BookingApiModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'booking_api_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$BookingApiModelImpl _$$BookingApiModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$BookingApiModelImpl(
|
||||
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> _$$BookingApiModelImplToJson(
|
||||
_$BookingApiModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'startDate': instance.startDate.toIso8601String(),
|
||||
'endDate': instance.endDate.toIso8601String(),
|
||||
'name': instance.name,
|
||||
'destinationRef': instance.destinationRef,
|
||||
'activitiesRef': instance.activitiesRef,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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_api_model.freezed.dart';
|
||||
part 'user_api_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class UserApiModel with _$UserApiModel {
|
||||
const factory UserApiModel({
|
||||
/// 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,
|
||||
}) = _UserApiModel;
|
||||
|
||||
factory UserApiModel.fromJson(Map<String, Object?> json) =>
|
||||
_$UserApiModelFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
// 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_api_model.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');
|
||||
|
||||
UserApiModel _$UserApiModelFromJson(Map<String, dynamic> json) {
|
||||
return _UserApiModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UserApiModel {
|
||||
/// 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 UserApiModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of UserApiModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$UserApiModelCopyWith<UserApiModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UserApiModelCopyWith<$Res> {
|
||||
factory $UserApiModelCopyWith(
|
||||
UserApiModel value, $Res Function(UserApiModel) then) =
|
||||
_$UserApiModelCopyWithImpl<$Res, UserApiModel>;
|
||||
@useResult
|
||||
$Res call({String id, String name, String email, String picture});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UserApiModelCopyWithImpl<$Res, $Val extends UserApiModel>
|
||||
implements $UserApiModelCopyWith<$Res> {
|
||||
_$UserApiModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of UserApiModel
|
||||
/// 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 _$$UserApiModelImplCopyWith<$Res>
|
||||
implements $UserApiModelCopyWith<$Res> {
|
||||
factory _$$UserApiModelImplCopyWith(
|
||||
_$UserApiModelImpl value, $Res Function(_$UserApiModelImpl) then) =
|
||||
__$$UserApiModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String id, String name, String email, String picture});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UserApiModelImplCopyWithImpl<$Res>
|
||||
extends _$UserApiModelCopyWithImpl<$Res, _$UserApiModelImpl>
|
||||
implements _$$UserApiModelImplCopyWith<$Res> {
|
||||
__$$UserApiModelImplCopyWithImpl(
|
||||
_$UserApiModelImpl _value, $Res Function(_$UserApiModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UserApiModel
|
||||
/// 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(_$UserApiModelImpl(
|
||||
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 _$UserApiModelImpl implements _UserApiModel {
|
||||
const _$UserApiModelImpl(
|
||||
{required this.id,
|
||||
required this.name,
|
||||
required this.email,
|
||||
required this.picture});
|
||||
|
||||
factory _$UserApiModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$UserApiModelImplFromJson(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 'UserApiModel(id: $id, name: $name, email: $email, picture: $picture)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UserApiModelImpl &&
|
||||
(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 UserApiModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UserApiModelImplCopyWith<_$UserApiModelImpl> get copyWith =>
|
||||
__$$UserApiModelImplCopyWithImpl<_$UserApiModelImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$UserApiModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _UserApiModel implements UserApiModel {
|
||||
const factory _UserApiModel(
|
||||
{required final String id,
|
||||
required final String name,
|
||||
required final String email,
|
||||
required final String picture}) = _$UserApiModelImpl;
|
||||
|
||||
factory _UserApiModel.fromJson(Map<String, dynamic> json) =
|
||||
_$UserApiModelImpl.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 UserApiModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$UserApiModelImplCopyWith<_$UserApiModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'user_api_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$UserApiModelImpl _$$UserApiModelImplFromJson(Map<String, dynamic> json) =>
|
||||
_$UserApiModelImpl(
|
||||
id: json['id'] as String,
|
||||
name: json['name'] as String,
|
||||
email: json['email'] as String,
|
||||
picture: json['picture'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$UserApiModelImplToJson(_$UserApiModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'name': instance.name,
|
||||
'email': instance.email,
|
||||
'picture': instance.picture,
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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:flutter/services.dart';
|
||||
|
||||
import '../../../config/assets.dart';
|
||||
import '../../../domain/models/activity/activity.dart';
|
||||
import '../../../domain/models/continent/continent.dart';
|
||||
import '../../../domain/models/destination/destination.dart';
|
||||
import '../../../domain/models/user/user.dart';
|
||||
|
||||
class LocalDataService {
|
||||
List<Continent> getContinents() {
|
||||
return [
|
||||
const Continent(
|
||||
name: 'Europe',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/TmR12QdlVTT',
|
||||
),
|
||||
const Continent(
|
||||
name: 'Asia',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/VJ8BXlQg8O1',
|
||||
),
|
||||
const Continent(
|
||||
name: 'South America',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/flm_-o1aI8e',
|
||||
),
|
||||
const Continent(
|
||||
name: 'Africa',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/-nzi8yFOBpF',
|
||||
),
|
||||
const Continent(
|
||||
name: 'North America',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/jlbgFDrSUVE',
|
||||
),
|
||||
const Continent(
|
||||
name: 'Oceania',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/vxyrDE-fZVL',
|
||||
),
|
||||
const Continent(
|
||||
name: 'Australia',
|
||||
imageUrl: 'https://rstr.in/google/tripedia/z6vy6HeRyvZ',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<Activity>> getActivities() async {
|
||||
final json = await _loadStringAsset(Assets.activities);
|
||||
return json.map<Activity>((json) => Activity.fromJson(json)).toList();
|
||||
}
|
||||
|
||||
Future<List<Destination>> getDestinations() async {
|
||||
final json = await _loadStringAsset(Assets.destinations);
|
||||
return json.map<Destination>((json) => Destination.fromJson(json)).toList();
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> _loadStringAsset(String asset) async {
|
||||
final localData = await rootBundle.loadString(asset);
|
||||
return (jsonDecode(localData) as List).cast<Map<String, dynamic>>();
|
||||
}
|
||||
|
||||
User getUser() {
|
||||
return const User(
|
||||
name: 'Sofie',
|
||||
// For demo purposes we use a local asset
|
||||
picture: 'assets/user.jpg',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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:logging/logging.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../utils/result.dart';
|
||||
|
||||
class SharedPreferencesService {
|
||||
static const _tokenKey = 'TOKEN';
|
||||
final _log = Logger('SharedPreferencesService');
|
||||
|
||||
Future<Result<String?>> fetchToken() async {
|
||||
try {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
_log.finer('Got token from SharedPreferences');
|
||||
return Result.ok(sharedPreferences.getString(_tokenKey));
|
||||
} on Exception catch (e) {
|
||||
_log.warning('Failed to get token', e);
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Result<void>> saveToken(String? token) async {
|
||||
try {
|
||||
final sharedPreferences = await SharedPreferences.getInstance();
|
||||
if (token == null) {
|
||||
_log.finer('Removed token');
|
||||
await sharedPreferences.remove(_tokenKey);
|
||||
} else {
|
||||
_log.finer('Replaced token');
|
||||
await sharedPreferences.setString(_tokenKey, token);
|
||||
}
|
||||
return Result.ok(null);
|
||||
} on Exception catch (e) {
|
||||
_log.warning('Failed to set token', e);
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user