diff --git a/lib/data/models/gas_model.dart b/lib/data/models/gas_model.dart new file mode 100644 index 0000000..5fd4c29 --- /dev/null +++ b/lib/data/models/gas_model.dart @@ -0,0 +1,294 @@ +// ignore_for_file: unnecessary_this + +class GasModel { + int? id; + String? name; + Location? location; + Contact? contact; + List? openingHours; + OfferInformation? offerInformation; + PaymentMethods? paymentMethods; + PaymentArrangements? paymentArrangements; + int? position; + bool? open; + double? distance; + List? prices; + + GasModel( + {int? id, + String? name, + Location? location, + Contact? contact, + List? openingHours, + OfferInformation? offerInformation, + PaymentMethods? paymentMethods, + PaymentArrangements? paymentArrangements, + int? position, + bool? open, + double? distance, + List? prices}) { + if (id != null) { + this.id = id; + } + if (name != null) { + this.name = name; + } + if (location != null) { + this.location = location; + } + if (contact != null) { + this.contact = contact; + } + if (openingHours != null) { + this.openingHours = openingHours; + } + if (offerInformation != null) { + this.offerInformation = offerInformation; + } + if (paymentMethods != null) { + this.paymentMethods = paymentMethods; + } + if (paymentArrangements != null) { + this.paymentArrangements = paymentArrangements; + } + if (position != null) { + this.position = position; + + if (open != null) { + this.open = open; + } + if (distance != null) { + this.distance = distance; + } + if (prices != null) { + this.prices = prices; + } + } + } + + GasModel.fromJson(Map json) { + id = json['id']; + name = json['name']; + location = + json['location'] != null ? Location.fromJson(json['location']) : null; + contact = + json['contact'] != null ? Contact.fromJson(json['contact']) : null; + if (json['openingHours'] != null) { + openingHours = []; + json['openingHours'].forEach((v) { + openingHours!.add(OpeningHours.fromJson(v)); + }); + } + offerInformation = json['offerInformation'] != null + ? OfferInformation.fromJson(json['offerInformation']) + : null; + paymentMethods = json['paymentMethods'] != null + ? PaymentMethods.fromJson(json['paymentMethods']) + : null; + paymentArrangements = json['paymentArrangements'] != null + ? PaymentArrangements.fromJson(json['paymentArrangements']) + : null; + position = json['position']; + open = json['open']; + distance = json['distance']; + if (json['prices'] != null) { + prices = []; + json['prices'].forEach((v) { + prices!.add(Prices.fromJson(v)); + }); + } + } +} + +class Location { + String? address; + String? postalCode; + String? city; + double? latitude; + double? longitude; + + Location( + {String? address, + String? postalCode, + String? city, + double? latitude, + double? longitude}) { + if (address != null) { + this.address = address; + } + if (postalCode != null) { + this.postalCode = postalCode; + } + if (city != null) { + this.city = city; + } + if (latitude != null) { + this.latitude = latitude; + } + if (longitude != null) { + this.longitude = longitude; + } + } + + + + Location.fromJson(Map json) { + address = json['address']; + postalCode = json['postalCode']; + city = json['city']; + latitude = json['latitude']; + longitude = json['longitude']; + } +} + +class Contact { + String? telephone; + String? website; + + Contact({String? telephone, String? website}) { + if (telephone != null) { + this.telephone = telephone; + } + if (website != null) { + this.website = website; + } + } + + Contact.fromJson(Map json) { + telephone = json['telephone']; + website = json['website']; + } +} + +class OpeningHours { + String? day; + String? label; + int? order; + String? from; + String? to; + + OpeningHours( + {String? day, String? label, int? order, String? from, String? to}) { + if (day != null) { + this.day = day; + } + if (label != null) { + this.label = label; + } + if (order != null) { + this.order = order; + } + if (from != null) { + this.from = from; + } + if (to != null) { + this.to = to; + } + } + + OpeningHours.fromJson(Map json) { + day = json['day']; + label = json['label']; + order = json['order']; + from = json['from']; + to = json['to']; + } +} + +class OfferInformation { + bool? service; + bool? selfService; + bool? unattended; + + OfferInformation({bool? service, bool? selfService, bool? unattended}) { + if (service != null) { + this.service = service; + } + if (selfService != null) { + this.selfService = selfService; + } + if (unattended != null) { + this.unattended = unattended; + } + } + + OfferInformation.fromJson(Map json) { + service = json['service']; + selfService = json['selfService']; + unattended = json['unattended']; + } +} + +class PaymentMethods { + bool? cash; + bool? debitCard; + bool? creditCard; + String? others; + + PaymentMethods( {bool? cash, bool? debitCard, bool? creditCard, String? others}) { + if (cash != null) { + this.cash = cash; + } + if (debitCard != null) { + this.debitCard = debitCard; + } + if (creditCard != null) { + this.creditCard = creditCard; + } + if (others != null) { + this.others = others; + } + } + + + PaymentMethods.fromJson(Map json) { + cash = json['cash']; + debitCard = json['debitCard']; + creditCard = json['creditCard']; + others = json['others']; + } +} + +class PaymentArrangements { + bool? cooperative; + bool? clubCard; + + PaymentArrangements({bool? cooperative, bool? clubCard}) { + if (cooperative != null) { + this.cooperative = cooperative; + } + if (clubCard != null) { + this.clubCard = clubCard; + } + } + + + PaymentArrangements.fromJson(Map json) { + cooperative = json['cooperative']; + clubCard = json['clubCard']; + } +} + +class Prices { + String? fuelType; + double? amount; + String? label; + + Prices({String? fuelType, double? amount, String? label}) { + if (fuelType != null) { + this.fuelType = fuelType; + } + if (amount != null) { + this.amount = amount; + } + if (label != null) { + this.label = label; + } + } + + Prices.fromJson(Map json) { + fuelType = json['fuelType']; + amount = json['amount']; + label = json['label']; + } +} diff --git a/lib/data/repository/gasstation_repository.dart b/lib/data/repository/gasstation_repository.dart new file mode 100644 index 0000000..6df52c3 --- /dev/null +++ b/lib/data/repository/gasstation_repository.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:http/http.dart' as http; + +class GasStationRepository { + static final GasStationRepository _instance = + GasStationRepository._internal(); + + /// Singleton instance getter + factory GasStationRepository() => _instance; + + //Constructor??? + GasStationRepository._internal() { + //init for something + } + + Future getGasStationsLocations(Map map) async { + List data = []; + var lat = map['lat']; + var lng = map['lng']; + var gas = map['gas']; + // Hier kannst du die Logik hinzufügen, um den Standort zu verwenden, z.B. + String baseUrl = dotenv.get('TANKSTOPS_BASE_URL'); + String getGasLocationLink ='$baseUrl?latitude=$lat&longitude=$lng&fuelType=$gas&includeClosed=false'; + final client = http.Client(); + var response = await client.get(Uri.parse(getGasLocationLink),headers: {'Content-Type': 'application/json', 'charset': 'utf-8'}); + //Response Data status + if (response.statusCode == 200) { + //Response is succsessful + data = json.decode(utf8.decode(response.bodyBytes)); //get response data + } else { + debugPrint(response.statusCode.toString()); + } + client.close(); + + return data; + } +} diff --git a/lib/pages/gaslist/gaslist_controller.dart b/lib/pages/gaslist/gaslist_controller.dart new file mode 100644 index 0000000..38092fe --- /dev/null +++ b/lib/pages/gaslist/gaslist_controller.dart @@ -0,0 +1,86 @@ +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import '../../data/models/gas_model.dart'; +import '../../data/repository/appwrite_repository.dart'; +import '../../pages/login/login_view.dart'; +import '../../pages/tanklist/tanklist_view.dart'; + +import './widgets/map_view.dart' show MapDialogView; +import '../../data/repository/gasstation_repository.dart'; + +class GaslistController extends GetxController { + final _dataBox = GetStorage('MyUserStorage'); + final szRxGasArt = 'DIE'.obs; + //Gas Station Repository + final GasStationRepository _gasStationRepository = GasStationRepository(); + final AppwriteRepository _authRepository = AppwriteRepository(); + final isLoadingList = false.obs; + var gasStationsList = [].obs; + + @override + void onInit() { + loadListData(); + super.onInit(); + } + + @override + void onReady() {} + + @override + void onClose() {} + + Future loadListData() async { + isLoadingList(true); + var lat = _dataBox.read('lastLatitude'); + var lng = _dataBox.read('lastLongitude'); + var gas = szRxGasArt.value; + var result = + await getGasStationsFromApi({'lat': lat, 'lng': lng, 'gas': gas}); + print('Gas Stations from API: $result'); + //Hier die Logik zum Laden der Daten einfügen + gasStationsList.clear(); + gasStationsList.refresh(); + // add Map to GasModelList + for (var element in result) { + Map gasModelMap = (element as Map); + var gasModelItem = GasModel.fromJson(gasModelMap); + gasStationsList.add(gasModelItem); + } + //Simulate a delay for loading data + + isLoadingList(false); + update(); + } + + Future getGasStationsFromApi(Map map) async { + var result = await _gasStationRepository.getGasStationsLocations(map); + return result; + } + + void goToListView() { + Get.offAndToNamed(TanklistPage.namedRoute); + } + + Future logoutSessionAndGoToLoginPage() async { + // Handle logout logic here + print('Logout session and go to login page'); + // Clear GetStorage session ID + _dataBox.remove('sessionId'); + _dataBox.remove('userId'); + _dataBox.remove('userName'); + _dataBox.remove('userEmail'); + print('Session ID removed from GetStorage'); + await _authRepository.logout(); + Get.offAndToNamed(LoginPage.namedRoute); + } + + Future openDirectionMaps(double lat, double lng) async { + Get.dialog( + MapDialogView( + latitude: lat, + longitude: lng, + ), + barrierDismissible: true, + ); + } +} diff --git a/lib/pages/gaslist/gaslist_view.dart b/lib/pages/gaslist/gaslist_view.dart new file mode 100644 index 0000000..5fc8435 --- /dev/null +++ b/lib/pages/gaslist/gaslist_view.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'gaslist_controller.dart'; + +class GaslistPage extends GetView { + static const namedRoute = '/gas-stations-list-page'; + const GaslistPage({super.key}); + + @override + Widget build(BuildContext context) { + var gasCtrl = controller; + return PopScope( + canPop: false, + child: SafeArea( + child: Scaffold( + appBar: AppBar( + shadowColor: Colors.grey, + title: const Text('Gas Stations'), + centerTitle: true, + actions: [ + IconButton( + icon: Icon(Icons.list, color: Colors.grey.shade300), + onPressed: () async { + // Handle go to Chart View + gasCtrl.goToListView(); + }, + ), + IconButton( + icon: Icon(Icons.logout, color: Colors.grey.shade300), + onPressed: () async { + // Handle logout logic here + gasCtrl.logoutSessionAndGoToLoginPage(); + }, + ), + ], + ), + body: Obx( + () => gasCtrl.isLoadingList.value == true + ? Center( + child: Text('GasStations'), + ) + : Column( + children: [ + SizedBox( + child: Wrap( + alignment: WrapAlignment.center, + spacing: 50, + children: [ + Divider( + color: Colors.grey.shade300, + ), + ElevatedButton( + onPressed: () async { + gasCtrl.szRxGasArt.value = 'DIE'; + await gasCtrl.loadListData(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey.shade800, + foregroundColor: Colors + .orange, // Hintergrundfarbe des Buttons + ), + child: Column( + children: [ + Text('Diesel'), + Text('DIE'), + ], + ), + ), + ElevatedButton( + onPressed: () async { + gasCtrl.szRxGasArt.value = 'SUP'; + await gasCtrl.loadListData(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey.shade800, + foregroundColor: Colors + .orange, // Hintergrundfarbe des Buttons + ), + child: Column( + children: [ + Text('Benzin'), + Text('SUP'), + ], + ), + ), + ], + ), + ), + Divider( + color: Colors.grey.shade300, + + ), + Expanded( + child: ListView.builder( + itemCount: 5, + itemBuilder: (context, index) { + var gasStation = gasCtrl.gasStationsList[index]; + return ListTile( + shape: RoundedRectangleBorder( + side: BorderSide( + color: Colors.grey, // Border color + width: 1.0, // Border thickness + ), + borderRadius: BorderRadius.circular(5.0), + ), + onTap: () { + // Handle item tap if needed + gasCtrl.openDirectionMaps( + gasStation.location!.latitude!, + gasStation.location!.longitude!); + }, + title: Text(gasStation.name ?? 'No Name'), + subtitle: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(gasStation.location?.address ?? + 'No Address'), + Text(gasStation.distance != null + ? '${gasStation.distance?.toStringAsFixed(2)} km' + : 'No Distance'), + ], + ), + trailing: gasStation.prices != null && + gasStation.prices!.isNotEmpty + ? Column( + children: [ + Text(gasStation.prices?[0].fuelType ?? + 'N/A'), + Text( + '${gasStation.prices?[0].amount?.toStringAsPrecision(4) ?? 'N/A'} €'), + ], + ) + : const Text('N/A'), + ); + }, + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/gaslist/widgets/map_view.dart b/lib/pages/gaslist/widgets/map_view.dart new file mode 100644 index 0000000..18b4d31 --- /dev/null +++ b/lib/pages/gaslist/widgets/map_view.dart @@ -0,0 +1,76 @@ +// map_dialog_view.dart + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class MapDialogView extends StatelessWidget { + final double latitude; + final double longitude; + + const MapDialogView({ + super.key, + required this.latitude, + required this.longitude, + }); + + // Funktion zum Öffnen der Karten-URL + void _openMap() async { + String url = ''; + final coords = '$latitude,$longitude'; + + if (Platform.isAndroid) { + // Android: Startet die Google Maps Navigation + url = + 'https://www.google.com/maps/dir/?api=1&destination=$coords'; // mode=d für Fahren + } else if (Platform.isIOS) { + // iOS: Startet die Apple Maps Navigation + url = + 'https://maps.apple.com/?daddr=$coords&dirflg=d'; // daddr für destination, dirflg=d für driving + } else { + // Fallback-URL für die Google Maps Website mit Wegbeschreibung + url = 'https://www.google.com/maps/dir/?api=1&destination=$coords'; + } + // Hier die URL-Logik einfügen, die Sie bereits kennen + //final url = 'http://googleusercontent.com/maps.google.com/8'; + final uri = Uri.parse(url); + + if (await canLaunchUrl(uri)) { + await launchUrl(uri); + } else { + // Eine Snackbar oder ein Dialog, um den Fehler zu melden + print('Fehler: Konnte Karten-App nicht öffnen.'); + } + Get.back(); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Karte öffnen'), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, // Passt die Höhe an den Inhalt an + children: [ + Text('Koordinaten'), + Text('Latitude: $latitude'), + Text('Longitude: $longitude'), + const SizedBox(height: 20), + ElevatedButton( + onPressed: _openMap, // Ruft die Methode zum Öffnen der Karte auf + child: const Text('Karten-App öffnen'), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), // Schließt den Dialog + child: const Text('Schließen'), + ), + ], + ); + } +} diff --git a/lib/pages/tank/tank_controller.dart b/lib/pages/tank/tank_controller.dart index ea7bf36..81cfcdc 100644 --- a/lib/pages/tank/tank_controller.dart +++ b/lib/pages/tank/tank_controller.dart @@ -73,6 +73,9 @@ class TankController extends GetxController { // Hier kannst du die Logik hinzufügen, um den Standort zu verwenden, z.B. // den Standort in der UI anzuzeigen oder an einen Server zu senden. var map = {'lat': latitude, 'lng': longitude}; + //save to local Storage lat and long + _dataBox.write('lastLatitude', latitude); + _dataBox.write('lastLongitude', longitude); var loc = await _locationRepository.getNearbyLocation(map); ortController.text = loc; // Print Standortinformationen in der Konsole diff --git a/lib/pages/tanklist/tanklist_controller.dart b/lib/pages/tanklist/tanklist_controller.dart index 838e66b..73b525e 100644 --- a/lib/pages/tanklist/tanklist_controller.dart +++ b/lib/pages/tanklist/tanklist_controller.dart @@ -1,13 +1,13 @@ import 'package:appwrite/appwrite.dart'; -import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; +import '../login/login_view.dart'; +import '../graph/graph_view.dart'; import '../../data/models/tank_model.dart'; import '../../data/repository/appwrite_repository.dart'; import '../../pages/tank/tank_view.dart'; -import '../graph/graph_view.dart'; -import '../login/login_view.dart'; +import '../../pages/gaslist/gaslist_view.dart'; class TanklistController extends GetxController { final _dataBox = GetStorage('MyUserStorage'); @@ -159,5 +159,9 @@ class TanklistController extends GetxController { print('$title: $message'); } - void goToGasView() {} + Future goToGasView() async { + //Go to Gas Station List Page + await Get.offAndToNamed(GaslistPage.namedRoute); + + } } diff --git a/lib/pages/tanklist/tanklist_view.dart b/lib/pages/tanklist/tanklist_view.dart index bedffbb..5c7c20a 100644 --- a/lib/pages/tanklist/tanklist_view.dart +++ b/lib/pages/tanklist/tanklist_view.dart @@ -24,14 +24,14 @@ class TanklistPage extends GetView { icon: Icon(Icons.add_chart, color: Colors.grey.shade300), onPressed: () async { // Handle go to Chart View - tankListCtrl.goToGasView(); + tankListCtrl.goToChartView(); }, ), IconButton( icon: Icon(Icons.local_gas_station_sharp, color: Colors.grey.shade300), onPressed: () async { // Handle go to Chart View - tankListCtrl.goToChartView(); + tankListCtrl.goToGasView(); }, ), IconButton( diff --git a/lib/utils/extensions/sample_bindings.dart b/lib/utils/extensions/sample_bindings.dart index ccb269b..a49e314 100644 --- a/lib/utils/extensions/sample_bindings.dart +++ b/lib/utils/extensions/sample_bindings.dart @@ -1,5 +1,6 @@ import 'package:get/get.dart'; +import '../../pages/gaslist/gaslist_controller.dart'; import '../../pages/graph/graph_controller.dart'; import '../../pages/login/login_controller.dart'; import '../../pages/tank/tank_controller.dart'; @@ -15,6 +16,7 @@ class SampleBindings extends Bindings { Get.lazyPut(() => TankController()); Get.lazyPut(() => TanklistController()); Get.lazyPut(() => GraphController()); + Get.lazyPut(() => GaslistController()); // Get.lazyPut(() => TrackingController(AuthRepository(AppWriteProvider()))); // Get.lazyPut(() => MapController(AuthRepository(AppWriteProvider()), LocationRepository(LocationProvider()))); } diff --git a/lib/utils/extensions/sample_routes.dart b/lib/utils/extensions/sample_routes.dart index a67d941..0ab0417 100644 --- a/lib/utils/extensions/sample_routes.dart +++ b/lib/utils/extensions/sample_routes.dart @@ -4,6 +4,7 @@ import '../../pages/graph/graph_view.dart'; import '../../pages/login/login_view.dart'; import '../../pages/tank/tank_view.dart'; import '../../pages/tanklist/tanklist_view.dart'; +import '../../pages/gaslist/gaslist_view.dart'; import './sample_bindings.dart'; @@ -31,11 +32,11 @@ class SampleRouts { page: () => const GraphPage(), binding: sampleBindings, ), - // GetPage( - // name: TrackingPage.namedRoute, - // page: () => const TrackingPage(), - // binding: sampleBindings, - // ), + GetPage( + name: GaslistPage.namedRoute, + page: () => const GaslistPage(), + binding: sampleBindings, + ), // GetPage( // name: MapPage.namedRoute, // page: () => const MapPage(),