first ui elements using the new structs
Some checks failed
Build and push docker image / Build (pull_request) Failing after 41s
Build and release APK / Build APK (pull_request) Successful in 5m25s
Build web / Build Web (pull_request) Successful in 1m17s

This commit is contained in:
2024-05-31 21:33:04 +02:00
parent 7e4538a1bf
commit 8bc7da0b3e
14 changed files with 336 additions and 226 deletions

View File

@@ -1,40 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class DestinationCard extends StatefulWidget {
final String title;
final String description;
final String image;
bool visited;
@override
_DestinationCardState createState() => _DestinationCardState();
DestinationCard(this.title, this.description, this.image, this.visited);
Widget build() {
return Card(
child: ListTile(
leading: Icon(Icons.location_on),
title: Text(title),
subtitle: Text(description),
onTap: () {
// Navigator.pushNamed(context, '/destination');
},
),
);
}
}
class _DestinationCardState extends State<DestinationCard> {
@override
Widget build(BuildContext context) {
return Card();
}
}

View File

@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
Widget Greeter (ThemeData theme, {bool full = false}) {
String greeterText = "";
try {
String cityName = getCityName();
greeterText = "Welcome to $cityName!";
} catch (e) {
greeterText = "Welcome ...";
}
Widget topGreeter = Text(
greeterText,
style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold),
maxLines: 1,
);
Widget bottomGreeter = Container();
if (full) {
bottomGreeter = Text(
"Busy day ahead? Here is how to make the most of it!",
style: TextStyle(color: Colors.black, fontSize: 18.0),
maxLines: 1,
);
}
Widget greeter = Center(
child: Column(
children: [
if (!full) Padding(padding: EdgeInsets.only(top: 24.0)),
topGreeter,
if (full) bottomGreeter,
Padding(padding: EdgeInsets.only(bottom: 24.0)),
],
),
);
return greeter;
}
String getCityName() {
return "Paris";
}

View File

@@ -0,0 +1,73 @@
import 'package:fast_network_navigation/structs/landmark.dart';
import 'package:flutter/material.dart';
class LandmarkCard extends StatefulWidget {
final Landmark landmark;
@override
_LandmarkCardState createState() => _LandmarkCardState();
LandmarkCard(this.landmark);
}
class _LandmarkCardState extends State<LandmarkCard> {
@override
Widget build(BuildContext context) {
ThemeData theme = Theme.of(context);
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Row(
children: [
Container(
width: 160,
height: 160,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15.0),
bottomLeft: Radius.circular(15.0),
),
image: DecorationImage(
image: NetworkImage('https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg'),
fit: BoxFit.cover,
),
),
),
Padding(
padding: EdgeInsets.all(10),
child: Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.landmark.name,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
SizedBox(height: 5),
Text(
"${widget.landmark.name} (${widget.landmark.type.name})",
style: TextStyle(fontSize: 14),
),
],
),
),
),
// Align(
// alignment: Alignment.topRight,
// child: Icon(Icons.push_pin, color: theme.primaryColor),
// ),
],
),
);
}
}

View File

