Skip to content

Commit 311fcb8

Browse files
authored
Merge pull request #88 from RealTeamRocket/65-map-display
65 map display
2 parents ab9eadd + 52a73b3 commit 311fcb8

19 files changed

Lines changed: 923 additions & 369 deletions

File tree

mobile_app/lib/main.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'utils/backend_api/backend_api.dart' as api;
1010
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
1111
import 'package:jwt_decoder/jwt_decoder.dart';
1212
import 'package:flutter_dotenv/flutter_dotenv.dart';
13-
import 'pages/pages.dart';
13+
import 'pages/pages.dart' as pages;
1414
import 'package:permission_handler/permission_handler.dart';
1515

1616
void main() async {
@@ -92,8 +92,8 @@ class MyAppState extends State<MyApp> {
9292
),
9393
home:
9494
isAuthenticated!
95-
? const HomePage(title: 'Rocket App')
96-
: const WelcomePage(),
95+
? const pages.AppNavigator(title: 'Rocket App')
96+
: const pages.WelcomePage(),
9797
routes: {'/settings': (context) => SettingsPage()},
9898
);
9999
}

mobile_app/lib/pages/leaderboard.dart

Lines changed: 201 additions & 172 deletions
Large diffs are not rendered by default.
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@ import '/widgets/widgets.dart';
44
import 'leaderboard.dart';
55
import 'pages.dart';
66

