Compare commits
No commits in common. "dd48fda99f220a457264c301dea7a90fd7222a80" and "4baf045c8c23731e44b8afa2b13e3b9116e989b0" have entirely different histories.
dd48fda99f
...
4baf045c8c
111
backend/test.py
111
backend/test.py
@ -1,111 +0,0 @@
|
|||||||
import numpy as np
|
|
||||||
|
|
||||||
def euclidean_distance(p1, p2):
|
|
||||||
print(p1, p2)
|
|
||||||
return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
|
|
||||||
|
|
||||||
|
|
||||||
def maximize_score(places, max_distance, fixed_entry, top_k=3):
|
|
||||||
"""
|
|
||||||
Maximizes the total score of visited places while staying below the maximum distance.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
places (list of tuples): Each tuple contains (score, (x, y), location).
|
|
||||||
max_distance (float): The maximum distance that can be traveled.
|
|
||||||
fixed_entry (tuple): The place that needs to be visited independently of its score.
|
|
||||||
top_k (int): Number of top candidates to consider in each iteration.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list of tuples: The visited places.
|
|
||||||
float: The total score of the visited places.
|
|
||||||
"""
|
|
||||||
# Initialize total distance and score
|
|
||||||
total_distance = 0
|
|
||||||
total_score = 0
|
|
||||||
visited_places = []
|
|
||||||
|
|
||||||
# Add the fixed entry to the visited list
|
|
||||||
score, (x, y), _ = fixed_entry
|
|
||||||
visited_places.append(fixed_entry)
|
|
||||||
total_score += score
|
|
||||||
|
|
||||||
# Remove the fixed entry from the list of places
|
|
||||||
remaining_places = [place for place in places if place != fixed_entry]
|
|
||||||
|
|
||||||
# Sort remaining places by score-to-distance ratio
|
|
||||||
|
|
||||||
remaining_places.sort(key=lambda p: p[0] / euclidean_distance((x, y), (p[1][0], p[1][1])), reverse=True)
|
|
||||||
|
|
||||||
# Add places to the visited list if they don't exceed the maximum distance
|
|
||||||
current_location = (x, y)
|
|
||||||
while remaining_places and total_distance < max_distance:
|
|
||||||
# Consider top_k candidates
|
|
||||||
candidates = remaining_places[:top_k]
|
|
||||||
best_candidate = None
|
|
||||||
best_score_increase = -np.inf
|
|
||||||
|
|
||||||
for candidate in candidates:
|
|
||||||
score, (cx, cy), location = candidate
|
|
||||||
distance = euclidean_distance(current_location, (cx, cy))
|
|
||||||
if total_distance + distance <= max_distance:
|
|
||||||
score_increase = score / distance
|
|
||||||
if score_increase > best_score_increase:
|
|
||||||
best_score_increase = score_increase
|
|
||||||
best_candidate = candidate
|
|
||||||
|
|
||||||
if best_candidate:
|
|
||||||
visited_places.append(best_candidate)
|
|
||||||
total_distance += euclidean_distance(current_location, best_candidate[1])
|
|
||||||
total_score += best_candidate[0]
|
|
||||||
current_location = best_candidate[1]
|
|
||||||
remaining_places.remove(best_candidate)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
return visited_places, total_score
|
|
||||||
|
|
||||||
# Example usage
|
|
||||||
places = [
|
|
||||||
(10, (0, 0), 'A'),
|
|
||||||
(8, (4, 2), 'B'),
|
|
||||||
(15, (6, 4), 'C'),
|
|
||||||
(7, (5, 6), 'D'),
|
|
||||||
(12, (1, 8), 'E'),
|
|
||||||
(14, (34, 10), 'F'),
|
|
||||||
(15, (65, 12), 'G'),
|
|
||||||
(12, (3, 14), 'H'),
|
|
||||||
(12, (15, 1), 'I'),
|
|
||||||
(7, (17, 4), 'J'),
|
|
||||||
(12, (3, 3), 'K'),
|
|
||||||
(4, (21, 22), 'L'),
|
|
||||||
(12, (23, 24), 'M'),
|
|
||||||
(4, (25, 26), 'N'),
|
|
||||||
(2, (27, 28), 'O'),
|
|
||||||
]
|
|
||||||
fixed_entry = (10, (0, 0), 'A')
|
|
||||||
max_distance = 50
|
|
||||||
|
|
||||||
visited_places, total_score = maximize_score(places, max_distance, fixed_entry)
|
|
||||||
print("Visited Places:", visited_places)
|
|
||||||
print("Total Score:", total_score)
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
# Plot the route
|
|
||||||
def plot_route(visited_places):
|
|
||||||
x_coords = [place[1][0] for place in visited_places]
|
|
||||||
y_coords = [place[1][1] for place in visited_places]
|
|
||||||
labels = [place[2] for place in visited_places]
|
|
||||||
|
|
||||||
plt.figure(figsize=(10, 6))
|
|
||||||
plt.plot(x_coords, y_coords, marker='o', linestyle='-', color='b')
|
|
||||||
for i, label in enumerate(labels):
|
|
||||||
plt.text(x_coords[i], y_coords[i], label, fontsize=12, ha='right')
|
|
||||||
|
|
||||||
plt.title('Route of Visited Places')
|
|
||||||
plt.xlabel('X Coordinate')
|
|
||||||
plt.ylabel('Y Coordinate')
|
|
||||||
plt.grid(True)
|
|
||||||
plt.savefig('route.png')
|
|
||||||
|
|
||||||
plot_route(visited_places)
|
|
@ -1,12 +1,10 @@
|
|||||||
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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
void main() => runApp(const App());
|
void main() => runApp(const App());
|
||||||
|
|
||||||
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||||
final SavedTrips savedTrips = SavedTrips();
|
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
class App extends StatelessWidget {
|
||||||
const App({super.key});
|
const App({super.key});
|
||||||
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:anyway/modules/landmark_card.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/main.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -24,7 +25,30 @@ List<Widget> landmarksList(Trip trip) {
|
|||||||
|
|
||||||
for (Landmark landmark in trip.landmarks) {
|
for (Landmark landmark in trip.landmarks) {
|
||||||
children.add(
|
children.add(
|
||||||
LandmarkCard(landmark, trip),
|
Dismissible(
|
||||||
|
key: ValueKey<int>(landmark.hashCode),
|
||||||
|
child: LandmarkCard(landmark),
|
||||||
|
dismissThresholds: {DismissDirection.endToStart: 0.95, DismissDirection.startToEnd: 0.95},
|
||||||
|
onDismissed: (direction) {
|
||||||
|
log('Removing ${landmark.name}');
|
||||||
|
trip.removeLandmark(landmark);
|
||||||
|
|
||||||
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
|
SnackBar(content: Text("We won't show ${landmark.name} again"))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
background: Container(color: Colors.red),
|
||||||
|
secondaryBackground: Container(
|
||||||
|
color: Colors.red,
|
||||||
|
child: Icon(
|
||||||
|
Icons.delete,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(15),
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (landmark.next != null) {
|
if (landmark.next != null) {
|
||||||
|
@ -34,19 +34,22 @@ Widget loadingText(Trip trip) => FutureBuilder(
|
|||||||
Widget greeter;
|
Widget greeter;
|
||||||
|
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
greeter = AnimatedGradientText(
|
greeter = AutoSizeText(
|
||||||
text: 'Generating your trip to ${snapshot.data}...',
|
maxLines: 1,
|
||||||
|
'Generating 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 = AnimatedGradientText(
|
greeter = AutoSizeText(
|
||||||
text: 'Error while loading trip.',
|
maxLines: 1,
|
||||||
|
'Error while loading trip.',
|
||||||
style: greeterStyle,
|
style: greeterStyle,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
greeter = AnimatedGradientText(
|
greeter = AutoSizeText(
|
||||||
text: 'Generating your trip...',
|
maxLines: 1,
|
||||||
|
'Generating your trip...',
|
||||||
style: greeterStyle,
|
style: greeterStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -54,65 +57,6 @@ Widget loadingText(Trip trip) => FutureBuilder(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
class AnimatedGradientText extends StatefulWidget {
|
|
||||||
final String text;
|
|
||||||
final TextStyle style;
|
|
||||||
|
|
||||||
const AnimatedGradientText({
|
|
||||||
Key? key,
|
|
||||||
required this.text,
|
|
||||||
required this.style,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
_AnimatedGradientTextState createState() => _AnimatedGradientTextState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AnimatedGradientTextState extends State<AnimatedGradientText> with SingleTickerProviderStateMixin {
|
|
||||||
late AnimationController _controller;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = AnimationController(
|
|
||||||
duration: const Duration(seconds: 1),
|
|
||||||
vsync: this,
|
|
||||||
)..repeat();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AnimatedBuilder(
|
|
||||||
animation: _controller,
|
|
||||||
builder: (context, child) {
|
|
||||||
return ShaderMask(
|
|
||||||
shaderCallback: (bounds) {
|
|
||||||
return LinearGradient(
|
|
||||||
colors: [Colors.blue, Colors.red, Colors.blue],
|
|
||||||
stops: [
|
|
||||||
_controller.value - 1.0,
|
|
||||||
_controller.value,
|
|
||||||
_controller.value + 1.0,
|
|
||||||
],
|
|
||||||
tileMode: TileMode.mirror,
|
|
||||||
).createShader(bounds);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
widget.text,
|
|
||||||
style: widget.style,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ 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:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|
||||||
class saveButton extends StatefulWidget {
|
class saveButton extends StatefulWidget {
|
||||||
@ -18,9 +19,8 @@ class _saveButtonState extends State<saveButton> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
savedTrips.addTrip(widget.trip);
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
// SharedPreferences prefs = await SharedPreferences.getInstance();
|
setState(() => widget.trip.toPrefs(prefs));
|
||||||
// setState(() => widget.trip.toPrefs(prefs));
|
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Trip saved'),
|
content: Text('Trip saved'),
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'package:anyway/main.dart';
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@ -8,12 +6,8 @@ import 'package:anyway/structs/landmark.dart';
|
|||||||
|
|
||||||
class LandmarkCard extends StatefulWidget {
|
class LandmarkCard extends StatefulWidget {
|
||||||
final Landmark landmark;
|
final Landmark landmark;
|
||||||
final Trip parentTrip;
|
|
||||||
|
|
||||||
LandmarkCard(
|
LandmarkCard(this.landmark);
|
||||||
this.landmark,
|
|
||||||
this.parentTrip,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LandmarkCardState createState() => _LandmarkCardState();
|
_LandmarkCardState createState() => _LandmarkCardState();
|
||||||
@ -23,38 +17,22 @@ 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(
|
||||||
|
height: 160,
|
||||||
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
|
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: [
|
||||||
Container(
|
Container( // the image on the left
|
||||||
// the image on the left
|
// inherit the height of the parent container
|
||||||
|
height: double.infinity,
|
||||||
|
// force a fixed width
|
||||||
width: 160,
|
width: 160,
|
||||||
height: 160,
|
|
||||||
|
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: widget.landmark.imageURL ?? '',
|
imageUrl: widget.landmark.imageURL ?? '',
|
||||||
placeholder: (context, url) => Center(child: CircularProgressIndicator()),
|
placeholder: (context, url) => Center(child: CircularProgressIndicator()),
|
||||||
@ -63,14 +41,7 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: textLayout(),
|
child: Padding(
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget textLayout() {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -102,10 +73,7 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(padding: EdgeInsets.only(top: 10)),
|
SingleChildScrollView(
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
// allows the buttons to be scrolled
|
// allows the buttons to be scrolled
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
@ -132,41 +100,25 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
|||||||
icon: Icon(Icons.link),
|
icon: Icon(Icons.link),
|
||||||
label: Text('Website'),
|
label: Text('Website'),
|
||||||
),
|
),
|
||||||
PopupMenuButton(
|
// if (widget.landmark.wikipediaURL != null)
|
||||||
icon: Icon(Icons.settings),
|
// TextButton.icon(
|
||||||
style: TextButtonTheme.of(context).style,
|
// onPressed: () async {
|
||||||
itemBuilder: (context) => [
|
// // open a browser with the wikipedia link
|
||||||
PopupMenuItem(
|
// await launchUrl(Uri.parse(widget.landmark.wikipediaURL!));
|
||||||
child: ListTile(
|
// },
|
||||||
leading: Icon(Icons.delete),
|
// icon: Icon(Icons.book),
|
||||||
title: Text('Delete'),
|
// label: Text('Wikipedia'),
|
||||||
onTap: () async {
|
// ),
|
||||||
widget.parentTrip.removeLandmark(widget.landmark);
|
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
|
||||||
SnackBar(content: Text("We won't show ${widget.landmark.name} again"))
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(Icons.star),
|
|
||||||
title: Text('Favorite'),
|
|
||||||
onTap: () async {
|
|
||||||
// delete the landmark
|
|
||||||
// await deleteLandmark(widget.landmark);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import 'package:anyway/pages/current_trip.dart';
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:anyway/utils/load_trips.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
|
||||||
|
|
||||||
class TripsOverview extends StatefulWidget {
|
class TripsOverview extends StatefulWidget {
|
||||||
final SavedTrips trips;
|
final Future<List<Trip>> trips;
|
||||||
const TripsOverview({
|
const TripsOverview({
|
||||||
super.key,
|
super.key,
|
||||||
required this.trips,
|
required this.trips,
|
||||||
@ -17,11 +16,11 @@ class TripsOverview extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TripsOverviewState extends State<TripsOverview> {
|
class _TripsOverviewState extends State<TripsOverview> {
|
||||||
Widget listBuild (BuildContext context, SavedTrips trips) {
|
Widget listBuild (BuildContext context, AsyncSnapshot<List<Trip>> snapshot) {
|
||||||
List<Widget> children;
|
List<Widget> children;
|
||||||
List<Trip> items = trips.trips;
|
if (snapshot.hasData) {
|
||||||
children = List<Widget>.generate(items.length, (index) {
|
children = List<Widget>.generate(snapshot.data!.length, (index) {
|
||||||
Trip trip = items[index];
|
Trip trip = snapshot.data![index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: FutureBuilder(
|
title: FutureBuilder(
|
||||||
future: trip.cityName,
|
future: trip.cityName,
|
||||||
@ -45,6 +44,21 @@ class _TripsOverviewState extends State<TripsOverview> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
children = [
|
||||||
|
const Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 60,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 16),
|
||||||
|
child: Text('Error: ${snapshot.error}'),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
children = [Center(child: CircularProgressIndicator())];
|
||||||
|
}
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
children: children,
|
children: children,
|
||||||
@ -54,11 +68,9 @@ class _TripsOverviewState extends State<TripsOverview> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListenableBuilder(
|
return FutureBuilder(
|
||||||
listenable: widget.trips,
|
future: widget.trips,
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: listBuild,
|
||||||
return listBuild(context, widget.trips);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:anyway/main.dart';
|
|
||||||
import 'package:anyway/modules/help_dialog.dart';
|
import 'package:anyway/modules/help_dialog.dart';
|
||||||
import 'package:anyway/pages/current_trip.dart';
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:anyway/pages/settings.dart';
|
import 'package:anyway/pages/settings.dart';
|
||||||
@ -39,8 +38,7 @@ class _BasePageState extends State<BasePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
savedTrips.loadTrips();
|
Future<List<Trip>> trips = loadTrips();
|
||||||
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@ -100,11 +98,11 @@ class _BasePageState extends State<BasePage> {
|
|||||||
// through the options in the drawer if there isn't enough vertical
|
// through the options in the drawer if there isn't enough vertical
|
||||||
// space to fit everything.
|
// space to fit everything.
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TripsOverview(trips: savedTrips),
|
child: TripsOverview(trips: trips),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
savedTrips.clearTrips();
|
removeAllTripsFromPrefs();
|
||||||
},
|
},
|
||||||
child: const Text('Clear trips'),
|
child: const Text('Clear trips'),
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
|
||||||
import 'package:anyway/modules/onboarding_card.dart';
|
import 'package:anyway/modules/onboarding_card.dart';
|
||||||
import 'package:anyway/pages/new_trip_location.dart';
|
import 'package:anyway/pages/new_trip_location.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -36,42 +33,22 @@ class OnboardingPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _OnboardingPageState extends State<OnboardingPage> {
|
class _OnboardingPageState extends State<OnboardingPage> {
|
||||||
final PageController _controller = PageController();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final PageController _controller = PageController();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
|
||||||
AnimatedBuilder(
|
|
||||||
animation: _controller,
|
|
||||||
builder: (context, child) {
|
|
||||||
return Stack(
|
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
|
colors: [Colors.red, Colors.blue],
|
||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
colors: APP_GRADIENT.colors,
|
|
||||||
stops: [
|
|
||||||
(_controller.hasClients ? _controller.page ?? _controller.initialPage : _controller.initialPage) / onboardingCards.length,
|
|
||||||
(_controller.hasClients ? _controller.page ?? _controller.initialPage + 1 : _controller.initialPage + 1) / onboardingCards.length,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
child: PageView(
|
||||||
BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 100, sigmaY: 100),
|
|
||||||
child: Container(
|
|
||||||
color: Colors.black.withOpacity(0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PageView(
|
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
children: List.generate(
|
children: List.generate(
|
||||||
onboardingCards.length,
|
onboardingCards.length,
|
||||||
@ -83,6 +60,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
@ -97,10 +75,10 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||||||
_controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
|
_controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
label: AnimatedBuilder(
|
label: ListenableBuilder(
|
||||||
animation: _controller,
|
listenable: _controller,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
if ((_controller.page ?? _controller.initialPage) == onboardingCards.length - 1) {
|
if (_controller.page == onboardingCards.length - 1) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const Text("Start planning!"),
|
const Text("Start planning!"),
|
||||||
|
@ -125,7 +125,7 @@ class LandmarkType {
|
|||||||
LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
|
LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'sightseeing':
|
case 'sightseeing':
|
||||||
icon = const Icon(Icons.castle);
|
icon = const Icon(Icons.church);
|
||||||
break;
|
break;
|
||||||
case 'nature':
|
case 'nature':
|
||||||
icon = const Icon(Icons.eco);
|
icon = const Icon(Icons.eco);
|
||||||
|
@ -113,3 +113,10 @@ LinkedList<Landmark> readLandmarks(SharedPreferences prefs, String? firstUUID) {
|
|||||||
}
|
}
|
||||||
return landmarks;
|
return landmarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void removeAllTripsFromPrefs () async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
prefs.clear();
|
||||||
|
}
|
||||||
|
@ -93,11 +93,6 @@ patchLandmarkImage(Landmark landmark) async {
|
|||||||
if (newUrl != null) {
|
if (newUrl != null) {
|
||||||
landmark.imageURL = newUrl;
|
landmark.imageURL = newUrl;
|
||||||
}
|
}
|
||||||
} else if (landmark.imageURL!.contains("photos.app.goo.gl")) {
|
|
||||||
// the image is a google photos link, we should get the image behind the link
|
|
||||||
String? newUrl = await getImageUrlFromGooglePhotos(landmark.imageURL!);
|
|
||||||
// also set the new url if it is null
|
|
||||||
landmark.imageURL = newUrl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,37 +5,23 @@ import 'package:anyway/utils/load_trips.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Widget getFirstPage() {
|
Widget getFirstPage() {
|
||||||
SavedTrips trips = SavedTrips();
|
Future<List<Trip>> trips = loadTrips();
|
||||||
trips.loadTrips();
|
// test if there are any active trips
|
||||||
|
// if there are, return the trip list
|
||||||
return ListenableBuilder(
|
// if there are not, return the onboarding page
|
||||||
listenable: trips,
|
return FutureBuilder(
|
||||||
builder: (BuildContext context, Widget? child) {
|
future: trips,
|
||||||
List<Trip> items = trips.trips;
|
builder: (context, snapshot) {
|
||||||
if (items.isNotEmpty) {
|
if (snapshot.hasData) {
|
||||||
return TripPage(trip: items[0]);
|
List<Trip> availableTrips = snapshot.data!;
|
||||||
|
if (availableTrips.isNotEmpty) {
|
||||||
|
return TripPage(trip: availableTrips[0]);
|
||||||
} else {
|
} else {
|
||||||
return OnboardingPage();
|
return OnboardingPage();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return CircularProgressIndicator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// Future<List<Trip>> trips = loadTrips();
|
|
||||||
// // test if there are any active trips
|
|
||||||
// // if there are, return the trip list
|
|
||||||
// // if there are not, return the onboarding page
|
|
||||||
// return FutureBuilder(
|
|
||||||
// future: trips,
|
|
||||||
// builder: (context, snapshot) {
|
|
||||||
// if (snapshot.hasData) {
|
|
||||||
// List<Trip> availableTrips = snapshot.data!;
|
|
||||||
// if (availableTrips.isNotEmpty) {
|
|
||||||
// return TripPage(trip: availableTrips[0]);
|
|
||||||
// } else {
|
|
||||||
// return OnboardingPage();
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return CircularProgressIndicator();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
}
|
}
|
@ -58,14 +58,3 @@ Future<String?> getImageUrlFromName(String title) async {
|
|||||||
}
|
}
|
||||||
return await getImageUrl(pageId);
|
return await getImageUrl(pageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<String?> getImageUrlFromGooglePhotos(String url) async {
|
|
||||||
// this is a very simple implementation that just gets the image behind the link
|
|
||||||
// it is not guaranteed to work for all google photos links
|
|
||||||
final response = await dio.get(url);
|
|
||||||
final data = response.toString();
|
|
||||||
final int start = data.indexOf("https://lh3.googleusercontent.com");
|
|
||||||
final int end = data.indexOf('"', start);
|
|
||||||
return data.substring(start, end);
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
Future<List<Trip>> loadTrips() async {
|
||||||
|
|
||||||
class SavedTrips extends ChangeNotifier {
|
|
||||||
List<Trip> _trips = [];
|
|
||||||
|
|
||||||
List<Trip> get trips => _trips;
|
|
||||||
|
|
||||||
void loadTrips() async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
List<Trip> trips = [];
|
List<Trip> trips = [];
|
||||||
@ -19,21 +12,5 @@ class SavedTrips extends ChangeNotifier {
|
|||||||
trips.add(Trip.fromPrefs(prefs, uuid));
|
trips.add(Trip.fromPrefs(prefs, uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_trips = trips;
|
return trips;
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void addTrip(Trip trip) async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
trip.toPrefs(prefs);
|
|
||||||
_trips.add(trip);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearTrips () async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
prefs.clear();
|
|
||||||
_trips = [];
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user