@@ -0,0 +1,101 @@
import 'package:fast_network_navigation/modules/landmark_card.dart';
import 'package:fast_network_navigation/structs/landmark.dart';
import 'package:fast_network_navigation/utils/get_landmarks.dart';
import 'package:flutter/material.dart';
class loadLandmarksOverview extends StatefulWidget {
const loadLandmarksOverview({super.key});
@override
State<loadLandmarksOverview> createState() => _loadLandmarksOverviewState();
}
class _loadLandmarksOverviewState extends State<loadLandmarksOverview> {
final Future<List<Landmark>> _landmarks = fetchLandmarks();
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.displayMedium!,
textAlign: TextAlign.center,
child: FutureBuilder<List<Landmark>>(
future: _landmarks,
builder: (BuildContext context, AsyncSnapshot<List<Landmark>> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = [landmarksWithSteps(snapshot.data!)];
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
),
];
} else {
children = [LandmarkCard(Landmark(name: "loading", location: [0,0], type: LandmarkType(name: "loading")))];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
);
},
),
);
}
}
Widget landmarksWithSteps(List<Landmark> landmarks) {
List<Widget> children = [];
for (Landmark landmark in landmarks) {
children.add(LandmarkCard(landmark));
children.add(stepBetweenLandmarks());
}
return Column(
children: children.sublist(0, children.length - 1)
);
}
Widget stepBetweenLandmarks() {
// This is a simple widget that draws a line between landmark-cards
// It's a vertical dotted line
// Next to the line is the icon for the mode of transport (walking for now) and the estimated time
// There is also a button to open the navigation instructions as a new intent
return Row(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
border: Border(
left: BorderSide(width: 1.0, color: Colors.black),
),
),
child: Column(
children: [
Icon(Icons.directions_walk),
Text("5 min", style: TextStyle(fontSize: 10)),
],
),
),
Spacer(),
ElevatedButton(
onPressed: () {
// Open navigation instructions
},
child: Text("Navigate"),
),
],
);
}

View File

@@ -1,5 +1,5 @@
import 'package:fast_network_navigation/structs/landmark.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class MapWidget extends StatefulWidget {
@@ -9,16 +9,37 @@ class MapWidget extends StatefulWidget {
class _MapWidgetState extends State<MapWidget> {
late GoogleMapController mapController;
final LatLng _center = const LatLng(45.521563, -122.677433);
// coordinates of Paris
final LatLng _center = const LatLng(48.8566, 2.3522);
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
addLandmarks();
}
void _onCameraIdle() {
// print(mapController.getLatLng());
}
void addLandmarks() {
// // adds a marker for each landmark
// List<Landmark> landmarks = [
// Landmark(name: "Eiffel Tower", location: [48.8584, 2.2945], type: LandmarkType(name: "Type 1")),
// Landmark(name: "Louvre Museum", location: [48.8606, 2.3376], type: LandmarkType(name: "Type 1")),
// Landmark(name: "Notre-Dame Cathedral", location: [48.8529, 2.3499], type: LandmarkType(name: "Type 1")),
// Landmark(name: "Arc de Triomphe", location: [48.8738, 2.2950], type: LandmarkType(name: "Type 1")),
// Landmark(name: "Palace of Versailles", location: [48.8014, 2.1301], type: LandmarkType(name: "Type 1")),
// ];
// for (Landmark landmark in landmarks) {
// mapController.
// mapController.addMarker(MarkerOptions(
// position: LatLng(landmark.location[0], landmark.location[1]),
// infoWindowText: InfoWindowText(landmark.name, landmark.type.name),
// ));
// }
}
@override
Widget build(BuildContext context) {
return GoogleMap(
@@ -28,6 +49,8 @@ class _MapWidgetState extends State<MapWidget> {
zoom: 11.0,
),
onCameraIdle: _onCameraIdle,
// onLongPress: ,
// markers: #,
);
}
}

View File

@@ -1,63 +0,0 @@
import 'package:fast_network_navigation/modules/destination_card.dart';
import 'package:flutter/material.dart';
List<Widget> loadDestinations() {
List<Widget> cities = [
singleDestination(
"New York",
"The Big Apple",
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/View_of_New_York_City.jpg/800px-View_of_New_York_City.jpg"
),
singleDestination(
"Los Angeles",
"City of Angels",
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Los_Angeles_City_Hall_2013.jpg/800px-Los_Angeles_City_Hall_2013.jpg"
),
singleDestination(
"Chicago",
"The Windy City",
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Chicago_skyline%2C_viewed_from_John_Hancock_Center.jpg/800px-Chicago_skyline%2C_viewed_from_John_Hancock_Center.jpg"
),
singleDestination(
"San Francisco",
"The Golden City",
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/San_Francisco_City_Hall_2013.jpg/800px-San_Francisco_City_Hall_2013.jpg"
),
singleDestination(
"Miami",
"The Magic City",
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Miami_collage.jpg/800px-Miami_collage.jpg"
),
singleDestination(
"Las Vegas",
"Sin City",
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Las_Vegas_Strip.jpg/800px-Las_Vegas_Strip.jpg"
),
singleDestination(
"Seattle",
"Emerald City",
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Seattle_Kerry_Park_Skyline.jpg/800px-Seattle_Kerry_Park_Skyline.jpg"
),
singleDestination(
"Boston",
"Beantown",
"https://upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Boston_skyline_from_Longfellow_Bridge_September_2017_panorama_2.jpg/800px-Boston"
)
];
cities.shuffle();
return cities;
}
Widget singleDestination(String title, String description, String image) {
return Card(
child: ListTile(
leading: Icon(Icons.location_on),
title: Text(title),
subtitle: Text(description),
onTap: () {
// Navigator.pushNamed(context, '/destination');
},
),
);
}

