diff --git a/README.md b/README.md
index d19d7061..0e601f45 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,11 @@ Make sure Node.js, Flutter, and Docker are installed!
npm run setup
```
+### API Keys for Flutter
+```
+To access the Google Maps in the CornellGo app, you need two Google Maps API Keys. One is for Android and one is for iOS. Ask a TPM for the .env file with the keys and the instructions to add it into the app.
+```
+
### Run project in container
```
diff --git a/game/.gitignore b/game/.gitignore
index 952722ca..ab7fa15a 100644
--- a/game/.gitignore
+++ b/game/.gitignore
@@ -44,3 +44,6 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
+
+# Secret API Keys
+*.env
\ No newline at end of file
diff --git a/game/android/app/build.gradle b/game/android/app/build.gradle
index 1ad2bd46..be8576be 100644
--- a/game/android/app/build.gradle
+++ b/game/android/app/build.gradle
@@ -31,6 +31,8 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'com.google.gms.google-services'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+apply from: project(':flutter_config').projectDir.getPath() + "/dotenv.gradle"
+
android {
compileSdkVersion 33
diff --git a/game/android/app/src/main/AndroidManifest.xml b/game/android/app/src/main/AndroidManifest.xml
index 9c839461..852baa93 100644
--- a/game/android/app/src/main/AndroidManifest.xml
+++ b/game/android/app/src/main/AndroidManifest.xml
@@ -2,7 +2,12 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/game/assets/icons/userlocation.png b/game/assets/icons/userlocation.png
new file mode 100644
index 00000000..9193d251
Binary files /dev/null and b/game/assets/icons/userlocation.png differ
diff --git a/game/ios/Runner/AppDelegate.swift b/game/ios/Runner/AppDelegate.swift
index 716e80f7..1d7f1447 100644
--- a/game/ios/Runner/AppDelegate.swift
+++ b/game/ios/Runner/AppDelegate.swift
@@ -1,6 +1,8 @@
import UIKit
import Flutter
import Firebase
+import GoogleMaps
+import flutter_config
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
@@ -10,6 +12,7 @@ import Firebase
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
FirebaseApp.configure()
+ GMSServices.provideAPIKey(FlutterConfigPlugin.env(for: "IOS_MAP_API_KEY"))
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
diff --git a/game/lib/api/geopoint.dart b/game/lib/api/geopoint.dart
index b2d6ef95..bb0b90ad 100644
--- a/game/lib/api/geopoint.dart
+++ b/game/lib/api/geopoint.dart
@@ -1,19 +1,28 @@
+import 'dart:async';
+import 'dart:io' show Platform;
import 'package:geolocator/geolocator.dart';
class GeoPoint {
static bool didMakeRequest = false;
double _lat = 0;
double _long = 0;
+ double _heading = 0;
double get lat => _lat;
double get long => _long;
+ double get heading => _heading;
static bool _isRequestingLocationPermissions = false;
static bool _isRequestingLocation = false;
- GeoPoint(double lat, double long) {
+ GeoPoint(
+ double lat,
+ double long,
+ double heading,
+ ) {
_lat = lat;
_long = long;
+ _heading = heading;
}
static Future current() async {
@@ -37,7 +46,7 @@ class GeoPoint {
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
- return Future.error('Location permissions are denied');
+ return Future.error('Location services are disabled.');
}
}
if (permission == LocationPermission.deniedForever) {
@@ -46,7 +55,7 @@ class GeoPoint {
'Location permissions are permanently denied, we cannot request permissions.');
}
final pos = await Geolocator.getCurrentPosition();
- return GeoPoint(pos.latitude, pos.longitude);
+ return GeoPoint(pos.latitude, pos.longitude, pos.heading);
} catch (e) {
return Future.error(e.toString());
}
@@ -59,4 +68,40 @@ class GeoPoint {
double bearingTo(GeoPoint other) {
return Geolocator.bearingBetween(_lat, _long, other._lat, other._long);
}
+
+ static LocationSettings getLocationSettings() {
+ late LocationSettings locationSettings;
+
+ if (Platform.isAndroid) {
+ locationSettings = AndroidSettings(
+ accuracy: LocationAccuracy.high,
+ distanceFilter: 100,
+ forceLocationManager: true,
+ intervalDuration: const Duration(seconds: 10),
+ //(Optional) Set foreground notification config to keep the app alive
+ //when going to the background
+ foregroundNotificationConfig: const ForegroundNotificationConfig(
+ notificationText:
+ "CornellGO will continue to receive your location even when you aren't using it",
+ notificationTitle: "Running in Background",
+ enableWakeLock: true,
+ ));
+ } else if (Platform.isIOS || Platform.isMacOS) {
+ locationSettings = AppleSettings(
+ accuracy: LocationAccuracy.high,
+ activityType: ActivityType.fitness,
+ distanceFilter: 100,
+ pauseLocationUpdatesAutomatically: true,
+ // Only set to true if our app will be started up in the background.
+ showBackgroundLocationIndicator: false,
+ );
+ } else {
+ locationSettings = LocationSettings(
+ accuracy: LocationAccuracy.high,
+ distanceFilter: 100,
+ );
+ }
+
+ return locationSettings;
+ }
}
diff --git a/game/lib/challenges/challenges_page.dart b/game/lib/challenges/challenges_page.dart
index 051fae02..262fd4b8 100644
--- a/game/lib/challenges/challenges_page.dart
+++ b/game/lib/challenges/challenges_page.dart
@@ -3,6 +3,7 @@ import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/src/widgets/placeholder.dart';
import 'challenge_cell.dart';
+import 'package:game/journeys/filter_form.dart';
class ChallengesPage extends StatefulWidget {
const ChallengesPage({Key? key}) : super(key: key);
@@ -12,6 +13,17 @@ class ChallengesPage extends StatefulWidget {
}
class _ChallengesPageState extends State {
+ void openFilter() {
+ showModalBottomSheet(
+ context: context,
+ isScrollControlled: true,
+ builder: (
+ BuildContext context,
+ ) {
+ return FilterForm();
+ });
+ }
+
/* Dummy code, to be replaced */
final cells = [
ChallengeCell(
@@ -93,25 +105,33 @@ class _ChallengesPageState extends State {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
- padding: EdgeInsets.zero,
- color: Color.fromARGB(76, 217, 217, 217),
+ height: 30,
child: TextButton.icon(
- onPressed: () {},
- icon: Icon(
- Icons.tune,
- color: Color.fromARGB(204, 0, 0, 0),
- size: 12,
- ),
- label: Text(
- "filter",
- style: TextStyle(
- color: Color.fromARGB(204, 0, 0, 0),
- fontSize: 12,
- fontFamily: 'Lato',
- fontWeight: FontWeight.w600,
+ onPressed: openFilter,
+ icon: Icon(
+ Icons.filter_list_rounded,
+ color: Color.fromARGB(255, 0, 0, 0),
+ size: 20.0,
+ ),
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Color.fromARGB(153, 217, 217, 217)),
+ padding: MaterialStateProperty.all(
+ EdgeInsets.only(right: 16.0, left: 16.0),
+ ),
+ shape: MaterialStateProperty.all(
+ RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(3.0),
+ )),
),
- ),
- ),
+ label: Text(
+ "Filter By",
+ style: TextStyle(
+ color: Color.fromARGB(255, 0, 0, 0),
+ fontSize: 15,
+ fontFamily: 'Inter',
+ ),
+ )),
),
],
),
diff --git a/game/lib/gameplay/gameplay_map.dart b/game/lib/gameplay/gameplay_map.dart
index 49780cb8..40cf373a 100644
--- a/game/lib/gameplay/gameplay_map.dart
+++ b/game/lib/gameplay/gameplay_map.dart
@@ -1,6 +1,10 @@
-import 'package:flutter/src/widgets/framework.dart';
-import 'package:flutter_map/flutter_map.dart';
-import 'package:latlong2/latlong.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+import 'package:game/api/geopoint.dart';
+import 'package:geolocator/geolocator.dart';
+import 'dart:async';
class GameplayMap extends StatefulWidget {
const GameplayMap({Key? key}) : super(key: key);
@@ -10,20 +14,278 @@ class GameplayMap extends StatefulWidget {
}
class _GameplayMapState extends State {
- final mapController = MapController();
+ late Completer mapCompleter = Completer();
+ late StreamSubscription positionStream;
+
@override
- Widget build(BuildContext context) {
- return FlutterMap(
- options: MapOptions(
- center: LatLng(51.509364, -0.128928),
- zoom: 9.2,
+ void initState() {
+ setCustomMarkerIcon();
+ startPositionStream();
+ super.initState();
+ }
+
+ // User is by default centered around some location on Cornell's campus.
+ // User should only be at these coords briefly before map is moved to user's
+ // current location.
+ final LatLng _center = const LatLng(42.447, -76.4875);
+
+ // User's current location will fall back to _center when current location
+ // cannot be found
+ GeoPoint? currentLocation;
+
+ // hard coded target for testing
+ // TODO: connect target location and radius to backend
+ GeoPoint targetLocation = GeoPoint(42.4475, -76.4879, 0);
+ double arrivalRadius = 10.0;
+
+ // whether the picture is expanded over the map
+ bool isExpanded = false;
+
+ Future _onMapCreated(GoogleMapController controller) async {
+ mapCompleter.complete(controller);
+ }
+
+ /**
+ * Starts the user's current location streaming upon state initialization
+ * Sets the camera to center on user's location by default
+ */
+ void startPositionStream() async {
+ GoogleMapController googleMapController = await mapCompleter.future;
+
+ GeoPoint.current().then(
+ (location) {
+ currentLocation = location;
+ },
+ );
+
+ positionStream = Geolocator.getPositionStream(
+ locationSettings: GeoPoint.getLocationSettings())
+ .listen((Position? newPos) {
+ // prints user coordinates - useful for debugging
+ // print(newPos == null
+ // ? 'Unknown'
+ // : '${newPos.latitude.toString()}, ${newPos.longitude.toString()}');
+
+ // putting the animate camera logic in here seems to not work
+ // could be useful to debug later?
+ currentLocation = newPos == null
+ ? GeoPoint(_center.latitude, _center.longitude, 0)
+ : GeoPoint(newPos.latitude, newPos.longitude, newPos.heading);
+ });
+
+ positionStream.onData((newPos) {
+ currentLocation =
+ GeoPoint(newPos.latitude, newPos.longitude, newPos.heading);
+
+ // upon new user location data, moves map camera to be centered around
+ // new position and sets zoom.
+ googleMapController.animateCamera(
+ CameraUpdate.newCameraPosition(
+ CameraPosition(
+ target: LatLng(newPos.latitude, newPos.longitude),
+ zoom: 16.5,
+ ),
+ ),
+ );
+ setState(() {});
+ });
+ }
+
+ /**
+ * Recenters the camera onto the user's current location and will keep
+ * camera centered until position stream's event handler is replaced
+ */
+ void recenterCamera() async {
+ GoogleMapController googleMapController = await mapCompleter.future;
+
+ googleMapController.animateCamera(
+ CameraUpdate.newCameraPosition(
+ CameraPosition(
+ target: LatLng(currentLocation!.lat, currentLocation!.long),
+ zoom: 16.5,
+ ),
),
- children: [
- TileLayer(
- urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
- userAgentPackageName: 'dev.fleaflet.flutter_map.example',
+ );
+
+ positionStream.onData((newPos) {
+ currentLocation =
+ GeoPoint(newPos.latitude, newPos.longitude, newPos.heading);
+
+ // upon new user location data, moves map camera to be centered around
+ // new position and sets zoom.
+ googleMapController.animateCamera(
+ CameraUpdate.newCameraPosition(
+ CameraPosition(
+ target: LatLng(newPos.latitude, newPos.longitude),
+ zoom: 16.5,
+ ),
),
- ],
+ );
+ setState(() {});
+ });
+ }
+
+ /**
+ * Replaces the position stream event handler to stop recentering the
+ * camera on the user's location
+ */
+ void cancelRecenterCamera() async {
+ positionStream.onData((newPos) {
+ currentLocation =
+ GeoPoint(newPos.latitude, newPos.longitude, newPos.heading);
+ setState(() {});
+ });
+ }
+
+ BitmapDescriptor currentLocationIcon = BitmapDescriptor.defaultMarker;
+ void setCustomMarkerIcon() {
+ BitmapDescriptor.fromAssetImage(
+ ImageConfiguration.empty, "assets/icons/userlocation.png")
+ .then(
+ (icon) {
+ currentLocationIcon = icon;
+ },
+ );
+ setState(() {});
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ theme: ThemeData(
+ useMaterial3: true,
+ colorSchemeSeed: Colors.green[700],
+ ),
+ home: Scaffold(
+ body: Listener(
+ onPointerDown: (e) {
+ cancelRecenterCamera();
+ },
+ child: GoogleMap(
+ onMapCreated: _onMapCreated,
+ compassEnabled: false,
+ myLocationButtonEnabled: false,
+ zoomControlsEnabled: false,
+ myLocationEnabled: false,
+ mapToolbarEnabled: false,
+ mapType: MapType.normal,
+ initialCameraPosition: CameraPosition(
+ target: currentLocation == null
+ ? _center
+ : LatLng(currentLocation!.lat, currentLocation!.lat),
+ zoom: 11,
+ ),
+ markers: {
+ Marker(
+ markerId: const MarkerId("currentLocation"),
+ icon: currentLocationIcon,
+ position: currentLocation == null
+ ? _center
+ : LatLng(currentLocation!.lat, currentLocation!.long),
+ rotation:
+ currentLocation == null ? 0 : currentLocation!.heading,
+ ),
+ },
+ circles: {
+ Circle(
+ circleId: CircleId("hintCircle"),
+ center: LatLng(targetLocation.lat, targetLocation.long),
+ radius: 100,
+ strokeColor: Color.fromARGB(80, 30, 41, 143),
+ strokeWidth: 2,
+ fillColor: Color.fromARGB(80, 83, 134, 237),
+ )
+ },
+ ),
+ ),
+ floatingActionButton: Stack(
+ alignment: AlignmentDirectional.topEnd,
+ children: [
+ Column(
+ mainAxisAlignment: MainAxisAlignment.end,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ Padding(
+ padding: EdgeInsets.only(bottom: 15.0),
+ child: FloatingActionButton.extended(
+ onPressed: recenterCamera,
+ label: Icon(Icons.lightbulb,
+ color: Color.fromARGB(255, 223, 84, 84)),
+ backgroundColor: Color.fromARGB(255, 255, 255, 255),
+ shape: CircleBorder(),
+ ),
+ ),
+ Padding(
+ padding: EdgeInsets.only(bottom: 150.0),
+ child: FloatingActionButton.extended(
+ onPressed: recenterCamera,
+ label: Icon(Icons.location_on,
+ color: Color.fromARGB(255, 223, 84, 84)),
+ backgroundColor: Color.fromARGB(255, 255, 255, 255),
+ shape: CircleBorder(),
+ ),
+ ),
+ ],
+ ),
+ Padding(
+ padding: EdgeInsets.only(left: 24.0, top: 40.0),
+ child: isExpanded
+ ? Container(
+ width: MediaQuery.of(context).size.width * 0.9,
+ height: MediaQuery.of(context).size.height * 0.9,
+ alignment: Alignment.topCenter,
+ child: Stack(
+ alignment: Alignment.topRight,
+ children: [
+ Image.asset('assets/images/main-bg.jpeg'),
+ Padding(
+ padding: EdgeInsets.all(8.0),
+ child: FloatingActionButton(
+ onPressed: () {
+ setState(() {
+ isExpanded = false;
+ });
+ },
+ child: Icon(Icons.close,
+ color: Color.fromARGB(255, 223, 84, 84)),
+ backgroundColor:
+ Color.fromARGB(255, 255, 255, 255),
+ shape: CircleBorder(),
+ ),
+ )
+ ],
+ ),
+ )
+ : GestureDetector(
+ onTap: () {
+ setState(() {
+ isExpanded = true;
+ });
+ },
+ child: Stack(
+ alignment: Alignment.topRight,
+ children: [
+ ClipRRect(
+ borderRadius: BorderRadius.circular(10),
+ child: Image.asset(
+ 'assets/images/main-bg.jpeg',
+ fit: BoxFit.cover,
+ width: 100,
+ height: 120,
+ ),
+ ),
+ Padding(
+ padding: EdgeInsets.all(4.0),
+ child: Icon(Icons.circle,
+ size: 50,
+ color: Color.fromARGB(255, 255, 255, 255)),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ )),
);
}
}
diff --git a/game/lib/gameplay/gameplay_page.dart b/game/lib/gameplay/gameplay_page.dart
index d88258b9..daebe849 100644
--- a/game/lib/gameplay/gameplay_page.dart
+++ b/game/lib/gameplay/gameplay_page.dart
@@ -122,40 +122,31 @@ class _GameplayPageState extends State {
child: Stack(
alignment: Alignment.bottomCenter,
children: [
- //Event Picture and google map
- Stack(alignment: Alignment.topRight, children: [
- Container(
- height: double.infinity,
- width: double.infinity,
- //Change to challenge picture
- child: Image.network(
- 'https://picsum.photos/500/1500',
- fit: BoxFit.fitWidth,
- ),
- ),
- Container(
- height: 100,
- width: 100,
- padding: EdgeInsets.all(10),
- margin: EdgeInsets.only(top: 15, right: 15),
- child: Text(
- "MAP",
- style: TextStyle(fontSize: 21, color: Color(0xFFED5656)),
- ),
- decoration: BoxDecoration(
- color: Color.fromARGB(255, 255, 255, 255),
- borderRadius: BorderRadius.all(Radius.circular(10)),
- boxShadow: [
- BoxShadow(
- color: Colors.grey.withOpacity(0.5),
- spreadRadius: 1,
- blurRadius: 1,
- offset: Offset(0, 3), // shadow direction: bottom
- ),
- ],
- ),
- ),
- ]),
+ Padding(
+ padding: EdgeInsets.only(top: 20), child: GameplayMap()),
+ // //Event Picture
+ // Container(
+ // height: 100,
+ // width: 100,
+ // padding: EdgeInsets.all(10),
+ // margin: EdgeInsets.only(top: 15, right: 15),
+ // child: Text(
+ // "MAP",
+ // style: TextStyle(fontSize: 21, color: Color(0xFFED5656)),
+ // ),
+ // decoration: BoxDecoration(
+ // color: Color.fromARGB(255, 255, 255, 255),
+ // borderRadius: BorderRadius.all(Radius.circular(10)),
+ // boxShadow: [
+ // BoxShadow(
+ // color: Colors.grey.withOpacity(0.5),
+ // spreadRadius: 1,
+ // blurRadius: 1,
+ // offset: Offset(0, 3), // shadow direction: bottom
+ // ),
+ // ],
+ // ),
+ // ),
Container(
margin: EdgeInsets.only(bottom: 70),
child: ElevatedButton(
diff --git a/game/lib/main.dart b/game/lib/main.dart
index cbeaabeb..3b7f40a7 100644
--- a/game/lib/main.dart
+++ b/game/lib/main.dart
@@ -1,8 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:flutter_config/flutter_config.dart';
+
+// imports for google maps
+import 'dart:io' show Platform;
+import 'dart:async';
+import 'package:google_maps_flutter_android/google_maps_flutter_android.dart';
+import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
+
+// api and widget imports
import 'package:game/api/game_api.dart';
import 'package:game/gameplay/gameplay_page.dart';
+import 'package:game/gameplay/gameplay_map.dart';
import 'package:game/global_leaderboard/global_leaderboard_widget.dart';
import 'package:game/journeys/journeys_page.dart';
import 'package:game/model/challenge_model.dart';
@@ -29,11 +39,47 @@ final LOOPBACK =
(Platform.isAndroid ? "http://10.0.2.2:8080" : "http://0.0.0.0:8080");
final API_URL = ENV_URL == "" ? LOOPBACK : ENV_URL;
-void main() {
+void main() async {
print(API_URL);
+ final GoogleMapsFlutterPlatform platform = GoogleMapsFlutterPlatform.instance;
+ // should only apply to Android - needs to be tested for iOS
+ if (platform is GoogleMapsFlutterAndroid) {
+ (platform as GoogleMapsFlutterAndroid).useAndroidViewSurface = true;
+ initializeMapRenderer();
+ }
+ // load environment variables
+ WidgetsFlutterBinding.ensureInitialized(); // Required by FlutterConfig
+ await FlutterConfig.loadEnvVariables();
+
runApp(MyApp());
}
+Completer? _initializedRendererCompleter;
+
+/// Initializes map renderer to the `latest` renderer type.
+///
+/// The renderer must be requested before creating GoogleMap instances,
+/// as the renderer can be initialized only once per application context.
+Future initializeMapRenderer() async {
+ if (_initializedRendererCompleter != null) {
+ return _initializedRendererCompleter!.future;
+ }
+
+ final Completer completer =
+ Completer();
+ _initializedRendererCompleter = completer;
+
+ WidgetsFlutterBinding.ensureInitialized();
+
+ final GoogleMapsFlutterPlatform platform = GoogleMapsFlutterPlatform.instance;
+ unawaited((platform as GoogleMapsFlutterAndroid)
+ .initializeWithRenderer(AndroidMapRenderer.latest)
+ .then((AndroidMapRenderer initializedRenderer) =>
+ completer.complete(initializedRenderer)));
+
+ return completer.future;
+}
+
final client = ApiClient(storage, API_URL);
class MyApp extends StatelessWidget {
@@ -76,6 +122,7 @@ class MyApp extends StatelessWidget {
theme: ThemeData(
fontFamily: 'Poppins', primarySwatch: ColorPalette.BigRed),
home: SplashPageWidget(),
+ // home: GameplayMap(),
)));
}
}
diff --git a/game/lib/preview/preview.dart b/game/lib/preview/preview.dart
index fd630947..57a6e51e 100644
--- a/game/lib/preview/preview.dart
+++ b/game/lib/preview/preview.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
+import 'package:game/gameplay/gameplay_page.dart';
enum previewType { challenge, journey }
@@ -393,6 +394,10 @@ class _PreviewState extends State {
side: BorderSide(color: backgroundRed)))),
onPressed: () {
print("Unimplemented. Starting Challenge!");
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => GameplayPage()));
},
child: Text(
"Continue exploring",
diff --git a/game/lib/profile/achievement_cell.dart b/game/lib/profile/achievement_cell.dart
index 9e643935..cd8396f6 100644
--- a/game/lib/profile/achievement_cell.dart
+++ b/game/lib/profile/achievement_cell.dart
@@ -14,8 +14,8 @@ Widget achievementCell(
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
- width: 380,
- height: 100,
+ width: 345,
+ height: 88,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
@@ -29,8 +29,7 @@ Widget achievementCell(
child: Row(
children: [
Padding(
- padding: const EdgeInsets.only(
- left: 18.0, top: 15, bottom: 15, right: 15),
+ padding: const EdgeInsets.all(10),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image(
@@ -49,7 +48,7 @@ Widget achievementCell(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
- width: 250,
+ width: 215,
child: Text(
name,
overflow: TextOverflow.ellipsis,
@@ -66,8 +65,8 @@ Widget achievementCell(
children: [
Stack(children: [
Container(
- width: 200,
- height: 20,
+ width: 170,
+ height: 13,
alignment: Alignment.centerLeft,
child: Container(
decoration: new BoxDecoration(
@@ -81,8 +80,8 @@ Widget achievementCell(
Container(
width:
(totalTasks > 0 ? tasksFinished / totalTasks : 0) *
- 200,
- height: 20,
+ 170,
+ height: 13,
alignment: Alignment.centerLeft,
child: Container(
decoration: new BoxDecoration(
diff --git a/game/lib/profile/completed_cell.dart b/game/lib/profile/completed_cell.dart
index c7b141ae..025607e1 100644
--- a/game/lib/profile/completed_cell.dart
+++ b/game/lib/profile/completed_cell.dart
@@ -17,8 +17,8 @@ Widget completedCell(String name, String picture, String type, String date,
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
- width: 380,
- height: 100,
+ width: 345,
+ height: 88,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
@@ -32,8 +32,7 @@ Widget completedCell(String name, String picture, String type, String date,
child: Row(
children: [
Padding(
- padding: const EdgeInsets.only(
- left: 18.0, top: 15, bottom: 15, right: 15),
+ padding: const EdgeInsets.all(10),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image(
@@ -63,7 +62,7 @@ Widget completedCell(String name, String picture, String type, String date,
children: [
Text(
"From " + type + " - ",
- style: TextStyle(color: Colors.grey),
+ style: TextStyle(color: Colors.grey, fontSize: 12),
),
Text(date)
],
diff --git a/game/lib/profile/profile_page.dart b/game/lib/profile/profile_page.dart
index f3584264..23c8a08b 100644
--- a/game/lib/profile/profile_page.dart
+++ b/game/lib/profile/profile_page.dart
@@ -19,35 +19,24 @@ class _ProfilePageState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- backgroundColor: Color.fromARGB(255, 255, 245, 234),
- body: Container(
- child: Column(
- children: [
- Align(
- alignment: Alignment.topRight,
- child: Padding(
- padding: const EdgeInsets.only(top: 35, right: 20),
- child: IconButton(
- alignment: Alignment.topRight,
- icon: Icon(Icons.settings, size: 40),
- onPressed: () {
- Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => SettingsPage()));
- }),
- ),
- ),
- Container(
- height: 120,
- child: Stack(
- children: [
- Center(
- child: Image(
- image: AssetImage("assets/images/user_2@2x.png"),
+ backgroundColor: Color.fromARGB(255, 255, 245, 234),
+ body: SafeArea(
+ child: Container(
+ child: Column(
+ children: [
+ Stack(fit: StackFit.passthrough, children: [
+ Center(
+ child: Container(
+ height: 140,
+ padding: EdgeInsets.only(top: 30),
+ child: Stack(
+ children: [
+ Center(
+ child: Image(
+ image: AssetImage("assets/images/user_2@2x.png"),
+ ),
),
- ),
- Align(
+ Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 30,
@@ -66,84 +55,102 @@ class _ProfilePageState extends State {
),
),
),
- )),
- ],
+ ),
+ ),
+ ],
+ ),
),
),
- Padding(
- padding: const EdgeInsets.all(5.0),
- child: Text(
- "Hanan Abraha",
- style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
+ Positioned.directional(
+ textDirection: TextDirection.rtl,
+ start: 10,
+ // top: 22,
+ child: Padding(
+ padding: const EdgeInsets.only(top: 10, right: 20),
+ child: IconButton(
+ alignment: Alignment.topRight,
+ icon: Icon(Icons.settings, size: 40),
+ onPressed: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => SettingsPage()));
+ }),
),
),
- Padding(
- padding: const EdgeInsets.only(bottom: 8.0),
- child: Text("@Hanan Abraha"),
+ ]),
+ Padding(
+ padding: const EdgeInsets.all(5.0),
+ child: Text(
+ "Hanan Abraha",
+ style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
- Padding(
- padding: const EdgeInsets.only(left: 20, right: 20),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Text("Achievements",
- style: TextStyle(
- fontSize: 20, fontWeight: FontWeight.bold)),
- TextButton(
- onPressed: () {
- // Handle button press, e.g., navigate to details page
- print('View Details button pressed');
- },
- child: Text(
- 'View Details →',
- style: TextStyle(
- color: Colors.black,
- fontSize: 16.0,
- ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 8.0),
+ child: Text("@Hanan Abraha"),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 24, right: 24),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text("Achievements",
+ style:
+ TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
+ TextButton(
+ onPressed: () {
+ // Handle button press, e.g., navigate to details page
+ print('View Details button pressed');
+ },
+ child: Text(
+ 'View Details →',
+ style: TextStyle(
+ color: Colors.black,
+ fontSize: 14.0,
),
- )
- ],
- ),
+ ),
+ )
+ ],
),
- achievementCell("Complete three challenges on the Arts quad", 4,
- 6, locationImage),
- achievementCell(
- "Complete three challenges on the Engineering quad",
- 4,
- 6,
- locationImage),
- Padding(
- padding: const EdgeInsets.only(left: 20, right: 20.0),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Text("Completed",
- style: TextStyle(
- fontSize: 20, fontWeight: FontWeight.bold)),
- TextButton(
- onPressed: () {
- // Handle button press, e.g., navigate to details page
- print('View Details button pressed');
- },
- child: Text(
- 'View More →',
- style: TextStyle(
- color: Colors.black,
- fontSize: 16.0,
- ),
+ ),
+ achievementCell("Complete three challenges on the Arts quad", 4, 6,
+ locationImage),
+ achievementCell("Complete three challenges on the Engineering quad",
+ 4, 6, locationImage),
+ Padding(
+ padding: const EdgeInsets.only(left: 24, right: 24.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Text("Completed",
+ style:
+ TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
+ TextButton(
+ onPressed: () {
+ // Handle button press, e.g., navigate to details page
+ print('View Details button pressed');
+ },
+ child: Text(
+ 'View More →',
+ style: TextStyle(
+ color: Colors.black,
+ fontSize: 14.0,
),
- )
- ],
- ),
+ ),
+ )
+ ],
),
- completedCell("Cornell Cafes", locationImage, "Journeys",
- "January 19, 2023", "Arts Quad", "Easy", 120),
- completedCell("Cornell Cafes", locationImage, "Journeys",
- "January 19, 2023", "Arts Quad", "Easy", 120),
- ],
- ),
- ));
+ ),
+ completedCell("Cornell Cafes", locationImage, "Journeys",
+ "January 19, 2023", "Arts Quad", "Easy", 120),
+ completedCell("Cornell Cafes", locationImage, "Journeys",
+ "January 19, 2023", "Arts Quad", "Easy", 120),
+ ],
+ ),
+ )),
+ );
}
}
diff --git a/game/lib/widget/game_widget.dart b/game/lib/widget/game_widget.dart
index b274fb05..b9efb02a 100644
--- a/game/lib/widget/game_widget.dart
+++ b/game/lib/widget/game_widget.dart
@@ -99,9 +99,9 @@ class _GameWidgetState extends State {
curChallenge != null &&
requiredSizeMet) {
final chalLoc =
- GeoPoint(curChallenge.lat, curChallenge.long);
- final location = GeoPoint(
- snapshot.data!.latitude, snapshot.data!.longitude);
+ GeoPoint(curChallenge.lat, curChallenge.long, 0);
+ final location = GeoPoint(snapshot.data!.latitude,
+ snapshot.data!.longitude, snapshot.data!.heading);
final distance = location.distanceTo(chalLoc);
gameModel.walkingTime =
diff --git a/game/pubspec.yaml b/game/pubspec.yaml
index 09c2d22b..1a2d1350 100644
--- a/game/pubspec.yaml
+++ b/game/pubspec.yaml
@@ -50,6 +50,11 @@ dependencies:
latlong2: ^0.9.0
device_info_plus: ^9.1.0
flutter_svg: ^2.0.8
+ google_maps_flutter: ^2.5.3
+ google_maps_flutter_android: ^2.4.2
+ google_maps_flutter_platform_interface: ^2.4.3
+ location: ^5.0.0
+ flutter_config: ^2.0.2
flutter_icons:
android: true