7-
class HomePage extends StatefulWidget {
8-
const HomePage({super.key, required this.title});
7+
class AppNavigator extends StatefulWidget {
8+
const AppNavigator({
9+
super.key,
10+
required this.title,
11+
this.initialIndex = 2, // Default to "Run" tab in the middle
12+
});
913

1014
final String title;
15+
final int initialIndex;
1116

1217
@override
13-
State<HomePage> createState() => _HomePageState();
18+
State<AppNavigator> createState() => _AppNavigatorState();
1419
}
1520

16-
class _HomePageState extends State<HomePage> {
17-
int _selectedIndex = 2; /// set position of starting page to homepage in the middle
21+
class _AppNavigatorState extends State<AppNavigator> {
22+
late int _selectedIndex;
1823

1924
final List<Widget> _pages = <Widget>[
2025
const ChallengePage(title: 'Challenges'),
@@ -24,6 +29,12 @@ class _HomePageState extends State<HomePage> {
2429
const ProfilePage(),
2530
];
2631

32+
@override
33+
void initState() {
34+
super.initState();
35+
_selectedIndex = widget.initialIndex;
36+
}
37+
2738
void _onItemTapped(int index) {
2839
setState(() {
2940
_selectedIndex = index;

mobile_app/lib/pages/pages.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
export 'home_page.dart';
1+
export 'navigator.dart';
22
export 'profile_page.dart';
33
export 'run_page.dart';
44
export 'start_pages/start_pages.dart';
55
export 'challenges_page.dart';
66
export 'friendlist_page.dart';
7+
export 'leaderboard.dart';

mobile_app/lib/pages/route.dart

Lines changed: 91 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,69 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
3-
import 'package:geolocator/geolocator.dart';
3+
import 'dart:math';
4+
5+
import 'package:mobile_app/pages/pages.dart';
46

57
class RoutePage extends StatefulWidget {
6-
const RoutePage({super.key, required this.title});
8+
const RoutePage({
9+
super.key,
10+
required this.title,
11+
required this.routePoints,
12+
required this.elapsedTime,
13+
});
714

815
final String title;
16+
final List<GeoPoint> routePoints;
17+
final String elapsedTime;
918

1019
@override
1120
State<RoutePage> createState() => _RoutePageState();
1221
}
1322

14-
Future<Position> _determinePosition() async {
15-
bool serviceEnabled;
16-
LocationPermission locationPermission;
17-
serviceEnabled = await Geolocator.isLocationServiceEnabled();
18-
if (!serviceEnabled) {
19-
return Future.error('Location services are disabled.');
20-
}
21-
locationPermission = await Geolocator.checkPermission();
22-
if (locationPermission == LocationPermission.denied) {
23-
locationPermission = await Geolocator.requestPermission();
24-
if (locationPermission == LocationPermission.denied) {
25-
return Future.error('Location permissions are denied');
26-
}
27-
}
28-
if (locationPermission == LocationPermission.deniedForever) {
29-
return Future.error(
30-
'Location permissions are permanently denied, we cannot request permissions.',
31-
);
32-
}
33-
return await Geolocator.getCurrentPosition();
34-
}
35-
3623
class _RoutePageState extends State<RoutePage> {
3724
GeoPoint? _initPosition;
38-
List<GeoPoint> _routePoints = [];
25+
late List<GeoPoint> _routePoints;
3926
late MapController _mapController;
40-
var distance = 0.0;
41-
var numOfGeoPoints = 0;
42-
var rocketPoints = 0;
27+
double distance = 0.0;
4328

4429
@override
4530
void initState() {
4631
super.initState();
47-
_setInitialPosition();
32+
_routePoints = widget.routePoints;
33+
_initPosition = _routePoints.isNotEmpty
34+
? _routePoints.first
35+
: GeoPoint(latitude: 48.61313, longitude: 9.45881);
4836
_mapController = MapController(
49-
initPosition: GeoPoint(latitude: 48.61313, longitude: 9.45881),
37+
initPosition: _initPosition!,
5038
);
39+
distance = _calculateTotalDistance(_routePoints);
5140
}
5241

53-
/// Here: Instead of the hardcoded points use the points from the list _routePoints
54-
Future<void> _setInitialPosition() async {
55-
try {
56-
setState(() {
57-
_initPosition = GeoPoint(latitude: 48.61313, longitude: 9.45881);
58-
_routePoints = [
59-
_initPosition!,
60-
GeoPoint(latitude: 48.6156, longitude: 9.45984),
61-
GeoPoint(latitude: 48.61651, longitude: 9.4549),
62-
];
63-
});
64-
} catch (e) {
65-
// Handle the error accordingly
66-
///Instead of print maybe don't show map and just show earned points and so on
67-
print(e);
42+
double _calculateTotalDistance(List<GeoPoint> points) {
43+
if (points.length < 2) return 0.0;
44+
double total = 0.0;
45+
for (int i = 0; i < points.length - 1; i++) {
46+
total += _calculateDistanceBetween(points[i], points[i + 1]);
6847
}
48+
return total;
49+
}
50+
51+
// Haversine formula for distance in km
52+
double _calculateDistanceBetween(GeoPoint a, GeoPoint b) {
53+
const double R = 6371; // Earth's radius in km
54+
double dLat = _deg2rad(b.latitude - a.latitude);
55+
double dLon = _deg2rad(b.longitude - a.longitude);
56+
double lat1 = _deg2rad(a.latitude);
57+
double lat2 = _deg2rad(b.latitude);
58+
59+
double hav = sin(dLat / 2) * sin(dLat / 2) +
60+
sin(dLon / 2) * sin(dLon / 2) * cos(lat1) * cos(lat2);
61+
double c = 2 * atan2(sqrt(hav), sqrt(1 - hav));
62+
return R * c;
6963
}
7064

65+
double _deg2rad(double deg) => deg * (pi / 180);
66+
7167
@override
7268
Widget build(BuildContext context) {
7369
return Scaffold(
@@ -76,88 +72,51 @@ class _RoutePageState extends State<RoutePage> {
7672
children: [
7773
SizedBox(
7874
height: 500,
79-
child:
80-
_initPosition == null
81-
? Center(child: CircularProgressIndicator())
82-
: OSMFlutter(
83-
controller: _mapController,
84-
osmOption: OSMOption(
85-
zoomOption: ZoomOption(
86-
minZoomLevel: 5,
87-
maxZoomLevel: 18,
88-
initZoom: 16,
89-
),
90-
userLocationMarker: UserLocationMaker(
91-
personMarker: MarkerIcon(
92-
icon: Icon(
93-
Icons.location_on,
94-
color: Colors.red,
95-
size: 48,
96-
),
75+
child: _initPosition == null || _routePoints.isEmpty
76+
? Center(child: Text("Keine Route verfügbar"))
77+
: OSMFlutter(
78+
controller: _mapController,
79+
osmOption: OSMOption(
80+
zoomOption: ZoomOption(
81+
minZoomLevel: 5,
82+
maxZoomLevel: 18,
83+
initZoom: 16,
84+
),
85+
userLocationMarker: UserLocationMaker(
86+
personMarker: MarkerIcon(
87+
icon: Icon(
88+
Icons.location_on,
89+
color: Colors.red,
90+
size: 48,
9791
),
98-
directionArrowMarker: MarkerIcon(
99-
icon: Icon(
100-
Icons.arrow_forward,
101-
color: Colors.blue,
102-
size: 48,
103-
),
92+
),
93+
directionArrowMarker: MarkerIcon(
94+
icon: Icon(
95+
Icons.arrow_forward,
96+
color: Colors.blue,
97+
size: 48,
10498
),
10599
),
106100
),
107-
mapIsLoading: Center(child: CircularProgressIndicator()),
108-
onMapIsReady: (isReady) async {
109-
RoadInfo roadInfo;
110-
///Here draw the map and get the distance from point to point
111-
for(var point in _routePoints){
112-
/**
113-
* Checks if all points have been already used
114-
*/
115-
if(numOfGeoPoints == _routePoints.length){
116-
break;
117-
}
118-
numOfGeoPoints++;
119-
/**
120-
* Draws the road between the last and first point
121-
*/
122-
if(_routePoints.indexOf(point) == _routePoints.length-1){
123-
roadInfo = await _mapController.drawRoad(
124-
point,
125-
_routePoints[0],
126-
roadType: RoadType.foot,
127-
roadOption: RoadOption(
128-
roadColor: Colors.yellow,
129-
roadWidth: 8,
130-
),
131-
);
132-
distance += roadInfo.distance ?? 0;
133-
/**
134-
* Draws road between each other point 0->1, 1->2, ...
135-
*/
136-
}else{
137-
roadInfo = await _mapController.drawRoad(
138-
point,
139-
_routePoints[_routePoints.indexOf(point) + 1],
140-
roadType: RoadType.foot,
141-
roadOption: RoadOption(
142-
roadColor: Colors.yellow,
143-
roadWidth: 8,
144-
),
145-
);
146-
/**
147-
* Adds the distance of the road to the total distance
148-
*/
149-
distance += roadInfo.distance ?? 0;
150-
setState(() {
151-
distance = double.parse(distance.toStringAsFixed(2));
152-
});
153-
}
154-
}
155-
// Logik für die Karte
156-
},
157-
onGeoPointClicked: (geoPoint) {
158-
// Behandlung des Klicks auf einen Geopunkt
159-
},
160101
),
102+
mapIsLoading: Center(child: CircularProgressIndicator()),
103+
onMapIsReady: (isReady) async {
104+
if (_routePoints.length > 1) {
105+
for (int i = 0; i < _routePoints.length - 1; i++) {
106+
await _mapController.drawRoad(
107+
_routePoints[i],
108+
_routePoints[i + 1],
109+
roadType: RoadType.foot,
110+
roadOption: RoadOption(
111+
roadColor: Colors.yellow,
112+
roadWidth: 8,
113+
),
114+
);
115+
}
116+
}
117+
},
118+
onGeoPointClicked: (geoPoint) {},
119+
),
161120
),
162121
Container(
163122
padding: const EdgeInsets.all(16.0),
@@ -169,39 +128,33 @@ class _RoutePageState extends State<RoutePage> {
169128
mainAxisAlignment: MainAxisAlignment.spaceBetween,
170129
children: [
171130
Text(
172-
"Distanz: ${distance.toStringAsFixed(2)} km",
131+
"Distance: ${distance.toStringAsFixed(2)} km",
173132
style: TextStyle(
174133
fontSize: 16,
175134
fontWeight: FontWeight.bold,
176135
),
177136
),
178137
Text(
179-
"Dauer: 00:45:30",
138+
"Time: ${widget.elapsedTime}",
180139
style: TextStyle(
181140
fontSize: 16,
182141
fontWeight: FontWeight.bold,
183142
),
184143
),
185144
],
186145
),
187-
SizedBox(height: 8),
188-
Center(
189-
child: Text(
190-
"Punkte: ${distance.floor()}",
191-
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
192-
),
193-
),
194-
/**
195-
* Here: Possible to add the challenges that are completed
196-
*/
197146
SizedBox(height: 16),
198147
Center(
199148
child: ElevatedButton(
200149
onPressed: () {
201-
/**
202-
* Here: Navigate back to the main app screen
203-
*/
204-
},
150+
Navigator.pushAndRemoveUntil(
151+
context,
152+
MaterialPageRoute(
153+
builder: (context) => AppNavigator(title: 'Rocket App', initialIndex: 2),
154+
),
155+
(route) => false,
156+
);
157+
},
205158
child: Text("Back To App"),
206159
),
207160
),
@@ -213,13 +166,3 @@ class _RoutePageState extends State<RoutePage> {
213166
);
214167
}
215168
}
216-
217-
void main() {
218-
runApp(
219-
MaterialApp(
220-
title: 'Route Page',
221-
theme: ThemeData(primarySwatch: Colors.blue),
222-
home: RoutePage(title: 'Completed Run'),
223-
),
224-
);
225-
}

0 commit comments

Comments
 (0)