View File

@@ -1,99 +0,0 @@
import 'package:flutter/material.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';
import 'package:geocode/geocode.dart';
import 'dart:async';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:fast_network_navigation/modules/navigation.dart';
import 'package:fast_network_navigation/modules/map.dart';
class NavigationOverview extends StatefulWidget {
@override
State<NavigationOverview> createState() => _NavigationOverviewState();
}
class Debounce {
Duration delay;
Timer? _timer;
Debounce(
this.delay,
);
call(void Function() callback) {
_timer?.cancel();
_timer = Timer(delay, callback);
}
dispose() {
_timer?.cancel();
}
}
class _NavigationOverviewState extends State<NavigationOverview> {
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return SlidingUpPanel(
renderPanelSheet: false,
panel: _floatingPanel(theme),
collapsed: _floatingCollapsed(theme),
body: MapWidget()
);
}
Widget _floatingCollapsed(ThemeData theme){
return Container(
decoration: BoxDecoration(
color: theme.canvasColor,
borderRadius: BorderRadius.only(topLeft: Radius.circular(24.0), topRight: Radius.circular(24.0)),
),
child: Greeting(theme)
);
}
Widget _floatingPanel(ThemeData theme){
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(24.0)),
boxShadow: [
BoxShadow(
blurRadius: 20.0,
color: theme.shadowColor,
),
]
),
child: Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Greeting(theme),
Text("Got a lot to do today! Here is a rundown:"),
...loadDestinations(),
],
),
),
),
),
);
}
Widget Greeting (ThemeData theme) {
return Center(
child: Text(
"Explore #todo",
style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold),
),
);
}
}

View File

@@ -1,91 +0,0 @@
import 'package:fast_network_navigation/structs/preferences.dart';
import 'package:flutter/material.dart';
class ProfilePage extends StatefulWidget {
@override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
@override
Widget build(BuildContext context) {
return ListView(
children: [
// First a round, centered image
Center(
child: CircleAvatar(
radius: 100,
child: Icon(Icons.person, size: 100),
)
),
Center(
child: Text('Curious traveler', style: TextStyle(fontSize: 24))
),
Padding(
padding: EdgeInsets.all(10),
),
Text('Please rate your preferences for the following activities:'),
// Now the sliders
ImportanceSliders()
]
);
}
}
class ImportanceSliders extends StatefulWidget {
@override
State<ImportanceSliders> createState() => _ImportanceSlidersState();
}
class _ImportanceSlidersState extends State<ImportanceSliders> {
UserPreferences _prefs = UserPreferences();
@override
void initState() {
super.initState();
_prefs.load();
}
List<Card> _createSliders() {
List<Card> sliders = [];
for (SinglePreference pref in _prefs.preferences) {
sliders.add(Card(
child: ListTile(
leading: pref.icon,
title: Text(pref.name),
subtitle: Slider(
value: pref.value.toDouble(),
min: 0,
max: 10,
divisions: 10,
label: pref.value.toString(),
onChanged: (double newValue) {
setState(() {
pref.value = newValue.toInt();
_prefs.save();
});
},
)
),
margin: EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0),
shadowColor: Colors.grey,
));
}
return sliders;
}
@override
Widget build(BuildContext context) {
return Column(children: _createSliders());
}
}