Compare commits
No commits in common. "c4fddc1a575b1dd22c5f0ba82173a5a5b2a8ea7e" and "d31ca9f81fb9cd85cf9a2f5399be6b6299bd90b9" have entirely different histories.
c4fddc1a57
...
d31ca9f81f
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
@ -36,10 +36,7 @@
|
|||||||
"type": "dart",
|
"type": "dart",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "lib/main.dart",
|
"program": "lib/main.dart",
|
||||||
"cwd": "${workspaceFolder}/frontend",
|
"cwd": "${workspaceFolder}/frontend"
|
||||||
"env": {
|
|
||||||
"GOOGLE_MAPS_API_KEY": "testing"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Frontend - profile",
|
"name": "Frontend - profile",
|
||||||
|
@ -19,7 +19,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "8.1.0" apply false
|
id "com.android.application" version "7.3.0" apply false
|
||||||
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
|
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
|
||||||
import 'package:anyway/utils/get_first_page.dart';
|
import 'package:anyway/utils/get_first_page.dart';
|
||||||
import 'package:anyway/utils/load_trips.dart';
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
void main() => runApp(const App());
|
void main() => runApp(const App());
|
||||||
|
|
||||||
// Some global variables
|
|
||||||
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||||
final SavedTrips savedTrips = SavedTrips();
|
final SavedTrips savedTrips = SavedTrips();
|
||||||
// the list of saved trips is then populated implicitly by getFirstPage()
|
|
||||||
|
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
class App extends StatelessWidget {
|
||||||
const App({super.key});
|
const App({super.key});
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => MaterialApp(
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
title: APP_NAME,
|
title: APP_NAME,
|
||||||
home: getFirstPage(),
|
home: getFirstPage(),
|
||||||
theme: APP_THEME,
|
theme: APP_THEME,
|
||||||
scaffoldMessengerKey: rootScaffoldMessengerKey
|
scaffoldMessengerKey: rootScaffoldMessengerKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'package:anyway/modules/step_between_landmarks.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:anyway/modules/landmark_card.dart';
|
||||||
import 'package:anyway/structs/landmark.dart';
|
import 'package:anyway/structs/landmark.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/modules/step_between_landmarks.dart';
|
|
||||||
import 'package:anyway/modules/landmark_card.dart';
|
|
||||||
|
|
||||||
|
|
||||||
// Returns a list of widgets that represent the landmarks matching the given selector
|
|
||||||
List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector}) {
|
List<Widget> landmarksList(Trip trip) {
|
||||||
|
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||||
|
|
||||||
List<Widget> children = [];
|
List<Widget> children = [];
|
||||||
|
|
||||||
|
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||||
|
|
||||||
if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) {
|
if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) {
|
||||||
children.add(
|
children.add(
|
||||||
const Text("No landmarks in this trip"),
|
const Text("No landmarks in this trip"),
|
||||||
@ -21,24 +23,17 @@ List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Landmark landmark in trip.landmarks) {
|
for (Landmark landmark in trip.landmarks) {
|
||||||
if (selector(landmark)) {
|
|
||||||
children.add(
|
children.add(
|
||||||
LandmarkCard(landmark, trip),
|
LandmarkCard(landmark, trip),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!landmark.visited) {
|
if (landmark.next != null) {
|
||||||
Landmark? nextLandmark = landmark.next;
|
|
||||||
while (nextLandmark != null && nextLandmark.visited) {
|
|
||||||
nextLandmark = nextLandmark.next;
|
|
||||||
}
|
|
||||||
if (nextLandmark != null) {
|
|
||||||
children.add(
|
children.add(
|
||||||
StepBetweenLandmarks(current: landmark, next: nextLandmark!)
|
StepBetweenLandmarks(current: landmark, next: landmark.next!)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
|
||||||
@ -36,32 +35,29 @@ class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicato
|
|||||||
// In the very center of the panel, show the greeter which tells the user that the trip is being generated
|
// In the very center of the panel, show the greeter which tells the user that the trip is being generated
|
||||||
Center(child: loadingText(widget.trip)),
|
Center(child: loadingText(widget.trip)),
|
||||||
// As a gimmick, and a way to show that the app is still working, show a few loading dots
|
// As a gimmick, and a way to show that the app is still working, show a few loading dots
|
||||||
const Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Padding(
|
child: statusText(),
|
||||||
padding: EdgeInsets.only(bottom: 12),
|
|
||||||
child: StatusText(),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// automatically cycle through the greeter texts
|
// automatically cycle through the greeter texts
|
||||||
class StatusText extends StatefulWidget {
|
class statusText extends StatefulWidget {
|
||||||
const StatusText({Key? key}) : super(key: key);
|
const statusText({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_StatusTextState createState() => _StatusTextState();
|
_statusTextState createState() => _statusTextState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StatusTextState extends State<StatusText> {
|
class _statusTextState extends State<statusText> {
|
||||||
int statusIndex = 0;
|
int statusIndex = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Future.delayed(const Duration(seconds: 5), () {
|
Future.delayed(Duration(seconds: 5), () {
|
||||||
setState(() {
|
setState(() {
|
||||||
statusIndex = (statusIndex + 1) % statusTexts.length;
|
statusIndex = (statusIndex + 1) % statusTexts.length;
|
||||||
});
|
});
|
||||||
@ -85,19 +81,19 @@ Widget loadingText(Trip trip) => FutureBuilder(
|
|||||||
Widget greeter;
|
Widget greeter;
|
||||||
|
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
greeter = AnimatedDotsText(
|
greeter = AnimatedGradientText(
|
||||||
baseText: 'Creating your trip to ${snapshot.data}',
|
text: 'Creating your trip to ${snapshot.data}...',
|
||||||
style: greeterStyle,
|
style: greeterStyle,
|
||||||
);
|
);
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
// the exact error is shown in the central part of the trip overview. No need to show it here
|
// the exact error is shown in the central part of the trip overview. No need to show it here
|
||||||
greeter = Text(
|
greeter = AnimatedGradientText(
|
||||||
'Error while loading trip.',
|
text: 'Error while loading trip.',
|
||||||
style: greeterStyle,
|
style: greeterStyle,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
greeter = AnimatedDotsText(
|
greeter = AnimatedGradientText(
|
||||||
baseText: 'Creating your trip',
|
text: 'Creating your trip...',
|
||||||
style: greeterStyle,
|
style: greeterStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -105,44 +101,62 @@ Widget loadingText(Trip trip) => FutureBuilder(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
class AnimatedDotsText extends StatefulWidget {
|
class AnimatedGradientText extends StatefulWidget {
|
||||||
final String baseText;
|
final String text;
|
||||||
final TextStyle style;
|
final TextStyle style;
|
||||||
|
|
||||||
const AnimatedDotsText({
|
const AnimatedGradientText({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.baseText,
|
required this.text,
|
||||||
required this.style,
|
required this.style,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AnimatedDotsTextState createState() => _AnimatedDotsTextState();
|
_AnimatedGradientTextState createState() => _AnimatedGradientTextState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AnimatedDotsTextState extends State<AnimatedDotsText> {
|
class _AnimatedGradientTextState extends State<AnimatedGradientText> with SingleTickerProviderStateMixin {
|
||||||
int dotCount = 0;
|
late AnimationController _controller;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Timer.periodic(const Duration(seconds: 1), (timer) {
|
_controller = AnimationController(
|
||||||
if (mounted) {
|
duration: const Duration(seconds: 1),
|
||||||
setState(() {
|
vsync: this,
|
||||||
dotCount = (dotCount + 1) % 4;
|
)..repeat();
|
||||||
// show up to 3 dots
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
timer.cancel();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String dots = '.' * dotCount;
|
return AnimatedBuilder(
|
||||||
return Text(
|
animation: _controller,
|
||||||
'${widget.baseText}$dots',
|
builder: (context, child) {
|
||||||
|
return ShaderMask(
|
||||||
|
shaderCallback: (bounds) {
|
||||||
|
return LinearGradient(
|
||||||
|
colors: [GRADIENT_START, GRADIENT_END, GRADIENT_START],
|
||||||
|
stops: [
|
||||||
|
_controller.value - 1.0,
|
||||||
|
_controller.value,
|
||||||
|
_controller.value + 1.0,
|
||||||
|
],
|
||||||
|
tileMode: TileMode.mirror,
|
||||||
|
).createShader(bounds);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
widget.text,
|
||||||
style: widget.style,
|
style: widget.style,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
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/constants.dart';
|
||||||
|
import 'package:anyway/modules/landmark_map_marker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:anyway/structs/landmark.dart';
|
import 'package:anyway/structs/landmark.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/modules/landmark_map_marker.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:widget_to_marker/widget_to_marker.dart';
|
||||||
|
|
||||||
|
|
||||||
class CurrentTripMap extends StatefulWidget {
|
class CurrentTripMap extends StatefulWidget {
|
||||||
|
|
||||||
final Trip? trip;
|
final Trip? trip;
|
||||||
|
|
||||||
CurrentTripMap({this.trip});
|
CurrentTripMap({
|
||||||
|
this.trip
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CurrentTripMap> createState() => _CurrentTripMapState();
|
State<CurrentTripMap> createState() => _CurrentTripMapState();
|
||||||
@ -27,23 +30,7 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
zoom: 11.0,
|
zoom: 11.0,
|
||||||
);
|
);
|
||||||
Set<Marker> mapMarkers = <Marker>{};
|
Set<Marker> mapMarkers = <Marker>{};
|
||||||
Set<Polyline> mapPolylines = <Polyline>{};
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
widget.trip?.addListener(setMapMarkers);
|
|
||||||
widget.trip?.addListener(setMapRoute);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
widget.trip?.removeListener(setMapMarkers);
|
|
||||||
widget.trip?.removeListener(setMapRoute);
|
|
||||||
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onMapCreated(GoogleMapController controller) async {
|
void _onMapCreated(GoogleMapController controller) async {
|
||||||
mapController = controller;
|
mapController = controller;
|
||||||
@ -53,70 +40,38 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
controller.moveCamera(update);
|
controller.moveCamera(update);
|
||||||
}
|
}
|
||||||
setMapMarkers();
|
setMapMarkers();
|
||||||
setMapRoute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onCameraIdle() {
|
void _onCameraIdle() {
|
||||||
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setMapMarkers() async {
|
void setMapMarkers() async {
|
||||||
Iterator<(int, Landmark)> it = (widget.trip?.landmarks.toList() ?? []).indexed.iterator;
|
List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
|
||||||
|
Set<Marker> newMarkers = <Marker>{};
|
||||||
while (it.moveNext()) {
|
for (int i = 0; i < landmarks.length; i++) {
|
||||||
int i = it.current.$1;
|
Landmark landmark = landmarks[i];
|
||||||
Landmark landmark = it.current.$2;
|
|
||||||
|
|
||||||
MarkerId markerId = MarkerId("${landmark.uuid} - ${landmark.visited}");
|
|
||||||
List<double> location = landmark.location;
|
List<double> location = landmark.location;
|
||||||
// only create a new marker, if there is no marker for this landmark
|
|
||||||
if (!mapMarkers.any((Marker marker) => marker.markerId == markerId)) {
|
|
||||||
Marker marker = Marker(
|
Marker marker = Marker(
|
||||||
markerId: markerId,
|
markerId: MarkerId(landmark.uuid),
|
||||||
position: LatLng(location[0], location[1]),
|
position: LatLng(location[0], location[1]),
|
||||||
icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
|
icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
|
||||||
logicalSize: const Size(150, 150),
|
logicalSize: const Size(150, 150),
|
||||||
imageSize: const Size(150, 150),
|
imageSize: const Size(150, 150)
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
newMarkers.add(marker);
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
mapMarkers.add(marker);
|
mapMarkers = newMarkers;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMapRoute() async {
|
|
||||||
List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
|
|
||||||
Set<Polyline> polyLines = <Polyline>{};
|
|
||||||
|
|
||||||
if (landmarks.length < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Landmark landmark in landmarks) {
|
|
||||||
if (landmark.next != null) {
|
|
||||||
List<LatLng> step = [
|
|
||||||
LatLng(landmark.location[0], landmark.location[1]),
|
|
||||||
LatLng(landmark.next!.location[0], landmark.next!.location[1])
|
|
||||||
];
|
|
||||||
Polyline stepLine = Polyline(
|
|
||||||
polylineId: PolylineId('step-${landmark.uuid}'),
|
|
||||||
points: step,
|
|
||||||
color: landmark.visited || (landmark.next?.visited ?? false) ? Colors.grey : PRIMARY_COLOR,
|
|
||||||
width: 5
|
|
||||||
);
|
|
||||||
polyLines.add(stepLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
mapPolylines = polyLines;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
widget.trip?.addListener(setMapMarkers);
|
||||||
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
|
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
|
||||||
|
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
@ -129,7 +84,7 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
} else {
|
} else {
|
||||||
return const CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +93,8 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
onMapCreated: _onMapCreated,
|
onMapCreated: _onMapCreated,
|
||||||
initialCameraPosition: _cameraPosition,
|
initialCameraPosition: _cameraPosition,
|
||||||
onCameraIdle: _onCameraIdle,
|
onCameraIdle: _onCameraIdle,
|
||||||
|
// onLongPress: ,
|
||||||
markers: mapMarkers,
|
markers: mapMarkers,
|
||||||
polylines: mapPolylines,
|
|
||||||
cloudMapId: MAP_ID,
|
cloudMapId: MAP_ID,
|
||||||
mapToolbarEnabled: false,
|
mapToolbarEnabled: false,
|
||||||
zoomControlsEnabled: false,
|
zoomControlsEnabled: false,
|
||||||
@ -147,4 +102,5 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
myLocationButtonEnabled: false,
|
myLocationButtonEnabled: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/landmark.dart';
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/modules/current_trip_error_message.dart';
|
import 'package:anyway/modules/current_trip_error_message.dart';
|
||||||
import 'package:anyway/modules/current_trip_loading_indicator.dart';
|
import 'package:anyway/modules/current_trip_loading_indicator.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/modules/current_trip_summary.dart';
|
import 'package:anyway/modules/current_trip_summary.dart';
|
||||||
import 'package:anyway/modules/current_trip_save_button.dart';
|
import 'package:anyway/modules/current_trip_save_button.dart';
|
||||||
import 'package:anyway/modules/current_trip_landmarks_list.dart';
|
import 'package:anyway/modules/current_trip_landmarks_list.dart';
|
||||||
@ -66,41 +63,13 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
|
|||||||
child: CurrentTripGreeter(trip: widget.trip),
|
child: CurrentTripGreeter(trip: widget.trip),
|
||||||
),
|
),
|
||||||
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(10),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey[100],
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
CurrentTripSummary(trip: widget.trip),
|
|
||||||
if (widget.trip.landmarks.where((Landmark landmark) => landmark.visited).isNotEmpty)
|
|
||||||
ExpansionTile(
|
|
||||||
leading: const Icon(Icons.location_on),
|
|
||||||
title: const Text('Visited Landmarks (tap to expand)'),
|
|
||||||
children: [
|
|
||||||
...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
|
|
||||||
],
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
collapsedShape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
|
|
||||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
|
|
||||||
// upcoming landmarks
|
// CurrentTripSummary(trip: widget.trip),
|
||||||
...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited == false),
|
|
||||||
|
// const Divider(),
|
||||||
|
|
||||||
|
...landmarksList(widget.trip),
|
||||||
|
|
||||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/main.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
class saveButton extends StatefulWidget {
|
class saveButton extends StatefulWidget {
|
||||||
@ -52,3 +52,4 @@ class _saveButtonState extends State<saveButton> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
class CurrentTripSummary extends StatefulWidget {
|
class CurrentTripSummary extends StatefulWidget {
|
||||||
final Trip trip;
|
final Trip trip;
|
||||||
const CurrentTripSummary({
|
const CurrentTripSummary({
|
||||||
@ -16,27 +15,17 @@ class CurrentTripSummary extends StatefulWidget {
|
|||||||
class _CurrentTripSummaryState extends State<CurrentTripSummary> {
|
class _CurrentTripSummaryState extends State<CurrentTripSummary> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Column(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Text('Summary'),
|
||||||
children: [
|
// Text('Start: ${widget.trip.start}'),
|
||||||
const Icon(Icons.flag, size: 20),
|
// Text('End: ${widget.trip.end}'),
|
||||||
const Padding(padding: EdgeInsets.only(right: 10)),
|
Text('Total duration: ${widget.trip.totalTime}'),
|
||||||
Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge),
|
Text('Total distance: ${widget.trip.totalTime}'),
|
||||||
]
|
// Text('Fuel: ${widget.trip.fuel}'),
|
||||||
),
|
// Text('Cost: ${widget.trip.cost}'),
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.hourglass_bottom_rounded, size: 20),
|
|
||||||
const Padding(padding: EdgeInsets.only(right: 10)),
|
|
||||||
Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Future<void> helpDialog(BuildContext context, String title, String content) {
|
Future<void> helpDialog(BuildContext context, String title, String content) {
|
||||||
return showDialog<void>(
|
return showDialog<void>(
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/main.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/landmark.dart';
|
import 'package:anyway/structs/landmark.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LandmarkCard extends StatefulWidget {
|
class LandmarkCard extends StatefulWidget {
|
||||||
final Landmark landmark;
|
final Landmark landmark;
|
||||||
final Trip parentTrip;
|
final Trip parentTrip;
|
||||||
@ -27,184 +23,150 @@ class LandmarkCard extends StatefulWidget {
|
|||||||
class _LandmarkCardState extends State<LandmarkCard> {
|
class _LandmarkCardState extends State<LandmarkCard> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (widget.landmark.type == typeStart || widget.landmark.type == typeFinish) {
|
||||||
|
return TextButton.icon(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: widget.landmark.type.icon,
|
||||||
|
label: Text(widget.landmark.name),
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
// else:
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(
|
|
||||||
// express the max height in terms text lines
|
|
||||||
maxHeight: 7 * (Theme.of(context).textTheme.titleMedium!.fontSize! + 10),
|
|
||||||
),
|
|
||||||
child: Card(
|
child: Card(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
),
|
),
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
|
||||||
// if the image is available, display it on the left side of the card, otherwise only display the text
|
// if the image is available, display it on the left side of the card, otherwise only display the text
|
||||||
child: Row(
|
child: widget.landmark.imageURL != null ? splitLayout() : textLayout(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget splitLayout() {
|
||||||
|
// If an image is available, display it on the left side of the card
|
||||||
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Image and landmark "type" on the left
|
|
||||||
AspectRatio(
|
|
||||||
aspectRatio: 3 / 4,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
if (widget.landmark.imageURL != null && widget.landmark.imageURL!.isNotEmpty)
|
|
||||||
Expanded(
|
|
||||||
child: CachedNetworkImage(
|
|
||||||
imageUrl: widget.landmark.imageURL!,
|
|
||||||
placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
|
|
||||||
errorWidget: (context, url, error) => imagePlaceholder(widget.landmark),
|
|
||||||
fit: BoxFit.cover
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else
|
|
||||||
imagePlaceholder(widget.landmark),
|
|
||||||
|
|
||||||
if (widget.landmark.type != typeStart && widget.landmark.type != typeFinish)
|
|
||||||
Container(
|
Container(
|
||||||
color: PRIMARY_COLOR,
|
// the image on the left
|
||||||
child: Center(
|
width: 160,
|
||||||
child: Padding(
|
height: 160,
|
||||||
padding: EdgeInsets.all(5),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
spacing: 5,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.timer_outlined, size: 16),
|
|
||||||
Text("${widget.landmark.duration?.inMinutes} minutes"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Main information, useful buttons on the right
|
child: CachedNetworkImage(
|
||||||
Expanded(
|
imageUrl: widget.landmark.imageURL ?? '',
|
||||||
|
placeholder: (context, url) => Center(child: CircularProgressIndicator()),
|
||||||
|
errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: textLayout(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget textLayout() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Row(
|
||||||
padding: const EdgeInsets.all(10),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Flexible(
|
||||||
|
child: Text(
|
||||||
widget.landmark.name,
|
widget.landmark.name,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: const TextStyle(
|
||||||
overflow: TextOverflow.ellipsis,
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
if (widget.landmark.nameEN != null)
|
if (widget.landmark.nameEN != null)
|
||||||
Text(
|
Row(
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
widget.landmark.nameEN!,
|
widget.landmark.nameEN!,
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
]
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
|
Align(
|
||||||
// fill the vspace
|
alignment: Alignment.centerLeft,
|
||||||
const Spacer(),
|
child: SingleChildScrollView(
|
||||||
|
// allows the buttons to be scrolled
|
||||||
SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
padding: EdgeInsets.only(left: 5, right: 5, bottom: 10),
|
|
||||||
// the scroll view should be flush once the buttons are scrolled to the left
|
|
||||||
// but initially there should be some padding
|
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 10,
|
spacing: 10,
|
||||||
// show the type, the website, and the wikipedia link as buttons/labels in a row
|
// show the type, the website, and the wikipedia link as buttons/labels in a row
|
||||||
children: [
|
children: [
|
||||||
doneToggleButton(),
|
TextButton.icon(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: widget.landmark.type.icon,
|
||||||
|
label: Text(widget.landmark.type.name),
|
||||||
|
),
|
||||||
|
if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icon(Icons.hourglass_bottom),
|
||||||
|
label: Text('${widget.landmark.duration!.inMinutes} minutes'),
|
||||||
|
),
|
||||||
if (widget.landmark.websiteURL != null)
|
if (widget.landmark.websiteURL != null)
|
||||||
websiteButton(),
|
TextButton.icon(
|
||||||
|
|
||||||
optionsButton()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget doneToggleButton() {
|
|
||||||
return TextButton.icon(
|
|
||||||
onPressed: () async {
|
|
||||||
widget.landmark.visited = !widget.landmark.visited;
|
|
||||||
widget.parentTrip.notifyUpdate();
|
|
||||||
},
|
|
||||||
icon: Icon(widget.landmark.visited ? Icons.undo_sharp : Icons.check),
|
|
||||||
label: Text(widget.landmark.visited ? "Add to overview" : "Done!"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget websiteButton () => TextButton.icon(
|
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// open a browser with the website link
|
// open a browser with the website link
|
||||||
await launchUrl(Uri.parse(widget.landmark.websiteURL!));
|
await launchUrl(Uri.parse(widget.landmark.websiteURL!));
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.link),
|
icon: Icon(Icons.link),
|
||||||
label: const Text('Website'),
|
label: Text('Website'),
|
||||||
);
|
),
|
||||||
|
PopupMenuButton(
|
||||||
|
icon: Icon(Icons.settings),
|
||||||
Widget optionsButton () => PopupMenuButton(
|
|
||||||
icon: const Icon(Icons.settings),
|
|
||||||
style: TextButtonTheme.of(context).style,
|
style: TextButtonTheme.of(context).style,
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(Icons.delete),
|
leading: Icon(Icons.delete),
|
||||||
title: const Text('Delete'),
|
title: Text('Delete'),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
widget.parentTrip.removeLandmark(widget.landmark);
|
widget.parentTrip.removeLandmark(widget.landmark);
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
SnackBar(content: Text("${widget.landmark.name} won't be shown again"))
|
SnackBar(content: Text("We won't show ${widget.landmark.name} again"))
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(Icons.star),
|
leading: Icon(Icons.star),
|
||||||
title: const Text('Favorite'),
|
title: Text('Favorite'),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
// delete the landmark
|
||||||
SnackBar(content: Text("Not implemented yet"))
|
// await deleteLandmark(widget.landmark);
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget imagePlaceholder (Landmark landmark) => Expanded(
|
|
||||||
child:
|
|
||||||
Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: [GRADIENT_START, GRADIENT_END],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Icon(landmark.type.icon.icon, size: 50),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
@ -40,7 +40,7 @@ class ThemedMarker extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: landmark.visited ? LinearGradient(colors: [Colors.grey, Colors.white]) : APP_GRADIENT,
|
gradient: APP_GRADIENT,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(color: Colors.black, width: 5),
|
border: Border.all(color: Colors.black, width: 5),
|
||||||
),
|
),
|
||||||
|
@ -46,11 +46,11 @@ class _NewTripButtonState extends State<NewTripButton> {
|
|||||||
UserPreferences preferences = widget.preferences;
|
UserPreferences preferences = widget.preferences;
|
||||||
if (preferences.nature.value == 0 && preferences.shopping.value == 0 && preferences.sightseeing.value == 0){
|
if (preferences.nature.value == 0 && preferences.shopping.value == 0 && preferences.sightseeing.value == 0){
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
const SnackBar(content: Text("Please specify at least one preference"))
|
SnackBar(content: Text("Please specify at least one preference"))
|
||||||
);
|
);
|
||||||
} else if (preferences.maxTime.value == 0){
|
} else if (preferences.maxTime.value == 0){
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
const SnackBar(content: Text("Please choose a longer duration"))
|
SnackBar(content: Text("Please choose a longer duration"))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Trip trip = widget.trip;
|
Trip trip = widget.trip;
|
||||||
@ -63,3 +63,4 @@ class _NewTripButtonState extends State<NewTripButton> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// A map that allows the user to select a location for a new trip.
|
// A map that allows the user to select a location for a new trip.
|
||||||
import 'package:flutter/material.dart';
|
import 'dart:developer';
|
||||||
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/constants.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
|
||||||
import 'package:anyway/structs/landmark.dart';
|
|
||||||
import 'package:anyway/modules/landmark_map_marker.dart';
|
import 'package:anyway/modules/landmark_map_marker.dart';
|
||||||
|
import 'package:anyway/structs/landmark.dart';
|
||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:widget_to_marker/widget_to_marker.dart';
|
||||||
|
|
||||||
|
|
||||||
class NewTripMap extends StatefulWidget {
|
class NewTripMap extends StatefulWidget {
|
||||||
@ -30,6 +30,7 @@ class _NewTripMapState extends State<NewTripMap> {
|
|||||||
final Set<Marker> _markers = <Marker>{};
|
final Set<Marker> _markers = <Marker>{};
|
||||||
|
|
||||||
_onLongPress(LatLng location) {
|
_onLongPress(LatLng location) {
|
||||||
|
log('Long press: $location');
|
||||||
widget.trip.landmarks.clear();
|
widget.trip.landmarks.clear();
|
||||||
widget.trip.addLandmark(
|
widget.trip.addLandmark(
|
||||||
Landmark(
|
Landmark(
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/structs/landmark.dart';
|
import 'package:anyway/structs/landmark.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:anyway/modules/map_chooser.dart';
|
import 'package:anyway/modules/map_chooser.dart';
|
||||||
|
|
||||||
|
|
||||||
class StepBetweenLandmarks extends StatefulWidget {
|
class StepBetweenLandmarks extends StatefulWidget {
|
||||||
final Landmark current;
|
final Landmark current;
|
||||||
final Landmark next;
|
final Landmark next;
|
||||||
@ -21,23 +19,12 @@ class StepBetweenLandmarks extends StatefulWidget {
|
|||||||
class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
|
class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
int? time = widget.current.tripTime?.inMinutes;
|
int timeRounded = 5 * ((widget.current.tripTime?.inMinutes ?? 0) ~/ 5);
|
||||||
|
// ~/ is integer division (rounding)
|
||||||
// since landmarks might have been marked as visited, the next landmark might not be the immediate next in the list
|
|
||||||
// => the precomputed trip time is not valid anymore
|
|
||||||
if (widget.current.next != widget.next) {
|
|
||||||
time = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// round 0 travel time to 1 minute
|
|
||||||
if (time != null && time < 1) {
|
|
||||||
time = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.all(10),
|
margin: EdgeInsets.all(10),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
left: BorderSide(width: 3.0, color: Colors.black),
|
left: BorderSide(width: 3.0, color: Colors.black),
|
||||||
),
|
),
|
||||||
@ -46,22 +33,21 @@ class _StepBetweenLandmarksState extends State<StepBetweenLandmarks> {
|
|||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.directions_walk),
|
Icon(Icons.directions_walk),
|
||||||
Text(
|
Text("~$timeRounded min", style: TextStyle(fontSize: 10)),
|
||||||
time == null ? "" : "About $time min",
|
|
||||||
style: const TextStyle(fontSize: 10)
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Spacer(),
|
||||||
const Spacer(),
|
ElevatedButton(
|
||||||
|
|
||||||
ElevatedButton.icon(
|
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
showMapChooser(context, widget.current, widget.next);
|
showMapChooser(context, widget.current, widget.next);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.directions),
|
child: Row(
|
||||||
label: const Text("Directions"),
|
children: [
|
||||||
|
Icon(Icons.directions),
|
||||||
|
Text("Directions"),
|
||||||
|
],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -1,51 +1,72 @@
|
|||||||
|
import 'package:anyway/main.dart';
|
||||||
|
import 'package:anyway/modules/help_dialog.dart';
|
||||||
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
|
import 'package:anyway/pages/settings.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/modules/help_dialog.dart';
|
|
||||||
import 'package:anyway/modules/trips_saved_list.dart';
|
import 'package:anyway/modules/trips_saved_list.dart';
|
||||||
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
|
|
||||||
import 'package:anyway/pages/onboarding.dart';
|
|
||||||
import 'package:anyway/pages/current_trip.dart';
|
|
||||||
import 'package:anyway/pages/settings.dart';
|
|
||||||
import 'package:anyway/pages/new_trip_location.dart';
|
import 'package:anyway/pages/new_trip_location.dart';
|
||||||
|
import 'package:anyway/pages/onboarding.dart';
|
||||||
|
|
||||||
|
|
||||||
mixin ScaffoldLayout<T extends StatefulWidget> on State<T> {
|
|
||||||
Widget mainScaffold(
|
|
||||||
BuildContext context,
|
// BasePage is the scaffold that holds a child page and a side drawer
|
||||||
{
|
// The side drawer is the main way to switch between pages
|
||||||
Widget child = const Text("emptiness"),
|
|
||||||
Widget title = const Text(APP_NAME),
|
class BasePage extends StatefulWidget {
|
||||||
List<String> helpTexts = const []
|
final Widget mainScreen;
|
||||||
|
final Widget title;
|
||||||
|
final List<String> helpTexts;
|
||||||
|
|
||||||
|
const BasePage({
|
||||||
|
super.key,
|
||||||
|
required this.mainScreen,
|
||||||
|
this.title = const Text(APP_NAME),
|
||||||
|
this.helpTexts = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BasePage> createState() => _BasePageState();
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
|
class _BasePageState extends State<BasePage> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
savedTrips.loadTrips();
|
||||||
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: title,
|
title: widget.title,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.help),
|
icon: const Icon(Icons.help),
|
||||||
tooltip: 'Help',
|
tooltip: 'Help',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (helpTexts.isNotEmpty) {
|
if (widget.helpTexts.isNotEmpty) {
|
||||||
helpDialog(context, helpTexts[0], helpTexts[1]);
|
helpDialog(context, widget.helpTexts[0], widget.helpTexts[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Center(child: child),
|
body: Center(child: widget.mainScreen),
|
||||||
drawer: Drawer(
|
drawer: Drawer(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: APP_GRADIENT,
|
gradient: APP_GRADIENT,
|
||||||
),
|
),
|
||||||
height: 150,
|
height: 150,
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
APP_NAME,
|
APP_NAME,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@ -60,7 +81,8 @@ mixin ScaffoldLayout<T extends StatefulWidget> on State<T> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Your Trips'),
|
title: const Text('Your Trips'),
|
||||||
leading: const Icon(Icons.map),
|
leading: const Icon(Icons.map),
|
||||||
selected: widget is TripPage,
|
// TODO: this is not working!
|
||||||
|
selected: widget.mainScreen is TripPage,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
trailing: ElevatedButton(
|
trailing: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -89,12 +111,13 @@ mixin ScaffoldLayout<T extends StatefulWidget> on State<T> {
|
|||||||
const Divider(indent: 10, endIndent: 10),
|
const Divider(indent: 10, endIndent: 10),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('How to use'),
|
title: const Text('How to use'),
|
||||||
leading: const Icon(Icons.help),
|
leading: Icon(Icons.help),
|
||||||
selected: widget is OnboardingPage,
|
// TODO: this is not working!
|
||||||
|
selected: widget.mainScreen is OnboardingPage,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => const OnboardingPage()
|
builder: (context) => OnboardingPage()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -104,7 +127,8 @@ mixin ScaffoldLayout<T extends StatefulWidget> on State<T> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Settings'),
|
title: const Text('Settings'),
|
||||||
leading: const Icon(Icons.settings),
|
leading: const Icon(Icons.settings),
|
||||||
selected: widget is SettingsPage,
|
// TODO: this is not working!
|
||||||
|
selected: widget.mainScreen is SettingsPage,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/layouts/scaffold.dart';
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:sliding_up_panel/sliding_up_panel.dart';
|
import 'package:sliding_up_panel/sliding_up_panel.dart';
|
||||||
|
|
||||||
@ -28,13 +28,12 @@ class TripPage extends StatefulWidget {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class _TripPageState extends State<TripPage> with ScaffoldLayout{
|
class _TripPageState extends State<TripPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return mainScaffold(
|
return BasePage(
|
||||||
context,
|
mainScreen: SlidingUpPanel(
|
||||||
child: SlidingUpPanel(
|
|
||||||
// use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
|
// use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
|
||||||
panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
|
panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
|
||||||
// using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
|
// using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
|
||||||
@ -59,13 +58,9 @@ class _TripPageState extends State<TripPage> with ScaffoldLayout{
|
|||||||
title: FutureBuilder(
|
title: FutureBuilder(
|
||||||
future: widget.trip.cityName,
|
future: widget.trip.cityName,
|
||||||
builder: (context, snapshot) => Text(
|
builder: (context, snapshot) => Text(
|
||||||
'Trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
helpTexts: [
|
|
||||||
'Current trip',
|
|
||||||
'You can see and edit your current trip here. Swipe up from the bottom to see a detailed view of the recommendations.'
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:anyway/layouts/scaffold.dart';
|
|
||||||
import 'package:anyway/modules/new_trip_options_button.dart';
|
import 'package:anyway/modules/new_trip_options_button.dart';
|
||||||
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import "package:anyway/structs/trip.dart";
|
import "package:anyway/structs/trip.dart";
|
||||||
@ -14,7 +14,7 @@ class NewTripPage extends StatefulWidget {
|
|||||||
_NewTripPageState createState() => _NewTripPageState();
|
_NewTripPageState createState() => _NewTripPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NewTripPageState extends State<NewTripPage> with ScaffoldLayout {
|
class _NewTripPageState extends State<NewTripPage> {
|
||||||
final TextEditingController latController = TextEditingController();
|
final TextEditingController latController = TextEditingController();
|
||||||
final TextEditingController lonController = TextEditingController();
|
final TextEditingController lonController = TextEditingController();
|
||||||
Trip trip = Trip();
|
Trip trip = Trip();
|
||||||
@ -23,9 +23,8 @@ class _NewTripPageState extends State<NewTripPage> with ScaffoldLayout {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// floating search bar and map as a background
|
// floating search bar and map as a background
|
||||||
return mainScaffold(
|
return BasePage(
|
||||||
context,
|
mainScreen: Scaffold(
|
||||||
child: Scaffold(
|
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
NewTripMap(trip),
|
NewTripMap(trip),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:anyway/layouts/scaffold.dart';
|
|
||||||
import 'package:anyway/modules/new_trip_button.dart';
|
import 'package:anyway/modules/new_trip_button.dart';
|
||||||
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:anyway/structs/preferences.dart';
|
import 'package:anyway/structs/preferences.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
@ -15,14 +15,13 @@ class NewTripPreferencesPage extends StatefulWidget {
|
|||||||
_NewTripPreferencesPageState createState() => _NewTripPreferencesPageState();
|
_NewTripPreferencesPageState createState() => _NewTripPreferencesPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with ScaffoldLayout {
|
class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
||||||
UserPreferences preferences = UserPreferences();
|
UserPreferences preferences = UserPreferences();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return mainScaffold(
|
return BasePage(
|
||||||
context,
|
mainScreen: Scaffold(
|
||||||
child: Scaffold(
|
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
// Center(
|
// Center(
|
||||||
@ -58,6 +57,7 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> with Sc
|
|||||||
),
|
),
|
||||||
floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
|
floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
|
||||||
),
|
),
|
||||||
|
|
||||||
title: FutureBuilder(
|
title: FutureBuilder(
|
||||||
future: widget.trip.cityName,
|
future: widget.trip.cityName,
|
||||||
builder: (context, snapshot) => Text(
|
builder: (context, snapshot) => Text(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/layouts/scaffold.dart';
|
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/main.dart';
|
||||||
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@ -14,11 +14,11 @@ class SettingsPage extends StatefulWidget {
|
|||||||
_SettingsPageState createState() => _SettingsPageState();
|
_SettingsPageState createState() => _SettingsPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
|
class _SettingsPageState extends State<SettingsPage> {
|
||||||
@override
|
@override
|
||||||
Widget build (BuildContext context) => mainScaffold(
|
Widget build(BuildContext context) {
|
||||||
context,
|
return BasePage(
|
||||||
child: ListView(
|
mainScreen: ListView(
|
||||||
padding: EdgeInsets.all(15),
|
padding: EdgeInsets.all(15),
|
||||||
children: [
|
children: [
|
||||||
// First a round, centered image
|
// First a round, centered image
|
||||||
@ -49,6 +49,7 @@ class _SettingsPageState extends State<SettingsPage> with ScaffoldLayout {
|
|||||||
'Preferences set in this page are global and will affect the entire application.'
|
'Preferences set in this page are global and will affect the entire application.'
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget setDebugMode() {
|
Widget setDebugMode() {
|
||||||
return Row(
|
return Row(
|
||||||
|
@ -27,12 +27,11 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
String? imageURL; // not final because it can be patched
|
String? imageURL; // not final because it can be patched
|
||||||
final String? description;
|
final String? description;
|
||||||
final Duration? duration;
|
final Duration? duration;
|
||||||
bool visited;
|
final bool? visited;
|
||||||
|
|
||||||
// Next node is implicitly available through the LinkedListEntry mixin
|
// Next node
|
||||||
// final Landmark? next;
|
// final Landmark? next;
|
||||||
Duration? tripTime;
|
final Duration? tripTime;
|
||||||
// the trip time depends on the next landmark, so it is not final
|
|
||||||
|
|
||||||
|
|
||||||
Landmark({
|
Landmark({
|
||||||
@ -47,7 +46,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
this.imageURL,
|
this.imageURL,
|
||||||
this.description,
|
this.description,
|
||||||
this.duration,
|
this.duration,
|
||||||
this.visited = false,
|
this.visited,
|
||||||
|
|
||||||
// this.next,
|
// this.next,
|
||||||
this.tripTime,
|
this.tripTime,
|
||||||
@ -71,8 +70,8 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
final websiteURL = json['website_url'] as String?;
|
final websiteURL = json['website_url'] as String?;
|
||||||
final imageURL = json['image_url'] as String?;
|
final imageURL = json['image_url'] as String?;
|
||||||
final description = json['description'] as String?;
|
final description = json['description'] as String?;
|
||||||
var duration = Duration(minutes: json['duration']);
|
var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
|
||||||
final visited = json['visited'] ?? false;
|
final visited = json['visited'] as bool?;
|
||||||
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
|
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
|
||||||
|
|
||||||
return Landmark(
|
return Landmark(
|
||||||
|
@ -29,18 +29,6 @@ class Trip with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> landmarkPosition (Landmark landmark) async {
|
|
||||||
int i = 0;
|
|
||||||
for (Landmark l in landmarks) {
|
|
||||||
if (l.uuid == landmark.uuid) {
|
|
||||||
return i;
|
|
||||||
} else if (l.type != typeStart && l.type != typeFinish) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Trip({
|
Trip({
|
||||||
this.uuid = 'pending',
|
this.uuid = 'pending',
|
||||||
@ -64,7 +52,6 @@ class Trip with ChangeNotifier {
|
|||||||
totalTime = json['total_time'];
|
totalTime = json['total_time'];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLandmark(Landmark landmark) {
|
void addLandmark(Landmark landmark) {
|
||||||
landmarks.add(landmark);
|
landmarks.add(landmark);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -75,16 +62,8 @@ class Trip with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeLandmark (Landmark landmark) async {
|
void removeLandmark(Landmark landmark) {
|
||||||
Landmark? previous = landmark.previous;
|
|
||||||
Landmark? next = landmark.next;
|
|
||||||
landmarks.remove(landmark);
|
landmarks.remove(landmark);
|
||||||
// removing the landmark means we need to recompute the time between the two adjoined landmarks
|
|
||||||
if (previous != null && next != null) {
|
|
||||||
// previous.next = next happens automatically since we are using a LinkedList
|
|
||||||
previous.tripTime = null;
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,10 +72,6 @@ class Trip with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyUpdate(){
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
|
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
|
||||||
String? content = prefs.getString('trip_$uuid');
|
String? content = prefs.getString('trip_$uuid');
|
||||||
Map<String, dynamic> json = jsonDecode(content!);
|
Map<String, dynamic> json = jsonDecode(content!);
|
||||||
@ -105,6 +80,7 @@ class Trip with ChangeNotifier {
|
|||||||
log('Loading trip $uuid with first landmark $firstUUID');
|
log('Loading trip $uuid with first landmark $firstUUID');
|
||||||
LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
|
LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
|
||||||
trip.landmarks = landmarks;
|
trip.landmarks = landmarks;
|
||||||
|
// notifyListeners();
|
||||||
return trip;
|
return trip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
import "dart:developer";
|
import "dart:developer";
|
||||||
|
import "package:anyway/utils/load_landmark_image.dart";
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import "package:anyway/utils/load_landmark_image.dart";
|
|
||||||
import "package:anyway/structs/landmark.dart";
|
import "package:anyway/structs/landmark.dart";
|
||||||
import "package:anyway/structs/trip.dart";
|
import "package:anyway/structs/trip.dart";
|
||||||
import "package:anyway/structs/preferences.dart";
|
import "package:anyway/structs/preferences.dart";
|
||||||
@ -24,10 +24,10 @@ Dio dio = Dio(
|
|||||||
// },
|
// },
|
||||||
contentType: Headers.jsonContentType,
|
contentType: Headers.jsonContentType,
|
||||||
responseType: ResponseType.json,
|
responseType: ResponseType.json,
|
||||||
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
fetchTrip(
|
fetchTrip(
|
||||||
Trip trip,
|
Trip trip,
|
||||||
UserPreferences preferences,
|
UserPreferences preferences,
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import 'package:anyway/main.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
|
||||||
import 'package:anyway/utils/load_trips.dart';
|
|
||||||
import 'package:anyway/pages/current_trip.dart';
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:anyway/pages/onboarding.dart';
|
import 'package:anyway/pages/onboarding.dart';
|
||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Widget getFirstPage() {
|
Widget getFirstPage() {
|
||||||
SavedTrips trips = savedTrips;
|
SavedTrips trips = SavedTrips();
|
||||||
trips.loadTrips();
|
trips.loadTrips();
|
||||||
|
|
||||||
return ListenableBuilder(
|
return ListenableBuilder(
|
||||||
@ -18,7 +15,7 @@ Widget getFirstPage() {
|
|||||||
if (items.isNotEmpty) {
|
if (items.isNotEmpty) {
|
||||||
return TripPage(trip: items[0]);
|
return TripPage(trip: items[0]);
|
||||||
} else {
|
} else {
|
||||||
return const OnboardingPage();
|
return OnboardingPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user