2022-06-01 13:10:04 +02:00

658 lines
18 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_applicationdemo/bottom_nav_page.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:async';
import 'login/user.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter_google_places/flutter_google_places.dart';
import 'package:location/location.dart';
import 'package:flutter_applicationdemo/login/user.dart';
import 'settings_page.dart';
import 'venue_page.dart';
import 'venue.dart';
import 'globals.dart' as globals;
import 'package:syncfusion_flutter_sliders/sliders.dart';
import 'feedback_page.dart';
import 'login/create_account_page.dart';
import 'login/sign_in_page.dart';
class Map extends StatefulWidget {
@override
State<Map> createState() => MapState();
}
const kGoogleApiKey = "AIzaSyAUmhd6Xxud8SwgDxJ4LlYlcntm01FGoSk";
final homeScaffoldKey = GlobalKey<ScaffoldState>();
late CameraPosition _currentCameraPosition;
class MapState extends State<Map> {
bool _bottomSheetIsOpen = false;
final Completer<GoogleMapController> _controller = Completer();
bool? _barFilterValue = true;
bool? _restaurantFilterValue = true;
bool? _cafeFilterValue = true;
dynamic _priceFilterValue = 3;
LocationData? _currentPosition;
final TextEditingController _searchController = TextEditingController();
static const CameraPosition _stockholmCity = CameraPosition(
target: LatLng(59.325027, 18.068516),
zoom: 14.4746,
);
List<Marker> markersList = [];
List<Marker> closeByMarkersList = [];
List<Venue> hiddenVenues = [];
List<Venue> closeByVenues = [];
@override
void initState() {
initialize();
_getUserLocation();
super.initState();
}
initialize() {
hiddenVenues.addAll(globals.VENUES);
}
Future<LocationData> _getLocationPermission() async {
Location location = Location();
bool _serviceEnabled;
PermissionStatus _permissionGranted;
LocationData _locationData;
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return Future.error('Service not enable');
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return Future.error('Permission Denied');
}
}
_locationData = await location.getLocation();
return _locationData;
}
_getUserLocation() async {
_currentPosition = await _getLocationPermission();
_goToCurrentPosition(
LatLng(_currentPosition!.latitude!, _currentPosition!.longitude!));
}
late GoogleMapController googleMapController;
final Mode _mode = Mode.fullscreen;
int currentIndex = 0;
@override
Widget build(BuildContext context) {
_currentCameraPosition = _stockholmCity;
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Sun chasers"),
key: homeScaffoldKey,
actions: <Widget>[createFilterMenuButton()],
backgroundColor: const Color.fromARGB(255, 190, 146, 160),
),
drawer: Drawer(
child: Container(
child: globals.LOGGED_IN_USER.userID == 0
? buildDrawerSignedOut(context)
: buildDrawerSignedIn(context),
),
),
body: Stack(
children: [
GoogleMap(
cameraTargetBounds: CameraTargetBounds(LatLngBounds(
northeast: const LatLng(59.3474696569038, 18.1001602476002147),
southwest:
const LatLng(59.297332547922636, 17.999522500277884))),
minMaxZoomPreference: MinMaxZoomPreference(12.5, 18.5),
onCameraMove: (CameraPosition camera) {
_currentCameraPosition = camera;
},
onCameraIdle: () {
(context as Element).reassemble();
removeMarkersOutOfRange();
addMarkersInRange();
},
mapType: MapType.normal,
myLocationEnabled: true,
initialCameraPosition: _stockholmCity,
compassEnabled: true,
onMapCreated: (GoogleMapController controller) {
setAllMarkersAsInvisible();
addMarkersInRange();
_controller.complete(controller);
},
markers: closeByMarkersList.map((e) => e).toSet(),
onTap: (LatLng) {
closeBottomSheetIfOpen();
},
),
],
),
floatingActionButton: Padding(
padding: const EdgeInsets.only(top: 100.0),
child: FloatingActionButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const SettingsPage()));
},
backgroundColor: Colors.purple,
child: const Icon(Icons.filter_alt),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endTop,
);
}
final screens = [
Map(),
];
PopupMenuButton<dynamic> createFilterMenuButton() {
return PopupMenuButton(
icon: Icon(Icons.filter_list),
iconSize: 40,
itemBuilder: (context) => [
const PopupMenuItem(
child: Text(
"Filters",
style: TextStyle(
fontSize: 20,
),
),
padding: EdgeInsets.only(left: 60),
),
createCheckBoxes(),
createPriceSlider(),
PopupMenuItem(
child: ButtonBar(
alignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: null,
// TODO: Fixa så att kartan filtreras när man klickar på 'Apply Filters'
child: Text(
"Apply Filters",
style: TextStyle(color: Colors.black),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
globals.BUTTONCOLOR)),
),
],
))
]);
}
// Creates the checkboxes for the filter menu
PopupMenuItem<dynamic> createCheckBoxes() {
return PopupMenuItem(
child: Padding(
padding: const EdgeInsets.all(8),
child: Expanded(
child: Column(
children: [
Divider(
color: Colors.black,
),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return CheckboxListTile(
value: _barFilterValue,
onChanged: (bool? newValue) {
setState(() {
_barFilterValue = newValue;
});
},
title: const Icon(
Icons.sports_bar,
color: Colors.orange,
));
}),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return CheckboxListTile(
value: _restaurantFilterValue,
onChanged: (bool? newValue) {
setState(() {
_restaurantFilterValue = newValue;
});
},
title: Icon(
Icons.restaurant,
color: Colors.blueGrey[200],
),
);
}),
//Cafe checkbox
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return CheckboxListTile(
value: _cafeFilterValue,
onChanged: (bool? newValue) {
setState(() => _cafeFilterValue = newValue);
},
title: Icon(
Icons.coffee,
color: Colors.brown[400],
));
}),
],
),
)));
}
PopupMenuItem<dynamic> createPriceSlider() {
return PopupMenuItem(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return SfSlider(
value: _priceFilterValue,
onChanged: (dynamic newValue) {
setState((() => _priceFilterValue = newValue));
},
min: 1,
max: 3,
showTicks: true,
interval: 1,
activeColor: Colors.blue,
showLabels: true,
stepSize: 1.0,
labelFormatterCallback: (dynamic value, String formattedText) {
switch (value) {
case 1:
return '\$';
case 2:
return '\$\$';
case 3:
return '\$\$\$';
}
return value.toString();
});
}),
);
}
Future<void> _gotoLocation(double lat, double lng) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(lat, lng), zoom: 14.5)));
}
Future<void> _goToCurrentPosition(LatLng latlng) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
bearing: 0,
target: LatLng(latlng.latitude, latlng.longitude),
//tilt: 59.440717697143555,
zoom: 15.4746)));
}
void removeMarkersOutOfRange() {
for (int i = 0; i < closeByMarkersList.length; i++) {
Marker marker = closeByMarkersList[i];
globals.venueAlreadyAdded(
globals.getVenueByID(int.parse(marker.markerId.value))!.venueName);
if (marker.position.longitude - _currentCameraPosition.target.longitude >
0.02 ||
marker.position.latitude - _currentCameraPosition.target.latitude >
0.02) {
closeByMarkersList.remove(marker);
globals.getVenueByID(int.parse(marker.markerId.value))?.isShownOnMap =
false;
i--;
}
}
}
void addMarkersInRange() {
for (int i = 0; i < globals.VENUES.length; i++) {
if (!globals.VENUES[i].isShownOnMap &&
(globals.VENUES[i].position.longitude -
_currentCameraPosition.target.longitude <
0.02 &&
globals.VENUES[i].position.latitude -
_currentCameraPosition.target.latitude <
0.02)) {
Marker marker = Marker(
markerId: MarkerId(globals.VENUES[i].venueID.toString()),
position: globals.VENUES[i].position,
onTap: () => createBottomSheet(globals.VENUES[i]),
icon: globals.VENUES[i].drawIconColor());
globals.VENUES[i].isShownOnMap = true;
closeByMarkersList.add(marker);
}
}
}
createBottomSheet(Venue venue) async {
_bottomSheetIsOpen = true;
// Scaffold.of(context).showBottomSheet<void>(((context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => VenuePage(venue)),
);
},
child: Container(
height: 175,
color: const Color(0xFFF5F5F5),
child: Center(
child: Column(
children: [
bottomSheetWidgetContainer(venue, context),
],
),
),
),
);
});
}
Container bottomSheetWidgetContainer(Venue venue, BuildContext context) {
return Container(
margin: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
columnCoveringNameAndAddress(venue),
],
),
// columnCoveringRating(),
],
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: const [
WeatherIconRow(),
WeatherStatusRow(),
],
),
columnHandlingReadMoreButton(context, venue),
],
)
],
),
);
}
Column columnHandlingReadMoreButton(BuildContext context, Venue venue) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
readMoreButton(context, venue),
],
),
),
],
);
}
ElevatedButton readMoreButton(BuildContext context, Venue venue) {
return ElevatedButton(
child: const Text(
'Read More',
style: TextStyle(fontSize: 16),
),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => VenuePage(venue)));
_bottomSheetIsOpen = false;
},
style: ElevatedButton.styleFrom(
primary: globals.BUTTONCOLOR,
),
);
}
Column columnCoveringNameAndAddress(Venue venue) {
return Column(
children: [
Text(
venue.venueName,
style: GoogleFonts.roboto(
textStyle: const TextStyle(
color: Colors.black87,
fontWeight: FontWeight.bold,
fontSize: 20,
)),
),
Text(
venue.venueAddress + ' ' + venue.venueStreetNo,
style: GoogleFonts.roboto(
textStyle: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.w300,
fontSize: 14,
)),
)
],
);
}
closeBottomSheetIfOpen() {
if (_bottomSheetIsOpen) {
Navigator.pop(context);
_bottomSheetIsOpen = false;
}
}
void setAllMarkersAsInvisible() {
for (Venue venue in hiddenVenues) {
venue.isShownOnMap = false;
}
}
}
class WeatherIconRow extends StatelessWidget {
const WeatherIconRow({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
const Text(
'Weather: \t\t',
style: TextStyle(fontSize: 18),
),
globals.forecast.getCurrentWeatherIcon(),
],
);
}
}
class WeatherStatusRow extends StatelessWidget {
const WeatherStatusRow({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: [
Text(
' ' + globals.forecast.getCurrentWeatherStatus(),
style: const TextStyle(
fontSize: 16,
fontStyle: FontStyle.italic,
),
),
],
);
}
}
Widget buildDrawerSignedIn(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration:
const BoxDecoration(color: Color.fromARGB(255, 190, 146, 160)),
child: Column(
children: const <Widget>[
Text(
'Sun Chaser',
style: TextStyle(fontSize: 32),
),
SizedBox(height: 30),
Icon(Icons.account_box_rounded),
],
),
),
ListTile(
leading: Icon(Icons.logout),
title: Text('Sign out'),
onTap: () {
globals.LOGGED_IN_USER = User(0, "", "");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
BottomNavPage()), //Replace Container() with call to Map-page.
);
},
),
giveFeedbackTile(context),
settingsTile(context),
],
),
);
}
Widget buildDrawerSignedOut(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
drawerHeader(),
createAccountTile(context),
logInTile(context),
giveFeedbackTile(context),
settingsTile(context),
],
),
);
}
DrawerHeader drawerHeader() {
return DrawerHeader(
decoration: const BoxDecoration(color: Color.fromARGB(255, 190, 146, 160)),
child: Column(
children: const <Widget>[
Text(
'Sun Chaser',
style: TextStyle(fontSize: 32),
),
SizedBox(height: 30),
],
),
);
}
ListTile settingsTile(BuildContext context) {
return ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SettingsPage(),
),
);
},
);
}
ListTile giveFeedbackTile(BuildContext context) {
return ListTile(
leading: Icon(Icons.thumb_up_alt),
title: Text('Give feedback'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FormForFeedback(),
),
);
},
);
}
ListTile logInTile(BuildContext context) {
return ListTile(
leading: Icon(Icons.login),
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SignInPage(),
),
);
},
);
}
ListTile createAccountTile(BuildContext context) {
return ListTile(
leading: Icon(Icons.account_box_rounded),
title: Text('Create account'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CreateAccountPage(),
),
);
},
);
}