chore(wip): upgrade dependencies, begin refactor
This commit is contained in:
@@ -10,7 +10,8 @@ pkgs.mkShell {
|
|||||||
# androidenv.androidPkgs.ndk-bundle
|
# androidenv.androidPkgs.ndk-bundle
|
||||||
];
|
];
|
||||||
|
|
||||||
# Set up Android SDK paths if needed
|
# Setting up android build environments on nix is a bit of a pain - immutable paths, etc.
|
||||||
|
# I used a hacky workaround by manually downloading the SDK and NDK from the website and simply telling the shell where to find them
|
||||||
ANDROID_HOME = "/scratch/remy/android";
|
ANDROID_HOME = "/scratch/remy/android";
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ To truly deploy a new version of the application, i.e. to the official app store
|
|||||||
git tag -a v<name> -m "Release <name>"
|
git tag -a v<name> -m "Release <name>"
|
||||||
git push origin v<name>
|
git push origin v<name>
|
||||||
```
|
```
|
||||||
We adhere to the [Semantic Versioning](https://semver.org/) standard, so the tag should be of the form `v0.1.8` for example.
|
We adhere to the [Semantic Versioning](https://semver.org/) standard, so the tag should be of the form `v0.1.8` for example.
|
||||||
|
|
||||||
### Icons and logos
|
### Icons and logos
|
||||||
The application uses a custom launcher icon and splash screen. These are managed platform-independently using the `flutter_launcher_icons` package.
|
The application uses a custom launcher icon and splash screen. These are managed platform-independently using the `flutter_launcher_icons` package.
|
||||||
@@ -66,3 +66,10 @@ These are used by the CI/CD pipeline to deploy the application.
|
|||||||
- `IOS_ASC_KEY_ID` as well
|
- `IOS_ASC_KEY_ID` as well
|
||||||
- `IOS_MATCH_PASSWORD` is used by fastlane match to download the certificates
|
- `IOS_MATCH_PASSWORD` is used by fastlane match to download the certificates
|
||||||
- `IOS_MATCH_REPO_SSH_KEY_BASE64` is used to authenticate with the git repository where the certificates are stored
|
- `IOS_MATCH_REPO_SSH_KEY_BASE64` is used to authenticate with the git repository where the certificates are stored
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Android SDK&NDK setup
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ if (secretPropertiesFile.exists()) {
|
|||||||
android {
|
android {
|
||||||
namespace "com.anydev.anyway"
|
namespace "com.anydev.anyway"
|
||||||
compileSdk flutter.compileSdkVersion
|
compileSdk flutter.compileSdkVersion
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion = "27.0.12077973"
|
||||||
|
// TODO - set back to ndkVersion flutter.ndkVersion once https://github.com/flutter/flutter/issues/139427 is resolved
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
@@ -65,7 +66,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
||||||
applicationId "com.anydev.anyway"
|
applicationId "com.anydev.anyway"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
|
|||||||
83
frontend/lib/core/constants.dart
Normal file
83
frontend/lib/core/constants.dart
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
const String APP_NAME = 'AnyWay';
|
||||||
|
|
||||||
|
String API_URL_BASE = 'https://anyway.anydev.info';
|
||||||
|
String API_URL_DEBUG = 'https://anyway-stg.anydev.info';
|
||||||
|
String PRIVACY_URL = 'https://anydev.info/privacy';
|
||||||
|
|
||||||
|
const String MAP_ID = '41c21ac9b81dbfd8';
|
||||||
|
|
||||||
|
|
||||||
|
const Color GRADIENT_START = Color(0xFFF9B208);
|
||||||
|
const Color GRADIENT_END = Color(0xFFE72E77);
|
||||||
|
|
||||||
|
const Color PRIMARY_COLOR = Color(0xFFF38F1A);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const double TRIP_PANEL_MAX_HEIGHT = 0.8;
|
||||||
|
const double TRIP_PANEL_MIN_HEIGHT = 0.12;
|
||||||
|
|
||||||
|
ThemeData APP_THEME = ThemeData(
|
||||||
|
primaryColor: PRIMARY_COLOR,
|
||||||
|
|
||||||
|
scaffoldBackgroundColor: Colors.white,
|
||||||
|
cardColor: Colors.white,
|
||||||
|
useMaterial3: true,
|
||||||
|
|
||||||
|
colorScheme: const ColorScheme.light(
|
||||||
|
primary: PRIMARY_COLOR,
|
||||||
|
secondary: GRADIENT_END,
|
||||||
|
surface: Colors.white,
|
||||||
|
error: Colors.red,
|
||||||
|
onPrimary: Colors.white,
|
||||||
|
onSecondary: Color.fromARGB(255, 30, 22, 22),
|
||||||
|
onSurface: Colors.black,
|
||||||
|
onError: Colors.white,
|
||||||
|
brightness: Brightness.light,
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
textButtonTheme: const TextButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||||
|
side: WidgetStatePropertyAll(
|
||||||
|
BorderSide(
|
||||||
|
color: PRIMARY_COLOR,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
elevatedButtonTheme: const ElevatedButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
outlinedButtonTheme: const OutlinedButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
sliderTheme: const SliderThemeData(
|
||||||
|
trackHeight: 15,
|
||||||
|
inactiveTrackColor: Colors.grey,
|
||||||
|
thumbColor: PRIMARY_COLOR,
|
||||||
|
activeTrackColor: GRADIENT_END
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const Gradient APP_GRADIENT = LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [GRADIENT_START, GRADIENT_END],
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||||
16
frontend/lib/core/dio_client.dart
Normal file
16
frontend/lib/core/dio_client.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
class DioClient {
|
||||||
|
final Dio dio;
|
||||||
|
|
||||||
|
DioClient({required String baseUrl}): dio = Dio(BaseOptions(
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
connectTimeout: const Duration(seconds: 5),
|
||||||
|
receiveTimeout: const Duration(seconds: 120),
|
||||||
|
// also accept 500 errors, since we cannot rule out that the server is at fault. We still want to gracefully handle these errors
|
||||||
|
validateStatus: (status) => status! <= 500,
|
||||||
|
receiveDataWhenStatusError: true,
|
||||||
|
contentType: Headers.jsonContentType,
|
||||||
|
responseType: ResponseType.json,
|
||||||
|
));
|
||||||
|
}
|
||||||
0
frontend/lib/data/README.md
Normal file
0
frontend/lib/data/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import 'package:anyway/domain/entities/landmark.dart';
|
||||||
|
|
||||||
|
abstract class TripRemoteDataSource {
|
||||||
|
Future<List<Landmark>> fetchLandmarks();
|
||||||
|
}
|
||||||
30
frontend/lib/data/models/landmark_model.dart
Normal file
30
frontend/lib/data/models/landmark_model.dart
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import 'package:anyway/domain/entities/landmark.dart';
|
||||||
|
import 'package:anyway/domain/entities/landmark_description.dart';
|
||||||
|
import 'package:anyway/domain/entities/landmark_type.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
part 'landmark_model.freezed.dart';
|
||||||
|
part 'landmark_model.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class LandmarkModel with _$LandmarkModel {
|
||||||
|
const factory LandmarkModel({
|
||||||
|
required String uuid,
|
||||||
|
required String name,
|
||||||
|
required List<double> location,
|
||||||
|
required String type,
|
||||||
|
required bool isSecondary,
|
||||||
|
required String description,
|
||||||
|
}) = _LandmarkModel;
|
||||||
|
|
||||||
|
factory LandmarkModel.fromJson(Map<String, dynamic> json) => _$LandmarkModelFromJson(json);
|
||||||
|
|
||||||
|
Landmark toEntity() => Landmark(
|
||||||
|
uuid: uuid,
|
||||||
|
name: name,
|
||||||
|
location: location,
|
||||||
|
type: LandmarkType(type: LandmarkTypeEnum.values.firstWhere((e) => e.value == type)),
|
||||||
|
isSecondary: isSecondary,
|
||||||
|
// TODO - try to set tags
|
||||||
|
description: LandmarkDescription(description: description, tags: [])
|
||||||
|
);
|
||||||
|
}
|
||||||
443
frontend/lib/data/models/landmark_model.freezed.dart
Normal file
443
frontend/lib/data/models/landmark_model.freezed.dart
Normal file
@@ -0,0 +1,443 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'landmark_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$LandmarkModel {
|
||||||
|
String get uuid;
|
||||||
|
String get name;
|
||||||
|
List<double> get location;
|
||||||
|
String get type;
|
||||||
|
bool get isSecondary;
|
||||||
|
String get description;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkModelCopyWith<LandmarkModel> get copyWith =>
|
||||||
|
_$LandmarkModelCopyWithImpl<LandmarkModel>(
|
||||||
|
this as LandmarkModel, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this LandmarkModel to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is LandmarkModel &&
|
||||||
|
(identical(other.uuid, uuid) || other.uuid == uuid) &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
const DeepCollectionEquality().equals(other.location, location) &&
|
||||||
|
(identical(other.type, type) || other.type == type) &&
|
||||||
|
(identical(other.isSecondary, isSecondary) ||
|
||||||
|
other.isSecondary == isSecondary) &&
|
||||||
|
(identical(other.description, description) ||
|
||||||
|
other.description == description));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
uuid,
|
||||||
|
name,
|
||||||
|
const DeepCollectionEquality().hash(location),
|
||||||
|
type,
|
||||||
|
isSecondary,
|
||||||
|
description);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LandmarkModel(uuid: $uuid, name: $name, location: $location, type: $type, isSecondary: $isSecondary, description: $description)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $LandmarkModelCopyWith<$Res> {
|
||||||
|
factory $LandmarkModelCopyWith(
|
||||||
|
LandmarkModel value, $Res Function(LandmarkModel) _then) =
|
||||||
|
_$LandmarkModelCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
String type,
|
||||||
|
bool isSecondary,
|
||||||
|
String description});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$LandmarkModelCopyWithImpl<$Res>
|
||||||
|
implements $LandmarkModelCopyWith<$Res> {
|
||||||
|
_$LandmarkModelCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final LandmarkModel _self;
|
||||||
|
final $Res Function(LandmarkModel) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? uuid = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? location = null,
|
||||||
|
Object? type = null,
|
||||||
|
Object? isSecondary = null,
|
||||||
|
Object? description = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
uuid: null == uuid
|
||||||
|
? _self.uuid
|
||||||
|
: uuid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _self.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
location: null == location
|
||||||
|
? _self.location
|
||||||
|
: location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<double>,
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
isSecondary: null == isSecondary
|
||||||
|
? _self.isSecondary
|
||||||
|
: isSecondary // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
description: null == description
|
||||||
|
? _self.description
|
||||||
|
: description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [LandmarkModel].
|
||||||
|
extension LandmarkModelPatterns on LandmarkModel {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>(
|
||||||
|
TResult Function(_LandmarkModel value)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkModel() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>(
|
||||||
|
TResult Function(_LandmarkModel value) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkModel():
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(_LandmarkModel value)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkModel() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>(
|
||||||
|
TResult Function(String uuid, String name, List<double> location,
|
||||||
|
String type, bool isSecondary, String description)?
|
||||||
|
$default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkModel() when $default != null:
|
||||||
|
return $default(_that.uuid, _that.name, _that.location, _that.type,
|
||||||
|
_that.isSecondary, _that.description);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>(
|
||||||
|
TResult Function(String uuid, String name, List<double> location,
|
||||||
|
String type, bool isSecondary, String description)
|
||||||
|
$default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkModel():
|
||||||
|
return $default(_that.uuid, _that.name, _that.location, _that.type,
|
||||||
|
_that.isSecondary, _that.description);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(String uuid, String name, List<double> location,
|
||||||
|
String type, bool isSecondary, String description)?
|
||||||
|
$default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkModel() when $default != null:
|
||||||
|
return $default(_that.uuid, _that.name, _that.location, _that.type,
|
||||||
|
_that.isSecondary, _that.description);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _LandmarkModel implements LandmarkModel {
|
||||||
|
const _LandmarkModel(
|
||||||
|
{required this.uuid,
|
||||||
|
required this.name,
|
||||||
|
required final List<double> location,
|
||||||
|
required this.type,
|
||||||
|
required this.isSecondary,
|
||||||
|
required this.description})
|
||||||
|
: _location = location;
|
||||||
|
factory _LandmarkModel.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$LandmarkModelFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String uuid;
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
final List<double> _location;
|
||||||
|
@override
|
||||||
|
List<double> get location {
|
||||||
|
if (_location is EqualUnmodifiableListView) return _location;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String type;
|
||||||
|
@override
|
||||||
|
final bool isSecondary;
|
||||||
|
@override
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$LandmarkModelCopyWith<_LandmarkModel> get copyWith =>
|
||||||
|
__$LandmarkModelCopyWithImpl<_LandmarkModel>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$LandmarkModelToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _LandmarkModel &&
|
||||||
|
(identical(other.uuid, uuid) || other.uuid == uuid) &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
const DeepCollectionEquality().equals(other._location, _location) &&
|
||||||
|
(identical(other.type, type) || other.type == type) &&
|
||||||
|
(identical(other.isSecondary, isSecondary) ||
|
||||||
|
other.isSecondary == isSecondary) &&
|
||||||
|
(identical(other.description, description) ||
|
||||||
|
other.description == description));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
uuid,
|
||||||
|
name,
|
||||||
|
const DeepCollectionEquality().hash(_location),
|
||||||
|
type,
|
||||||
|
isSecondary,
|
||||||
|
description);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LandmarkModel(uuid: $uuid, name: $name, location: $location, type: $type, isSecondary: $isSecondary, description: $description)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$LandmarkModelCopyWith<$Res>
|
||||||
|
implements $LandmarkModelCopyWith<$Res> {
|
||||||
|
factory _$LandmarkModelCopyWith(
|
||||||
|
_LandmarkModel value, $Res Function(_LandmarkModel) _then) =
|
||||||
|
__$LandmarkModelCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
String type,
|
||||||
|
bool isSecondary,
|
||||||
|
String description});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$LandmarkModelCopyWithImpl<$Res>
|
||||||
|
implements _$LandmarkModelCopyWith<$Res> {
|
||||||
|
__$LandmarkModelCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _LandmarkModel _self;
|
||||||
|
final $Res Function(_LandmarkModel) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? uuid = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? location = null,
|
||||||
|
Object? type = null,
|
||||||
|
Object? isSecondary = null,
|
||||||
|
Object? description = null,
|
||||||
|
}) {
|
||||||
|
return _then(_LandmarkModel(
|
||||||
|
uuid: null == uuid
|
||||||
|
? _self.uuid
|
||||||
|
: uuid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _self.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
location: null == location
|
||||||
|
? _self._location
|
||||||
|
: location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<double>,
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
isSecondary: null == isSecondary
|
||||||
|
? _self.isSecondary
|
||||||
|
: isSecondary // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
description: null == description
|
||||||
|
? _self.description
|
||||||
|
: description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
29
frontend/lib/data/models/landmark_model.g.dart
Normal file
29
frontend/lib/data/models/landmark_model.g.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'landmark_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_LandmarkModel _$LandmarkModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
_LandmarkModel(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
location: (json['location'] as List<dynamic>)
|
||||||
|
.map((e) => (e as num).toDouble())
|
||||||
|
.toList(),
|
||||||
|
type: json['type'] as String,
|
||||||
|
isSecondary: json['isSecondary'] as bool,
|
||||||
|
description: json['description'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$LandmarkModelToJson(_LandmarkModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'uuid': instance.uuid,
|
||||||
|
'name': instance.name,
|
||||||
|
'location': instance.location,
|
||||||
|
'type': instance.type,
|
||||||
|
'isSecondary': instance.isSecondary,
|
||||||
|
'description': instance.description,
|
||||||
|
};
|
||||||
119
frontend/lib/data/repositories/backend_trip_repository.dart
Normal file
119
frontend/lib/data/repositories/backend_trip_repository.dart
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:anyway/domain/entities/preferences.dart';
|
||||||
|
import 'package:anyway/domain/entities/trip.dart';
|
||||||
|
import 'package:anyway/domain/repositories/trip_repository.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
// We can request a new trip from our backend API by passing it user preferences (which contain all the necessary data)
|
||||||
|
class BackendTripRepository implements TripRepository {
|
||||||
|
final Dio dio;
|
||||||
|
|
||||||
|
BackendTripRepository({required this.dio});
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Trip> getTrip({Preferences? preferences, String? tripUUID}) async {
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
"preferences": preferences!.toJson(),
|
||||||
|
// "start": preferences!.startPoint.location,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
late Response response;
|
||||||
|
try {
|
||||||
|
response = await dio.post(
|
||||||
|
"/trip/new",
|
||||||
|
data: data
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
trip.updateUUID("error");
|
||||||
|
|
||||||
|
// Format the error message to be more user friendly
|
||||||
|
String errorDescription;
|
||||||
|
if (e is DioException) {
|
||||||
|
errorDescription = e.message ?? "Unknown error";
|
||||||
|
} else if (e is SocketException) {
|
||||||
|
errorDescription = "No internet connection";
|
||||||
|
} else if (e is TimeoutException) {
|
||||||
|
errorDescription = "Request timed out";
|
||||||
|
} else {
|
||||||
|
errorDescription = "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
String errorMessage = """
|
||||||
|
We're sorry, the following error was generated:
|
||||||
|
|
||||||
|
${errorDescription.trim()}
|
||||||
|
""".trim();
|
||||||
|
|
||||||
|
trip.updateError(errorMessage);
|
||||||
|
log(e.toString());
|
||||||
|
log(errorMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle more specific errors
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
trip.updateUUID("error");
|
||||||
|
String errorDescription;
|
||||||
|
if (response.data.runtimeType == String) {
|
||||||
|
errorDescription = response.data;
|
||||||
|
} else if (response.data.runtimeType == Map<String, dynamic>) {
|
||||||
|
errorDescription = response.data["detail"] ?? "Unknown error";
|
||||||
|
} else {
|
||||||
|
errorDescription = "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
String errorMessage = """
|
||||||
|
We're sorry, our servers generated the following error:
|
||||||
|
|
||||||
|
${errorDescription.trim()}
|
||||||
|
Please try again.
|
||||||
|
""".trim();
|
||||||
|
trip.updateError(errorMessage);
|
||||||
|
log(errorMessage);
|
||||||
|
// Actualy no need to throw an exception, we can just log the error and let the user retry
|
||||||
|
// throw Exception(errorDetail);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// if the response data is not json, throw an error
|
||||||
|
if (response.data is! Map<String, dynamic>) {
|
||||||
|
log("${response.data.runtimeType}");
|
||||||
|
trip.updateUUID("error");
|
||||||
|
String errorMessage = """
|
||||||
|
We're sorry, our servers generated the following error:
|
||||||
|
|
||||||
|
${response.data.trim()}
|
||||||
|
Please try again.
|
||||||
|
""".trim();
|
||||||
|
trip.updateError(errorMessage);
|
||||||
|
log(errorMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> json = response.data;
|
||||||
|
|
||||||
|
// only fill in the trip "meta" data for now
|
||||||
|
trip.loadFromJson(json);
|
||||||
|
|
||||||
|
// now fill the trip with landmarks
|
||||||
|
// we are going to recreate ALL the landmarks from the information given by the api
|
||||||
|
trip.landmarks.remove(trip.landmarks.first);
|
||||||
|
String? nextUUID = json["first_landmark_uuid"];
|
||||||
|
while (nextUUID != null) {
|
||||||
|
var (landmark, newUUID) = await fetchLandmark(nextUUID);
|
||||||
|
trip.addLandmark(landmark);
|
||||||
|
nextUUID = newUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(response.data.toString());
|
||||||
|
// // Also save the trip for the user's convenience
|
||||||
|
// savedTrips.addTrip(trip);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
24
frontend/lib/domain/README.md
Normal file
24
frontend/lib/domain/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Domain layer
|
||||||
|
|
||||||
|
## `entities` - Model definition
|
||||||
|
|
||||||
|
Since we follow the repository structure convention, in this folder we purely define data models, without providing any logic. To reduce boilerplate, we use the `freezed` package. This requires some code generation, which means that all model definitions have the following structure:
|
||||||
|
```dart
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
// required: associates our `main.dart` with the code generated by Freezed
|
||||||
|
part 'main.freezed.dart';
|
||||||
|
// optional: Since our Person class is serializable, we must add this line.
|
||||||
|
// But if Person was not serializable, we could skip it.
|
||||||
|
part 'main.g.dart';
|
||||||
|
```
|
||||||
|
|
||||||
|
This is required boilerplate for all models. Then, we define the model itself using the `@freezed` annotation:
|
||||||
|
```dart
|
||||||
|
@freezed
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
The `*.frozen.dart` and `*.g.dart` are pure boilerplate and should not be touched.
|
||||||
|
|
||||||
|
Note that the description of the data will losely follow the capabilities of the backend but does not need to reflect it exactly. That is where the `data` part is for: translating api calls into flutter objects.
|
||||||
21
frontend/lib/domain/entities/landmark.dart
Normal file
21
frontend/lib/domain/entities/landmark.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:anyway/domain/entities/landmark_type.dart';
|
||||||
|
import 'package:anyway/domain/entities/landmark_description.dart';
|
||||||
|
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
part 'landmark.freezed.dart';
|
||||||
|
part 'landmark.g.dart';
|
||||||
|
|
||||||
|
@unfreezed
|
||||||
|
abstract class Landmark with _$Landmark {
|
||||||
|
factory Landmark({
|
||||||
|
required String uuid,
|
||||||
|
required String name,
|
||||||
|
required List<double> location,
|
||||||
|
required LandmarkType type,
|
||||||
|
required bool isSecondary,
|
||||||
|
|
||||||
|
required LandmarkDescription description,
|
||||||
|
}) = _Landmark;
|
||||||
|
|
||||||
|
factory Landmark.fromJson(Map<String, Object?> json) => _$LandmarkFromJson(json);
|
||||||
|
}
|
||||||
448
frontend/lib/domain/entities/landmark.freezed.dart
Normal file
448
frontend/lib/domain/entities/landmark.freezed.dart
Normal file
@@ -0,0 +1,448 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'landmark.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$Landmark {
|
||||||
|
String get uuid;
|
||||||
|
set uuid(String value);
|
||||||
|
String get name;
|
||||||
|
set name(String value);
|
||||||
|
List<double> get location;
|
||||||
|
set location(List<double> value);
|
||||||
|
LandmarkType get type;
|
||||||
|
set type(LandmarkType value);
|
||||||
|
bool get isSecondary;
|
||||||
|
set isSecondary(bool value);
|
||||||
|
LandmarkDescription get description;
|
||||||
|
set description(LandmarkDescription value);
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkCopyWith<Landmark> get copyWith =>
|
||||||
|
_$LandmarkCopyWithImpl<Landmark>(this as Landmark, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this Landmark to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Landmark(uuid: $uuid, name: $name, location: $location, type: $type, isSecondary: $isSecondary, description: $description)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $LandmarkCopyWith<$Res> {
|
||||||
|
factory $LandmarkCopyWith(Landmark value, $Res Function(Landmark) _then) =
|
||||||
|
_$LandmarkCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
LandmarkType type,
|
||||||
|
bool isSecondary,
|
||||||
|
LandmarkDescription description});
|
||||||
|
|
||||||
|
$LandmarkTypeCopyWith<$Res> get type;
|
||||||
|
$LandmarkDescriptionCopyWith<$Res> get description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$LandmarkCopyWithImpl<$Res> implements $LandmarkCopyWith<$Res> {
|
||||||
|
_$LandmarkCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final Landmark _self;
|
||||||
|
final $Res Function(Landmark) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? uuid = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? location = null,
|
||||||
|
Object? type = null,
|
||||||
|
Object? isSecondary = null,
|
||||||
|
Object? description = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
uuid: null == uuid
|
||||||
|
? _self.uuid
|
||||||
|
: uuid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _self.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
location: null == location
|
||||||
|
? _self.location
|
||||||
|
: location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<double>,
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LandmarkType,
|
||||||
|
isSecondary: null == isSecondary
|
||||||
|
? _self.isSecondary
|
||||||
|
: isSecondary // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
description: null == description
|
||||||
|
? _self.description
|
||||||
|
: description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LandmarkDescription,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkTypeCopyWith<$Res> get type {
|
||||||
|
return $LandmarkTypeCopyWith<$Res>(_self.type, (value) {
|
||||||
|
return _then(_self.copyWith(type: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkDescriptionCopyWith<$Res> get description {
|
||||||
|
return $LandmarkDescriptionCopyWith<$Res>(_self.description, (value) {
|
||||||
|
return _then(_self.copyWith(description: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [Landmark].
|
||||||
|
extension LandmarkPatterns on Landmark {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>(
|
||||||
|
TResult Function(_Landmark value)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Landmark() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>(
|
||||||
|
TResult Function(_Landmark value) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Landmark():
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(_Landmark value)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Landmark() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>(
|
||||||
|
TResult Function(
|
||||||
|
String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
LandmarkType type,
|
||||||
|
bool isSecondary,
|
||||||
|
LandmarkDescription description)?
|
||||||
|
$default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Landmark() when $default != null:
|
||||||
|
return $default(_that.uuid, _that.name, _that.location, _that.type,
|
||||||
|
_that.isSecondary, _that.description);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>(
|
||||||
|
TResult Function(
|
||||||
|
String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
LandmarkType type,
|
||||||
|
bool isSecondary,
|
||||||
|
LandmarkDescription description)
|
||||||
|
$default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Landmark():
|
||||||
|
return $default(_that.uuid, _that.name, _that.location, _that.type,
|
||||||
|
_that.isSecondary, _that.description);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(
|
||||||
|
String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
LandmarkType type,
|
||||||
|
bool isSecondary,
|
||||||
|
LandmarkDescription description)?
|
||||||
|
$default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Landmark() when $default != null:
|
||||||
|
return $default(_that.uuid, _that.name, _that.location, _that.type,
|
||||||
|
_that.isSecondary, _that.description);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _Landmark implements Landmark {
|
||||||
|
_Landmark(
|
||||||
|
{required this.uuid,
|
||||||
|
required this.name,
|
||||||
|
required this.location,
|
||||||
|
required this.type,
|
||||||
|
required this.isSecondary,
|
||||||
|
required this.description});
|
||||||
|
factory _Landmark.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$LandmarkFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String uuid;
|
||||||
|
@override
|
||||||
|
String name;
|
||||||
|
@override
|
||||||
|
List<double> location;
|
||||||
|
@override
|
||||||
|
LandmarkType type;
|
||||||
|
@override
|
||||||
|
bool isSecondary;
|
||||||
|
@override
|
||||||
|
LandmarkDescription description;
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$LandmarkCopyWith<_Landmark> get copyWith =>
|
||||||
|
__$LandmarkCopyWithImpl<_Landmark>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$LandmarkToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Landmark(uuid: $uuid, name: $name, location: $location, type: $type, isSecondary: $isSecondary, description: $description)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$LandmarkCopyWith<$Res>
|
||||||
|
implements $LandmarkCopyWith<$Res> {
|
||||||
|
factory _$LandmarkCopyWith(_Landmark value, $Res Function(_Landmark) _then) =
|
||||||
|
__$LandmarkCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String uuid,
|
||||||
|
String name,
|
||||||
|
List<double> location,
|
||||||
|
LandmarkType type,
|
||||||
|
bool isSecondary,
|
||||||
|
LandmarkDescription description});
|
||||||
|
|
||||||
|
@override
|
||||||
|
$LandmarkTypeCopyWith<$Res> get type;
|
||||||
|
@override
|
||||||
|
$LandmarkDescriptionCopyWith<$Res> get description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$LandmarkCopyWithImpl<$Res> implements _$LandmarkCopyWith<$Res> {
|
||||||
|
__$LandmarkCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _Landmark _self;
|
||||||
|
final $Res Function(_Landmark) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? uuid = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? location = null,
|
||||||
|
Object? type = null,
|
||||||
|
Object? isSecondary = null,
|
||||||
|
Object? description = null,
|
||||||
|
}) {
|
||||||
|
return _then(_Landmark(
|
||||||
|
uuid: null == uuid
|
||||||
|
? _self.uuid
|
||||||
|
: uuid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _self.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
location: null == location
|
||||||
|
? _self.location
|
||||||
|
: location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<double>,
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LandmarkType,
|
||||||
|
isSecondary: null == isSecondary
|
||||||
|
? _self.isSecondary
|
||||||
|
: isSecondary // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
description: null == description
|
||||||
|
? _self.description
|
||||||
|
: description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LandmarkDescription,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkTypeCopyWith<$Res> get type {
|
||||||
|
return $LandmarkTypeCopyWith<$Res>(_self.type, (value) {
|
||||||
|
return _then(_self.copyWith(type: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of Landmark
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkDescriptionCopyWith<$Res> get description {
|
||||||
|
return $LandmarkDescriptionCopyWith<$Res>(_self.description, (value) {
|
||||||
|
return _then(_self.copyWith(description: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
28
frontend/lib/domain/entities/landmark.g.dart
Normal file
28
frontend/lib/domain/entities/landmark.g.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'landmark.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_Landmark _$LandmarkFromJson(Map<String, dynamic> json) => _Landmark(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
location: (json['location'] as List<dynamic>)
|
||||||
|
.map((e) => (e as num).toDouble())
|
||||||
|
.toList(),
|
||||||
|
type: LandmarkType.fromJson(json['type'] as Map<String, dynamic>),
|
||||||
|
isSecondary: json['isSecondary'] as bool,
|
||||||
|
description: LandmarkDescription.fromJson(
|
||||||
|
json['description'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$LandmarkToJson(_Landmark instance) => <String, dynamic>{
|
||||||
|
'uuid': instance.uuid,
|
||||||
|
'name': instance.name,
|
||||||
|
'location': instance.location,
|
||||||
|
'type': instance.type,
|
||||||
|
'isSecondary': instance.isSecondary,
|
||||||
|
'description': instance.description,
|
||||||
|
};
|
||||||
15
frontend/lib/domain/entities/landmark_description.dart
Normal file
15
frontend/lib/domain/entities/landmark_description.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
part 'landmark_description.freezed.dart';
|
||||||
|
part 'landmark_description.g.dart';
|
||||||
|
|
||||||
|
|
||||||
|
@Freezed(makeCollectionsUnmodifiable: false)
|
||||||
|
abstract class LandmarkDescription with _$LandmarkDescription {
|
||||||
|
const factory LandmarkDescription({
|
||||||
|
required String description,
|
||||||
|
required List<String> tags,
|
||||||
|
}) = _LandmarkDescription;
|
||||||
|
|
||||||
|
factory LandmarkDescription.fromJson(Map<String, Object?> json) => _$LandmarkDescriptionFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
336
frontend/lib/domain/entities/landmark_description.freezed.dart
Normal file
336
frontend/lib/domain/entities/landmark_description.freezed.dart
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'landmark_description.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$LandmarkDescription {
|
||||||
|
String get description;
|
||||||
|
List<String> get tags;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkDescription
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkDescriptionCopyWith<LandmarkDescription> get copyWith =>
|
||||||
|
_$LandmarkDescriptionCopyWithImpl<LandmarkDescription>(
|
||||||
|
this as LandmarkDescription, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this LandmarkDescription to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is LandmarkDescription &&
|
||||||
|
(identical(other.description, description) ||
|
||||||
|
other.description == description) &&
|
||||||
|
const DeepCollectionEquality().equals(other.tags, tags));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType, description, const DeepCollectionEquality().hash(tags));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LandmarkDescription(description: $description, tags: $tags)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $LandmarkDescriptionCopyWith<$Res> {
|
||||||
|
factory $LandmarkDescriptionCopyWith(
|
||||||
|
LandmarkDescription value, $Res Function(LandmarkDescription) _then) =
|
||||||
|
_$LandmarkDescriptionCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({String description, List<String> tags});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$LandmarkDescriptionCopyWithImpl<$Res>
|
||||||
|
implements $LandmarkDescriptionCopyWith<$Res> {
|
||||||
|
_$LandmarkDescriptionCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final LandmarkDescription _self;
|
||||||
|
final $Res Function(LandmarkDescription) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkDescription
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? description = null,
|
||||||
|
Object? tags = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
description: null == description
|
||||||
|
? _self.description
|
||||||
|
: description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
tags: null == tags
|
||||||
|
? _self.tags
|
||||||
|
: tags // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [LandmarkDescription].
|
||||||
|
extension LandmarkDescriptionPatterns on LandmarkDescription {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>(
|
||||||
|
TResult Function(_LandmarkDescription value)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkDescription() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>(
|
||||||
|
TResult Function(_LandmarkDescription value) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkDescription():
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(_LandmarkDescription value)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkDescription() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>(
|
||||||
|
TResult Function(String description, List<String> tags)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkDescription() when $default != null:
|
||||||
|
return $default(_that.description, _that.tags);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>(
|
||||||
|
TResult Function(String description, List<String> tags) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkDescription():
|
||||||
|
return $default(_that.description, _that.tags);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(String description, List<String> tags)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkDescription() when $default != null:
|
||||||
|
return $default(_that.description, _that.tags);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _LandmarkDescription implements LandmarkDescription {
|
||||||
|
const _LandmarkDescription({required this.description, required this.tags});
|
||||||
|
factory _LandmarkDescription.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$LandmarkDescriptionFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String description;
|
||||||
|
@override
|
||||||
|
final List<String> tags;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkDescription
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$LandmarkDescriptionCopyWith<_LandmarkDescription> get copyWith =>
|
||||||
|
__$LandmarkDescriptionCopyWithImpl<_LandmarkDescription>(
|
||||||
|
this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$LandmarkDescriptionToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _LandmarkDescription &&
|
||||||
|
(identical(other.description, description) ||
|
||||||
|
other.description == description) &&
|
||||||
|
const DeepCollectionEquality().equals(other.tags, tags));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType, description, const DeepCollectionEquality().hash(tags));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LandmarkDescription(description: $description, tags: $tags)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$LandmarkDescriptionCopyWith<$Res>
|
||||||
|
implements $LandmarkDescriptionCopyWith<$Res> {
|
||||||
|
factory _$LandmarkDescriptionCopyWith(_LandmarkDescription value,
|
||||||
|
$Res Function(_LandmarkDescription) _then) =
|
||||||
|
__$LandmarkDescriptionCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String description, List<String> tags});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$LandmarkDescriptionCopyWithImpl<$Res>
|
||||||
|
implements _$LandmarkDescriptionCopyWith<$Res> {
|
||||||
|
__$LandmarkDescriptionCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _LandmarkDescription _self;
|
||||||
|
final $Res Function(_LandmarkDescription) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkDescription
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? description = null,
|
||||||
|
Object? tags = null,
|
||||||
|
}) {
|
||||||
|
return _then(_LandmarkDescription(
|
||||||
|
description: null == description
|
||||||
|
? _self.description
|
||||||
|
: description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
tags: null == tags
|
||||||
|
? _self.tags
|
||||||
|
: tags // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
20
frontend/lib/domain/entities/landmark_description.g.dart
Normal file
20
frontend/lib/domain/entities/landmark_description.g.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'landmark_description.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_LandmarkDescription _$LandmarkDescriptionFromJson(Map<String, dynamic> json) =>
|
||||||
|
_LandmarkDescription(
|
||||||
|
description: json['description'] as String,
|
||||||
|
tags: (json['tags'] as List<dynamic>).map((e) => e as String).toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$LandmarkDescriptionToJson(
|
||||||
|
_LandmarkDescription instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'description': instance.description,
|
||||||
|
'tags': instance.tags,
|
||||||
|
};
|
||||||
27
frontend/lib/domain/entities/landmark_type.dart
Normal file
27
frontend/lib/domain/entities/landmark_type.dart
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'landmark_type.freezed.dart';
|
||||||
|
part 'landmark_type.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class LandmarkType with _$LandmarkType {
|
||||||
|
const factory LandmarkType({
|
||||||
|
required LandmarkTypeEnum type,
|
||||||
|
}) = _LandmarkType;
|
||||||
|
|
||||||
|
factory LandmarkType.fromJson(Map<String, Object?> json) => _$LandmarkTypeFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonEnum(alwaysCreate: true)
|
||||||
|
enum LandmarkTypeEnum {
|
||||||
|
@JsonValue('culture')
|
||||||
|
culture,
|
||||||
|
@JsonValue('nature')
|
||||||
|
nature,
|
||||||
|
@JsonValue('shopping')
|
||||||
|
shopping,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension LandmarkTypeEnumExtension on LandmarkTypeEnum {
|
||||||
|
String get value => _$LandmarkTypeEnumEnumMap[this]!;
|
||||||
|
}
|
||||||
315
frontend/lib/domain/entities/landmark_type.freezed.dart
Normal file
315
frontend/lib/domain/entities/landmark_type.freezed.dart
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'landmark_type.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$LandmarkType {
|
||||||
|
LandmarkTypeEnum get type;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkType
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$LandmarkTypeCopyWith<LandmarkType> get copyWith =>
|
||||||
|
_$LandmarkTypeCopyWithImpl<LandmarkType>(
|
||||||
|
this as LandmarkType, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this LandmarkType to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is LandmarkType &&
|
||||||
|
(identical(other.type, type) || other.type == type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, type);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LandmarkType(type: $type)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $LandmarkTypeCopyWith<$Res> {
|
||||||
|
factory $LandmarkTypeCopyWith(
|
||||||
|
LandmarkType value, $Res Function(LandmarkType) _then) =
|
||||||
|
_$LandmarkTypeCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({LandmarkTypeEnum type});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$LandmarkTypeCopyWithImpl<$Res> implements $LandmarkTypeCopyWith<$Res> {
|
||||||
|
_$LandmarkTypeCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final LandmarkType _self;
|
||||||
|
final $Res Function(LandmarkType) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkType
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? type = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LandmarkTypeEnum,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [LandmarkType].
|
||||||
|
extension LandmarkTypePatterns on LandmarkType {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>(
|
||||||
|
TResult Function(_LandmarkType value)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkType() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>(
|
||||||
|
TResult Function(_LandmarkType value) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkType():
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(_LandmarkType value)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkType() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>(
|
||||||
|
TResult Function(LandmarkTypeEnum type)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkType() when $default != null:
|
||||||
|
return $default(_that.type);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>(
|
||||||
|
TResult Function(LandmarkTypeEnum type) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkType():
|
||||||
|
return $default(_that.type);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(LandmarkTypeEnum type)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _LandmarkType() when $default != null:
|
||||||
|
return $default(_that.type);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _LandmarkType implements LandmarkType {
|
||||||
|
const _LandmarkType({required this.type});
|
||||||
|
factory _LandmarkType.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$LandmarkTypeFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final LandmarkTypeEnum type;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkType
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$LandmarkTypeCopyWith<_LandmarkType> get copyWith =>
|
||||||
|
__$LandmarkTypeCopyWithImpl<_LandmarkType>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$LandmarkTypeToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _LandmarkType &&
|
||||||
|
(identical(other.type, type) || other.type == type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, type);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'LandmarkType(type: $type)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$LandmarkTypeCopyWith<$Res>
|
||||||
|
implements $LandmarkTypeCopyWith<$Res> {
|
||||||
|
factory _$LandmarkTypeCopyWith(
|
||||||
|
_LandmarkType value, $Res Function(_LandmarkType) _then) =
|
||||||
|
__$LandmarkTypeCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({LandmarkTypeEnum type});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$LandmarkTypeCopyWithImpl<$Res>
|
||||||
|
implements _$LandmarkTypeCopyWith<$Res> {
|
||||||
|
__$LandmarkTypeCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _LandmarkType _self;
|
||||||
|
final $Res Function(_LandmarkType) _then;
|
||||||
|
|
||||||
|
/// Create a copy of LandmarkType
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? type = null,
|
||||||
|
}) {
|
||||||
|
return _then(_LandmarkType(
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as LandmarkTypeEnum,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
23
frontend/lib/domain/entities/landmark_type.g.dart
Normal file
23
frontend/lib/domain/entities/landmark_type.g.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'landmark_type.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_LandmarkType _$LandmarkTypeFromJson(Map<String, dynamic> json) =>
|
||||||
|
_LandmarkType(
|
||||||
|
type: $enumDecode(_$LandmarkTypeEnumEnumMap, json['type']),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$LandmarkTypeToJson(_LandmarkType instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'type': _$LandmarkTypeEnumEnumMap[instance.type]!,
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$LandmarkTypeEnumEnumMap = {
|
||||||
|
LandmarkTypeEnum.culture: 'culture',
|
||||||
|
LandmarkTypeEnum.nature: 'nature',
|
||||||
|
LandmarkTypeEnum.shopping: 'shopping',
|
||||||
|
};
|
||||||
12
frontend/lib/domain/entities/preferences.dart
Normal file
12
frontend/lib/domain/entities/preferences.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
part 'preferences.freezed.dart';
|
||||||
|
part 'preferences.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Preferences with _$Preferences {
|
||||||
|
const factory Preferences({
|
||||||
|
required String test,
|
||||||
|
}) = _Preferences;
|
||||||
|
|
||||||
|
factory Preferences.fromJson(Map<String, Object?> json) => _$PreferencesFromJson(json);
|
||||||
|
}
|
||||||
313
frontend/lib/domain/entities/preferences.freezed.dart
Normal file
313
frontend/lib/domain/entities/preferences.freezed.dart
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'preferences.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$Preferences {
|
||||||
|
String get test;
|
||||||
|
|
||||||
|
/// Create a copy of Preferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$PreferencesCopyWith<Preferences> get copyWith =>
|
||||||
|
_$PreferencesCopyWithImpl<Preferences>(this as Preferences, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this Preferences to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is Preferences &&
|
||||||
|
(identical(other.test, test) || other.test == test));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Preferences(test: $test)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $PreferencesCopyWith<$Res> {
|
||||||
|
factory $PreferencesCopyWith(
|
||||||
|
Preferences value, $Res Function(Preferences) _then) =
|
||||||
|
_$PreferencesCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({String test});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$PreferencesCopyWithImpl<$Res> implements $PreferencesCopyWith<$Res> {
|
||||||
|
_$PreferencesCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final Preferences _self;
|
||||||
|
final $Res Function(Preferences) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Preferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? test = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
test: null == test
|
||||||
|
? _self.test
|
||||||
|
: test // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [Preferences].
|
||||||
|
extension PreferencesPatterns on Preferences {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>(
|
||||||
|
TResult Function(_Preferences value)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Preferences() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>(
|
||||||
|
TResult Function(_Preferences value) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Preferences():
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(_Preferences value)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Preferences() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>(
|
||||||
|
TResult Function(String test)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Preferences() when $default != null:
|
||||||
|
return $default(_that.test);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>(
|
||||||
|
TResult Function(String test) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Preferences():
|
||||||
|
return $default(_that.test);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(String test)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Preferences() when $default != null:
|
||||||
|
return $default(_that.test);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _Preferences implements Preferences {
|
||||||
|
const _Preferences({required this.test});
|
||||||
|
factory _Preferences.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$PreferencesFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String test;
|
||||||
|
|
||||||
|
/// Create a copy of Preferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$PreferencesCopyWith<_Preferences> get copyWith =>
|
||||||
|
__$PreferencesCopyWithImpl<_Preferences>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$PreferencesToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _Preferences &&
|
||||||
|
(identical(other.test, test) || other.test == test));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, test);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Preferences(test: $test)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$PreferencesCopyWith<$Res>
|
||||||
|
implements $PreferencesCopyWith<$Res> {
|
||||||
|
factory _$PreferencesCopyWith(
|
||||||
|
_Preferences value, $Res Function(_Preferences) _then) =
|
||||||
|
__$PreferencesCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String test});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$PreferencesCopyWithImpl<$Res> implements _$PreferencesCopyWith<$Res> {
|
||||||
|
__$PreferencesCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _Preferences _self;
|
||||||
|
final $Res Function(_Preferences) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Preferences
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? test = null,
|
||||||
|
}) {
|
||||||
|
return _then(_Preferences(
|
||||||
|
test: null == test
|
||||||
|
? _self.test
|
||||||
|
: test // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
16
frontend/lib/domain/entities/preferences.g.dart
Normal file
16
frontend/lib/domain/entities/preferences.g.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'preferences.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_Preferences _$PreferencesFromJson(Map<String, dynamic> json) => _Preferences(
|
||||||
|
test: json['test'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$PreferencesToJson(_Preferences instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'test': instance.test,
|
||||||
|
};
|
||||||
19
frontend/lib/domain/entities/trip.dart
Normal file
19
frontend/lib/domain/entities/trip.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:anyway/domain/entities/landmark.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'trip.freezed.dart';
|
||||||
|
part 'trip.g.dart';
|
||||||
|
|
||||||
|
|
||||||
|
@Freezed(makeCollectionsUnmodifiable: false)
|
||||||
|
abstract class Trip with _$Trip {
|
||||||
|
|
||||||
|
const factory Trip({
|
||||||
|
required String uuid,
|
||||||
|
// Duration totalTime,
|
||||||
|
required List<Landmark> landmarks,
|
||||||
|
}) = _Trip;
|
||||||
|
|
||||||
|
factory Trip.fromJson(Map<String, Object?> json) => _$TripFromJson(json);
|
||||||
|
|
||||||
|
}
|
||||||
327
frontend/lib/domain/entities/trip.freezed.dart
Normal file
327
frontend/lib/domain/entities/trip.freezed.dart
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// 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 'trip.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$Trip {
|
||||||
|
String get uuid; // Duration totalTime,
|
||||||
|
List<Landmark> get landmarks;
|
||||||
|
|
||||||
|
/// Create a copy of Trip
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$TripCopyWith<Trip> get copyWith =>
|
||||||
|
_$TripCopyWithImpl<Trip>(this as Trip, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this Trip to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is Trip &&
|
||||||
|
(identical(other.uuid, uuid) || other.uuid == uuid) &&
|
||||||
|
const DeepCollectionEquality().equals(other.landmarks, landmarks));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType, uuid, const DeepCollectionEquality().hash(landmarks));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Trip(uuid: $uuid, landmarks: $landmarks)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $TripCopyWith<$Res> {
|
||||||
|
factory $TripCopyWith(Trip value, $Res Function(Trip) _then) =
|
||||||
|
_$TripCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({String uuid, List<Landmark> landmarks});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$TripCopyWithImpl<$Res> implements $TripCopyWith<$Res> {
|
||||||
|
_$TripCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final Trip _self;
|
||||||
|
final $Res Function(Trip) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Trip
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? uuid = null,
|
||||||
|
Object? landmarks = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
uuid: null == uuid
|
||||||
|
? _self.uuid
|
||||||
|
: uuid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
landmarks: null == landmarks
|
||||||
|
? _self.landmarks
|
||||||
|
: landmarks // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Landmark>,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [Trip].
|
||||||
|
extension TripPatterns on Trip {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>(
|
||||||
|
TResult Function(_Trip value)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Trip() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>(
|
||||||
|
TResult Function(_Trip value) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Trip():
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(_Trip value)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Trip() when $default != null:
|
||||||
|
return $default(_that);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>(
|
||||||
|
TResult Function(String uuid, List<Landmark> landmarks)? $default, {
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Trip() when $default != null:
|
||||||
|
return $default(_that.uuid, _that.landmarks);
|
||||||
|
case _:
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>(
|
||||||
|
TResult Function(String uuid, List<Landmark> landmarks) $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Trip():
|
||||||
|
return $default(_that.uuid, _that.landmarks);
|
||||||
|
case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>(
|
||||||
|
TResult? Function(String uuid, List<Landmark> landmarks)? $default,
|
||||||
|
) {
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Trip() when $default != null:
|
||||||
|
return $default(_that.uuid, _that.landmarks);
|
||||||
|
case _:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _Trip implements Trip {
|
||||||
|
const _Trip({required this.uuid, required this.landmarks});
|
||||||
|
factory _Trip.fromJson(Map<String, dynamic> json) => _$TripFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String uuid;
|
||||||
|
// Duration totalTime,
|
||||||
|
@override
|
||||||
|
final List<Landmark> landmarks;
|
||||||
|
|
||||||
|
/// Create a copy of Trip
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$TripCopyWith<_Trip> get copyWith =>
|
||||||
|
__$TripCopyWithImpl<_Trip>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$TripToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _Trip &&
|
||||||
|
(identical(other.uuid, uuid) || other.uuid == uuid) &&
|
||||||
|
const DeepCollectionEquality().equals(other.landmarks, landmarks));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType, uuid, const DeepCollectionEquality().hash(landmarks));
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Trip(uuid: $uuid, landmarks: $landmarks)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$TripCopyWith<$Res> implements $TripCopyWith<$Res> {
|
||||||
|
factory _$TripCopyWith(_Trip value, $Res Function(_Trip) _then) =
|
||||||
|
__$TripCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String uuid, List<Landmark> landmarks});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$TripCopyWithImpl<$Res> implements _$TripCopyWith<$Res> {
|
||||||
|
__$TripCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _Trip _self;
|
||||||
|
final $Res Function(_Trip) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Trip
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? uuid = null,
|
||||||
|
Object? landmarks = null,
|
||||||
|
}) {
|
||||||
|
return _then(_Trip(
|
||||||
|
uuid: null == uuid
|
||||||
|
? _self.uuid
|
||||||
|
: uuid // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
landmarks: null == landmarks
|
||||||
|
? _self.landmarks
|
||||||
|
: landmarks // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<Landmark>,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
19
frontend/lib/domain/entities/trip.g.dart
Normal file
19
frontend/lib/domain/entities/trip.g.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'trip.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_Trip _$TripFromJson(Map<String, dynamic> json) => _Trip(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
landmarks: (json['landmarks'] as List<dynamic>)
|
||||||
|
.map((e) => Landmark.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$TripToJson(_Trip instance) => <String, dynamic>{
|
||||||
|
'uuid': instance.uuid,
|
||||||
|
'landmarks': instance.landmarks,
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import 'package:anyway/domain/entities/preferences.dart';
|
||||||
|
|
||||||
|
abstract class PreferencesRepository {
|
||||||
|
Future<Preferences> getPreferences();
|
||||||
|
}
|
||||||
6
frontend/lib/domain/repositories/trip_repository.dart
Normal file
6
frontend/lib/domain/repositories/trip_repository.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:anyway/domain/entities/preferences.dart';
|
||||||
|
import 'package:anyway/domain/entities/trip.dart';
|
||||||
|
|
||||||
|
abstract class TripRepository {
|
||||||
|
Future<Trip> getTrip({Preferences? preferences, String? tripUUID});
|
||||||
|
}
|
||||||
@@ -1,26 +1,39 @@
|
|||||||
|
import 'package:anyway/presentation/pages/start.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/core/constants.dart';
|
||||||
import 'package:anyway/utils/get_first_page.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:anyway/utils/load_trips.dart';
|
|
||||||
|
|
||||||
|
|
||||||
void main() => runApp(const App());
|
/// The app entry point.
|
||||||
|
/// Initializes persistence, sets up dependency injection via ProviderScope,
|
||||||
|
/// and determines which screen (login or main app) to show based on auth state.
|
||||||
|
Future<void> main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
// Some global variables
|
// initialize local persistence (shared preferences)
|
||||||
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
final SavedTrips savedTrips = SavedTrips();
|
|
||||||
// the list of saved trips is then populated implicitly by getFirstPage()
|
|
||||||
|
|
||||||
|
// the app wrapped in ProviderScope
|
||||||
|
runApp(const ProviderScope(child: MyApp()));
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends ConsumerWidget {
|
||||||
|
const MyApp({super.key});
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
|
||||||
const App({super.key});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => MaterialApp(
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
title: APP_NAME,
|
|
||||||
home: getFirstPage(),
|
return MaterialApp(
|
||||||
theme: APP_THEME,
|
debugShowCheckedModeBanner: false,
|
||||||
scaffoldMessengerKey: rootScaffoldMessengerKey
|
title: APP_NAME,
|
||||||
);
|
theme: APP_THEME,
|
||||||
|
scaffoldMessengerKey: rootScaffoldMessengerKey,
|
||||||
|
home: const StartPage()
|
||||||
|
|
||||||
|
// TODO - set up routing
|
||||||
|
// onGenerateRoute: AppRouter.onGenerateRoute,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
frontend/lib/presentation/pages/create_trip.dart
Normal file
50
frontend/lib/presentation/pages/create_trip.dart
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class NewTripPage extends StatefulWidget {
|
||||||
|
const NewTripPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_NewTripPageState createState() => _NewTripPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class _NewTripPageState extends State<NewTripPage> {
|
||||||
|
int _currentStep = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Create New Trip'),
|
||||||
|
),
|
||||||
|
body: Stepper(
|
||||||
|
currentStep: _currentStep,
|
||||||
|
onStepContinue: () {
|
||||||
|
if (_currentStep < 1) {
|
||||||
|
setState(() {
|
||||||
|
_currentStep += 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onStepCancel: () {
|
||||||
|
if (_currentStep > 0) {
|
||||||
|
setState(() {
|
||||||
|
_currentStep -= 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
Step(
|
||||||
|
title: const Text('Select Location'),
|
||||||
|
content: const MapWithSearchField(), // Replace with your map module
|
||||||
|
isActive: _currentStep >= 0,
|
||||||
|
),
|
||||||
|
Step(
|
||||||
|
title: const Text('Choose Options'),
|
||||||
|
content: const OptionsList(), // Replace with your options module
|
||||||
|
isActive: _currentStep >= 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
12
frontend/lib/presentation/pages/login.dart
Normal file
12
frontend/lib/presentation/pages/login.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class LoginPage extends StatelessWidget {
|
||||||
|
const LoginPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(child: Text('Login Page')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/core/constants.dart';
|
||||||
import 'package:anyway/modules/onbarding_agreement_card.dart';
|
import 'package:anyway/presentation/providers/onboarding_state_provider.dart';
|
||||||
import 'package:anyway/modules/onboarding_card.dart';
|
import 'package:anyway/presentation/widgets/onbarding_agreement_card.dart';
|
||||||
import 'package:anyway/pages/new_trip_location.dart';
|
import 'package:anyway/presentation/widgets/onboarding_card.dart';
|
||||||
import 'package:anyway/structs/agreement.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
|
||||||
List<Widget> onboardingCards = [
|
List<Widget> onboardingCards = [
|
||||||
@@ -33,14 +32,14 @@ List<Widget> onboardingCards = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
class OnboardingPage extends StatefulWidget {
|
class OnboardingPage extends ConsumerStatefulWidget {
|
||||||
const OnboardingPage({super.key});
|
const OnboardingPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<OnboardingPage> createState() => _OnboardingPageState();
|
ConsumerState<OnboardingPage> createState() => _OnboardingPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OnboardingPageState extends State<OnboardingPage> {
|
class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
||||||
final PageController _controller = PageController();
|
final PageController _controller = PageController();
|
||||||
late List<Widget> fullCards;
|
late List<Widget> fullCards;
|
||||||
|
|
||||||
@@ -121,41 +120,53 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||||||
label: const Icon(Icons.arrow_forward)
|
label: const Icon(Icons.arrow_forward)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// only allow the user to proceed if they have agreed to the terms and conditions
|
// only allow the user to proceed if they have agreed to the terms and conditions
|
||||||
Future<bool> hasAgreed = getAgreement().then((agreement) => agreement.agreed);
|
// the information is accessible through ref.watch(onboardingStateProvider)
|
||||||
|
|
||||||
return FutureBuilder(
|
Widget disabledWidget = FloatingActionButton.extended(
|
||||||
future: hasAgreed,
|
onPressed: null,
|
||||||
builder: (context, snapshot){
|
label: const Row(
|
||||||
if (snapshot.hasData && snapshot.data!) {
|
children: [
|
||||||
return FloatingActionButton.extended(
|
Text("Start planning!"),
|
||||||
onPressed: () {
|
Padding(padding: EdgeInsets.only(right: 8.0)),
|
||||||
Navigator.of(context).push(
|
Icon(Icons.map_outlined)
|
||||||
MaterialPageRoute(
|
],
|
||||||
builder: (context) => const NewTripPage()
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
},
|
return ref.watch(onboardingStateProvider).when(
|
||||||
label: const Row(
|
data: (isOnboarded) {
|
||||||
children: [
|
if (isOnboarded) {
|
||||||
Text("Start planning!"),
|
return FloatingActionButton.extended(
|
||||||
Padding(padding: EdgeInsets.only(right: 8.0)),
|
onPressed: () {
|
||||||
Icon(Icons.map_outlined)
|
// proceed to the next page - pop the onboarding page so the StartPage can decide what to show next
|
||||||
],
|
Navigator.of(context).pop();
|
||||||
)
|
},
|
||||||
);
|
label: const Row(
|
||||||
} else {
|
children: [
|
||||||
return Container();
|
Text("Start planning!"),
|
||||||
}
|
Padding(padding: EdgeInsets.only(right: 8.0)),
|
||||||
}
|
Icon(Icons.map_outlined)
|
||||||
);
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return disabledWidget;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loading: () => disabledWidget,
|
||||||
|
error: (error, stack) => disabledWidget,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
void onAgreementChanged(bool value) async {
|
void onAgreementChanged(bool value) async {
|
||||||
saveAgreement(value);
|
await ref.read(onboardingControllerProvider).setOnboarded(value);
|
||||||
// Update the state of the OnboardingPage
|
|
||||||
setState(() {});
|
setState(() {
|
||||||
|
// rebuild to show the next button
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
97
frontend/lib/presentation/pages/start.dart
Normal file
97
frontend/lib/presentation/pages/start.dart
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:anyway/presentation/providers/onboarding_state_provider.dart';
|
||||||
|
import 'package:anyway/presentation/pages/login.dart';
|
||||||
|
import 'package:anyway/presentation/pages/onboarding.dart';
|
||||||
|
|
||||||
|
// Example providers (replace these with your actual providers)
|
||||||
|
// final onboardingStateProvider = Provider<bool>((ref) => true); // Replace with actual onboarding state logic
|
||||||
|
final authStateProvider = FutureProvider<bool>((ref) async => true); // Replace with actual auth state logic
|
||||||
|
final tripsAvailableProvider = FutureProvider<bool>((ref) async => false); // Replace with actual trips availability logic
|
||||||
|
|
||||||
|
class StartPage extends ConsumerWidget {
|
||||||
|
const StartPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
|
||||||
|
// the home page is dependent on the state of the providers:
|
||||||
|
// - if the user is not onboarded, show the onboarding flow
|
||||||
|
// - if the user is not logged in, show the login page
|
||||||
|
// - if there are no trips available, show the trip creation page
|
||||||
|
// - else: show the overview page that shows the last trip
|
||||||
|
|
||||||
|
final onboardingState = ref.watch(onboardingStateProvider);
|
||||||
|
final authState = ref.watch(authStateProvider);
|
||||||
|
final tripsAvailable = ref.watch(tripsAvailableProvider);
|
||||||
|
|
||||||
|
return onboardingState.when(
|
||||||
|
data: (isOnboarded) {
|
||||||
|
if (!isOnboarded) {
|
||||||
|
return const OnboardingPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return authState.when(
|
||||||
|
data: (isLoggedIn) {
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
return const LoginPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tripsAvailable.when(
|
||||||
|
data: (hasTrips) {
|
||||||
|
if (!hasTrips) {
|
||||||
|
return const TripCreationPage();
|
||||||
|
}
|
||||||
|
return const OverviewPage();
|
||||||
|
},
|
||||||
|
loading: () => const Scaffold(
|
||||||
|
body: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error: (error, stack) => Scaffold(
|
||||||
|
body: Center(child: Text('Error: $error')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const Scaffold(
|
||||||
|
body: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error: (error, stack) => Scaffold(
|
||||||
|
body: Center(child: Text('Error: $error')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const Scaffold(
|
||||||
|
body: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error: (error, stack) => Scaffold(
|
||||||
|
body: Center(child: Text('Error: $error')
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TripCreationPage extends StatelessWidget {
|
||||||
|
const TripCreationPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(child: Text('Trip Creation Page')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OverviewPage extends StatelessWidget {
|
||||||
|
const OverviewPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(child: Text('Overview Page')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
final onboardingStateProvider = FutureProvider<bool>((ref) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
return prefs.getBool('onboardingCompleted') ?? false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
final onboardingControllerProvider = Provider<OnboardingController>((ref) {
|
||||||
|
return OnboardingController(ref);
|
||||||
|
});
|
||||||
|
|
||||||
|
class OnboardingController {
|
||||||
|
final Ref ref;
|
||||||
|
OnboardingController(this.ref);
|
||||||
|
|
||||||
|
Future<void> setOnboarded(bool value) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setBool('onboardingCompleted', value);
|
||||||
|
// refresh the read provider so UI updates
|
||||||
|
ref.invalidate(onboardingStateProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
frontend/lib/presentation/providers/trip_provider.dart
Normal file
6
frontend/lib/presentation/providers/trip_provider.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// import 'package:anyway/data/repositories/trip_repository.dart';
|
||||||
|
// import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
// final weatherRepositoryProvider = Provider<TripRepository>((ref) {
|
||||||
|
// return TripRepositoryImpl(???);
|
||||||
|
// });
|
||||||
23
frontend/lib/presentation/widgets/create_trip_location.dart
Normal file
23
frontend/lib/presentation/widgets/create_trip_location.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:your_project/models/trip_request.dart';
|
||||||
|
import 'package:your_project/presentation/widgets/new_trip_map.dart';
|
||||||
|
import 'package:your_project/presentation/widgets/new_trip_location_search.dart';
|
||||||
|
|
||||||
|
class CreateTripLocation extends StatelessWidget {
|
||||||
|
final TripRequest tripRequest;
|
||||||
|
|
||||||
|
const CreateTripLocation(this.tripRequest, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
NewTripMap(tripRequest),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
child: NewTripLocationSearch(tripRequest),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
105
frontend/lib/presentation/widgets/create_trip_location_map.dart
Normal file
105
frontend/lib/presentation/widgets/create_trip_location_map.dart
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// A map that allows the user to select a location for a new trip.
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:widget_to_marker/widget_to_marker.dart';
|
||||||
|
|
||||||
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:anyway/structs/landmark.dart';
|
||||||
|
import 'package:anyway/modules/landmark_map_marker.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class NewTripMap extends StatefulWidget {
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NewTripMap> createState() => _NewTripMapState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NewTripMapState extends State<NewTripMap> {
|
||||||
|
final CameraPosition _cameraPosition = const CameraPosition(
|
||||||
|
target: LatLng(48.8566, 2.3522),
|
||||||
|
zoom: 11.0,
|
||||||
|
);
|
||||||
|
GoogleMapController? _mapController;
|
||||||
|
final Set<Marker> _markers = <Marker>{};
|
||||||
|
|
||||||
|
_onLongPress(LatLng location) {
|
||||||
|
// widget.trip.landmarks.clear();
|
||||||
|
// widget.trip.addLandmark(
|
||||||
|
// Landmark(
|
||||||
|
// uuid: 'pending',
|
||||||
|
// name: 'start',
|
||||||
|
// location: [location.latitude, location.longitude],
|
||||||
|
// type: typeStart
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTripDetails() async {
|
||||||
|
_markers.clear();
|
||||||
|
if (widget.trip.landmarks.isNotEmpty) {
|
||||||
|
Landmark landmark = widget.trip.landmarks.first;
|
||||||
|
_markers.add(
|
||||||
|
Marker(
|
||||||
|
markerId: MarkerId(landmark.uuid),
|
||||||
|
position: LatLng(landmark.location[0], landmark.location[1]),
|
||||||
|
icon: await ThemedMarker(landmark: landmark, position: 0).toBitmapDescriptor(
|
||||||
|
logicalSize: const Size(150, 150),
|
||||||
|
imageSize: const Size(150, 150)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// check if the controller is ready
|
||||||
|
|
||||||
|
if (_mapController != null) {
|
||||||
|
_mapController!.animateCamera(
|
||||||
|
CameraUpdate.newLatLng(
|
||||||
|
LatLng(landmark.location[0], landmark.location[1])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onMapCreated(GoogleMapController controller) async {
|
||||||
|
_mapController = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
widget.trip.addListener(updateTripDetails);
|
||||||
|
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
|
||||||
|
return FutureBuilder(
|
||||||
|
future: preferences,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
SharedPreferences prefs = snapshot.data as SharedPreferences;
|
||||||
|
bool useLocation = prefs.getBool('useLocation') ?? true;
|
||||||
|
return _buildMap(useLocation);
|
||||||
|
} else {
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMap(bool useLocation) {
|
||||||
|
return GoogleMap(
|
||||||
|
onMapCreated: _onMapCreated,
|
||||||
|
initialCameraPosition: _cameraPosition,
|
||||||
|
onLongPress: _onLongPress,
|
||||||
|
markers: _markers,
|
||||||
|
cloudMapId: MAP_ID,
|
||||||
|
mapToolbarEnabled: false,
|
||||||
|
zoomControlsEnabled: false,
|
||||||
|
myLocationButtonEnabled: false,
|
||||||
|
myLocationEnabled: useLocation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
|
||||||
|
// A search bar that allow the user to enter a city name
|
||||||
|
import 'dart:developer';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:geocoding/geocoding.dart';
|
||||||
|
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
const Map<String, List> debugLocations = {
|
||||||
|
'paris': [48.8575, 2.3514],
|
||||||
|
'london': [51.5074, -0.1278],
|
||||||
|
'new york': [40.7128, -74.0060],
|
||||||
|
'tokyo': [35.6895, 139.6917],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class NewTripLocationSearch extends StatefulWidget {
|
||||||
|
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
|
||||||
|
Trip trip;
|
||||||
|
|
||||||
|
NewTripLocationSearch(
|
||||||
|
this.trip,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NewTripLocationSearch> createState() => _NewTripLocationSearchState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
|
||||||
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
|
||||||
|
setTripLocation (String query) async {
|
||||||
|
List<Location> locations = [];
|
||||||
|
Location startLocation;
|
||||||
|
log('Searching for: $query');
|
||||||
|
if (GeocodingPlatform.instance != null) {
|
||||||
|
locations.addAll(await locationFromAddress(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locations.isNotEmpty) {
|
||||||
|
startLocation = locations.first;
|
||||||
|
} else {
|
||||||
|
log('No results found for: $query. Is geocoding available?');
|
||||||
|
log('Setting Fallback location');
|
||||||
|
List coordinates = debugLocations[query.toLowerCase()] ?? [48.8575, 2.3514];
|
||||||
|
startLocation = Location(
|
||||||
|
latitude: coordinates[0],
|
||||||
|
longitude: coordinates[1],
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.trip.landmarks.clear();
|
||||||
|
widget.trip.addLandmark(
|
||||||
|
Landmark(
|
||||||
|
uuid: 'pending',
|
||||||
|
name: query,
|
||||||
|
location: [startLocation.latitude, startLocation.longitude],
|
||||||
|
type: typeStart
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
late Widget locationSearchBar = SearchBar(
|
||||||
|
hintText: 'Enter a city name or long press on the map.',
|
||||||
|
onSubmitted: setTripLocation,
|
||||||
|
controller: _controller,
|
||||||
|
leading: const Icon(Icons.search),
|
||||||
|
trailing: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setTripLocation(_controller.text);
|
||||||
|
},
|
||||||
|
child: const Text('Search'),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
late Widget useCurrentLocationButton = ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
// this widget is only shown if the user has already granted location permissions
|
||||||
|
Position position = await Geolocator.getCurrentPosition();
|
||||||
|
widget.trip.landmarks.clear();
|
||||||
|
widget.trip.addLandmark(
|
||||||
|
Landmark(
|
||||||
|
uuid: 'pending',
|
||||||
|
name: 'start',
|
||||||
|
location: [position.latitude, position.longitude],
|
||||||
|
type: typeStart
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const Text('Use current location'),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder(
|
||||||
|
future: widget.prefs,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
final useLocation = snapshot.data!.getBool('useLocation') ?? false;
|
||||||
|
if (useLocation) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
locationSearchBar,
|
||||||
|
useCurrentLocationButton,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return locationSearchBar;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return locationSearchBar;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
121
frontend/lib/presentation/widgets/onbarding_agreement_card.dart
Normal file
121
frontend/lib/presentation/widgets/onbarding_agreement_card.dart
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
||||||
|
import 'package:anyway/presentation/providers/onboarding_state_provider.dart';
|
||||||
|
import 'package:anyway/presentation/widgets/onboarding_card.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OnboardingAgreementCard extends ConsumerStatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
final String imagePath;
|
||||||
|
final String agreementTextPath;
|
||||||
|
final ValueChanged<bool> onAgreementChanged;
|
||||||
|
|
||||||
|
|
||||||
|
const OnboardingAgreementCard({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
required this.imagePath,
|
||||||
|
required this.agreementTextPath,
|
||||||
|
required this.onAgreementChanged
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<OnboardingAgreementCard> createState() => _OnboardingAgreementCardState();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OnboardingAgreementCardState extends ConsumerState<OnboardingAgreementCard> {
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void initState() {
|
||||||
|
// super.initState();
|
||||||
|
// // You can use ref here if needed in initState
|
||||||
|
// }
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
OnboardingCard(title: widget.title, description: widget.description, imagePath: widget.imagePath),
|
||||||
|
const Padding(padding: EdgeInsets.only(top: 20)),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// The checkbox of the agreement
|
||||||
|
FutureBuilder(
|
||||||
|
future: ref.read(onboardingStateProvider.future),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
bool agreed = false;
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
agreed = snapshot.data!;
|
||||||
|
}
|
||||||
|
return Checkbox(
|
||||||
|
value: agreed,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
if (value != null) {
|
||||||
|
widget.onAgreementChanged(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeColor: Colors.white,
|
||||||
|
checkColor: Colors.black,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// The text of the agreement
|
||||||
|
Text(
|
||||||
|
"I agree to the ",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// The clickable text of the agreement that shows the agreement text
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// show a dialog with the agreement text
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
scrollable: true,
|
||||||
|
content: FutureBuilder(
|
||||||
|
future: DefaultAssetBundle.of(context).loadString(widget.agreementTextPath),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
return MarkdownBody(
|
||||||
|
data: snapshot.data.toString(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"Terms of Service (click to view)",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
frontend/lib/presentation/widgets/onboarding_card.dart
Normal file
45
frontend/lib/presentation/widgets/onboarding_card.dart
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
|
class OnboardingCard extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
final String imagePath;
|
||||||
|
|
||||||
|
const OnboardingCard({super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
required this.imagePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Padding(padding: EdgeInsets.only(top: 20)),
|
||||||
|
SvgPicture.asset(
|
||||||
|
imagePath,
|
||||||
|
height: 200,
|
||||||
|
),
|
||||||
|
const Padding(padding: EdgeInsets.only(top: 20)),
|
||||||
|
Text(
|
||||||
|
description,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -19,8 +19,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.3.4 <4.0.0'
|
sdk: ^3.8.0
|
||||||
flutter: '3.29.1'
|
flutter: '3.32.0'
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
@@ -32,7 +32,6 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
@@ -42,18 +41,20 @@ dependencies:
|
|||||||
dio: ^5.5.0+1
|
dio: ^5.5.0+1
|
||||||
google_maps_flutter: ^2.7.0
|
google_maps_flutter: ^2.7.0
|
||||||
cached_network_image: ^3.4.0
|
cached_network_image: ^3.4.0
|
||||||
geocoding: ^3.0.0
|
geocoding: ^4.0.0
|
||||||
widget_to_marker: ^1.0.6
|
widget_to_marker: ^1.0.6
|
||||||
provider: ^6.1.2
|
|
||||||
auto_size_text: ^3.0.0
|
auto_size_text: ^3.0.0
|
||||||
map_launcher: ^3.3.1
|
# map_launcher: ^4.4.2
|
||||||
flutter_svg: ^2.0.10+1
|
flutter_svg: ^2.0.10+1
|
||||||
url_launcher: ^6.3.0
|
url_launcher: ^6.3.0
|
||||||
flutter_launcher_icons: ^0.13.1
|
flutter_launcher_icons: ^0.14.4
|
||||||
permission_handler: ^11.3.1
|
permission_handler: ^12.0.1
|
||||||
geolocator: ^13.0.1
|
geolocator: ^14.0.2
|
||||||
fuzzywuzzy: ^1.2.0
|
freezed_annotation: ^3.1.0
|
||||||
flutter_markdown: ^0.7.6+2
|
json_annotation: ^4.9.0
|
||||||
|
uuid: ^4.5.1
|
||||||
|
flutter_riverpod: ^3.0.3
|
||||||
|
flutter_markdown_plus: ^1.0.5
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -64,7 +65,12 @@ dev_dependencies:
|
|||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^4.0.0
|
flutter_lints: ^6.0.0
|
||||||
|
build_runner:
|
||||||
|
freezed: ^3.2.3
|
||||||
|
json_serializable: ^6.11.1
|
||||||
|
custom_lint:
|
||||||
|
riverpod_lint: ^3.0.3
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|||||||
Reference in New Issue
Block a user