add login
This commit is contained in:
parent
b6bd692cd7
commit
c0960cbd9f
6
.envExample
Normal file
6
.envExample
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
APPWRITE_ENDPOINT_URL=<Your Appwrite Endpoint>
|
||||||
|
APPWRITE_PROJECT_NAME=<Your Project Name>
|
||||||
|
APPWRITE_PROJECT_ID=<Your Project Id>
|
||||||
|
APPWRITE_DATABASE_ID=<Your Database Id>
|
||||||
|
APPWRITE_COLLECTION_ID=<Your Collection id>
|
||||||
|
PTVE_API_KEY=<Your PTV API key Geolocation Address>
|
||||||
@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
# The following line activates a set of recommended lints for Flutter apps,
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
# packages, and plugins designed to encourage good coding practices.
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
analyzer:
|
||||||
|
errors:
|
||||||
|
avoid_print: ignore
|
||||||
include: package:flutter_lints/flutter.yaml
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
|
|||||||
18
lib/bindings/login_binding.dart
Normal file
18
lib/bindings/login_binding.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import '../controllers/login_controller.dart';
|
||||||
|
|
||||||
|
class LoginBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut<LoginController>(() => LoginController());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alternative: Permanent Binding für App-weite Nutzung
|
||||||
|
class LoginPermanentBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
// Permanent - Controller bleibt im Speicher
|
||||||
|
Get.put<LoginController>(LoginController(), permanent: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
import '../../services/geolocation.dart';
|
import '../../services/geolocation.dart';
|
||||||
|
import '../models/ptv_logistic_model.dart';
|
||||||
|
import '../services/ptv_api_simple.dart';
|
||||||
|
|
||||||
/// GetX Controller für Geolocation Funktionalität
|
/// GetX Controller für Geolocation Funktionalität
|
||||||
class GeolocationController extends GetxController {
|
class GeolocationController extends GetxController {
|
||||||
@ -9,12 +11,14 @@ class GeolocationController extends GetxController {
|
|||||||
final _statusText = 'Noch keine Position ermittelt'.obs;
|
final _statusText = 'Noch keine Position ermittelt'.obs;
|
||||||
final _isTracking = false.obs;
|
final _isTracking = false.obs;
|
||||||
final _isLoading = false.obs;
|
final _isLoading = false.obs;
|
||||||
|
final _ptvModel = Rxn<PTVModel>();
|
||||||
|
|
||||||
// Getter für reactive Variablen
|
// Getter für reactive Variablen
|
||||||
Position? get currentPosition => _currentPosition.value;
|
Position? get currentPosition => _currentPosition.value;
|
||||||
String get statusText => _statusText.value;
|
String get statusText => _statusText.value;
|
||||||
bool get isTracking => _isTracking.value;
|
bool get isTracking => _isTracking.value;
|
||||||
bool get isLoading => _isLoading.value;
|
bool get isLoading => _isLoading.value;
|
||||||
|
PTVModel? get ptvModel => _ptvModel.value;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
@ -34,7 +38,15 @@ class GeolocationController extends GetxController {
|
|||||||
if (position != null) {
|
if (position != null) {
|
||||||
_currentPosition.value = position;
|
_currentPosition.value = position;
|
||||||
_statusText.value = GeolocationService.positionToString(position);
|
_statusText.value = GeolocationService.positionToString(position);
|
||||||
|
var resultData = await PtvApiServiceSimple.getLocationsByPosition(
|
||||||
|
latitude: position.latitude,
|
||||||
|
longitude: position.longitude,
|
||||||
|
);
|
||||||
|
if(resultData != null) {
|
||||||
|
_ptvModel.value = PTVModel.fromJson(resultData);
|
||||||
|
} else {
|
||||||
|
_ptvModel.value = null;
|
||||||
|
}
|
||||||
// Erfolgs-Snackbar anzeigen
|
// Erfolgs-Snackbar anzeigen
|
||||||
Get.snackbar(
|
Get.snackbar(
|
||||||
'Position ermittelt',
|
'Position ermittelt',
|
||||||
|
|||||||
65
lib/controllers/login_controller.dart
Normal file
65
lib/controllers/login_controller.dart
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import 'package:appwrite/appwrite.dart' as account_models;
|
||||||
|
import 'package:appwrite/models.dart' as user_models;
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:appwrite/appwrite.dart';
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
class LoginController extends GetxController {
|
||||||
|
final _account = Rxn<account_models.Account>();
|
||||||
|
final mailController = TextEditingController();
|
||||||
|
final passwordController = TextEditingController();
|
||||||
|
final nameController = TextEditingController();
|
||||||
|
final _endpoint = dotenv.env['APPWRITE_ENDPOINT_URL'] ?? '';
|
||||||
|
final _projectId = dotenv.env['APPWRITE_PROJECT_ID'] ?? '';
|
||||||
|
final _logedInUser = Rxn<user_models.User>();
|
||||||
|
|
||||||
|
account_models.Account? get account => _account.value;
|
||||||
|
user_models.User? get logedInUser => _logedInUser.value;
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
Client client = Client()
|
||||||
|
.setEndpoint(_endpoint)
|
||||||
|
.setProject(_projectId);
|
||||||
|
_account.value = Account(client);
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> login(String email, String password) async {
|
||||||
|
await _account.value!.createEmailPasswordSession(
|
||||||
|
email: email,
|
||||||
|
password: password,
|
||||||
|
);
|
||||||
|
final user = await _account.value!.get();
|
||||||
|
|
||||||
|
_logedInUser.value = user;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> register(String email, String password, String name) async {
|
||||||
|
await _account.value!.create(
|
||||||
|
userId: ID.unique(),
|
||||||
|
email: email,
|
||||||
|
password: password,
|
||||||
|
name: name,
|
||||||
|
);
|
||||||
|
await login(email, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> logout() async {
|
||||||
|
await _account.value!.deleteSession(sessionId: 'current');
|
||||||
|
_logedInUser.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
mailController.dispose();
|
||||||
|
passwordController.dispose();
|
||||||
|
nameController.dispose();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'bindings/login_binding.dart';
|
||||||
import 'routes/app_routes.dart';
|
import 'routes/app_routes.dart';
|
||||||
import 'bindings/geolocation_binding.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'pages/examples/geolocation_example.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await dotenv.load(fileName: ".env");
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,11 +23,9 @@ class MyApp extends StatelessWidget {
|
|||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
// GetX Konfiguration
|
// GetX Konfiguration
|
||||||
initialRoute: AppRoutes.geolocation,
|
initialRoute: AppRoutes.login,
|
||||||
getPages: AppRoutes.pages,
|
getPages: AppRoutes.pages,
|
||||||
initialBinding: GeolocationBinding(), // Optional: Globale Bindings
|
initialBinding: LoginBinding(),
|
||||||
// Alternative: Direkte Navigation ohne Routen
|
|
||||||
home: const GeolocationExample(),
|
|
||||||
|
|
||||||
// GetX Optionen
|
// GetX Optionen
|
||||||
enableLog: true, // Debugging
|
enableLog: true, // Debugging
|
||||||
@ -34,41 +34,3 @@ class MyApp extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative: Home Page mit Navigation zu Geolocation
|
|
||||||
class HomePage extends StatelessWidget {
|
|
||||||
const HomePage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Tank App'),
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Tank Appwrite App',
|
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
ElevatedButton.icon(
|
|
||||||
onPressed: () => Get.to(() => const GeolocationExample()),
|
|
||||||
icon: const Icon(Icons.location_on),
|
|
||||||
label: const Text('Geolocation Beispiel'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 24,
|
|
||||||
vertical: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'routes/app_routes.dart';
|
|
||||||
import 'bindings/geolocation_binding.dart';
|
|
||||||
import 'pages/examples/geolocation_example.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(const MyApp());
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
|
||||||
const MyApp({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GetMaterialApp(
|
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
title: 'Web Flutter Tank Appwrite App',
|
|
||||||
theme: ThemeData(
|
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
|
||||||
useMaterial3: true,
|
|
||||||
),
|
|
||||||
// GetX Konfiguration
|
|
||||||
initialRoute: AppRoutes.geolocation,
|
|
||||||
getPages: AppRoutes.pages,
|
|
||||||
initialBinding: GeolocationBinding(), // Optional: Globale Bindings
|
|
||||||
|
|
||||||
// Alternative: Direkte Navigation ohne Routen
|
|
||||||
//home: const GeolocationExample(),
|
|
||||||
|
|
||||||
// GetX Optionen
|
|
||||||
enableLog: true, // Debugging
|
|
||||||
defaultTransition: Transition.fade,
|
|
||||||
transitionDuration: const Duration(milliseconds: 300),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Alternative: Home Page mit Navigation zu Geolocation
|
|
||||||
class HomePage extends StatelessWidget {
|
|
||||||
const HomePage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Tank App'),
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Tank Appwrite App',
|
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 32),
|
|
||||||
ElevatedButton.icon(
|
|
||||||
onPressed: () => Get.to(() => const GeolocationExample()),
|
|
||||||
icon: const Icon(Icons.location_on),
|
|
||||||
label: const Text('Geolocation Beispiel'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 24,
|
|
||||||
vertical: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
lib/models/login_model.dart
Normal file
7
lib/models/login_model.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
class LoginSigninModel {
|
||||||
|
String email;
|
||||||
|
String password;
|
||||||
|
String name;
|
||||||
|
|
||||||
|
LoginSigninModel({this.email='test@test.at', this.password='123PassWd', this.name='TestUser'});
|
||||||
|
}
|
||||||
168
lib/models/ptv_logistic_model.dart
Normal file
168
lib/models/ptv_logistic_model.dart
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Hauptklasse für die PTV Location Response
|
||||||
|
class PTVModel {
|
||||||
|
List<Locations>? locations;
|
||||||
|
String? noMatchFeedbackId;
|
||||||
|
|
||||||
|
PTVModel({this.locations, this.noMatchFeedbackId});
|
||||||
|
|
||||||
|
PTVModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
if (json['locations'] != null) {
|
||||||
|
locations = <Locations>[];
|
||||||
|
json['locations'].forEach((v) {
|
||||||
|
locations!.add(Locations.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
noMatchFeedbackId = json['noMatchFeedbackId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (locations != null) {
|
||||||
|
data['locations'] = locations!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
data['noMatchFeedbackId'] = noMatchFeedbackId;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Locations {
|
||||||
|
ReferencePosition? referencePosition;
|
||||||
|
Address? address;
|
||||||
|
String? locationType;
|
||||||
|
Quality? quality;
|
||||||
|
String? formattedAddress;
|
||||||
|
String? feedbackId;
|
||||||
|
|
||||||
|
Locations(
|
||||||
|
{this.referencePosition,
|
||||||
|
this.address,
|
||||||
|
this.locationType,
|
||||||
|
this.quality,
|
||||||
|
this.formattedAddress,
|
||||||
|
this.feedbackId});
|
||||||
|
|
||||||
|
Locations.fromJson(Map<String, dynamic> json) {
|
||||||
|
referencePosition = json['referencePosition'] != null
|
||||||
|
? ReferencePosition.fromJson(json['referencePosition'])
|
||||||
|
: null;
|
||||||
|
address =
|
||||||
|
json['address'] != null ? Address.fromJson(json['address']) : null;
|
||||||
|
locationType = json['locationType'];
|
||||||
|
quality =
|
||||||
|
json['quality'] != null ? Quality.fromJson(json['quality']) : null;
|
||||||
|
formattedAddress = json['formattedAddress'];
|
||||||
|
feedbackId = json['feedbackId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (referencePosition != null) {
|
||||||
|
data['referencePosition'] = referencePosition!.toJson();
|
||||||
|
}
|
||||||
|
if (address != null) {
|
||||||
|
data['address'] = address!.toJson();
|
||||||
|
}
|
||||||
|
data['locationType'] = locationType;
|
||||||
|
if (quality != null) {
|
||||||
|
data['quality'] = quality!.toJson();
|
||||||
|
}
|
||||||
|
data['formattedAddress'] = formattedAddress;
|
||||||
|
data['feedbackId'] = feedbackId;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReferencePosition {
|
||||||
|
double? latitude;
|
||||||
|
double? longitude;
|
||||||
|
|
||||||
|
ReferencePosition({this.latitude, this.longitude});
|
||||||
|
|
||||||
|
ReferencePosition.fromJson(Map<String, dynamic> json) {
|
||||||
|
latitude = json['latitude'];
|
||||||
|
longitude = json['longitude'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['latitude'] = latitude;
|
||||||
|
data['longitude'] = longitude;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Address {
|
||||||
|
String? countryName;
|
||||||
|
String? state;
|
||||||
|
String? province;
|
||||||
|
String? city;
|
||||||
|
String? district;
|
||||||
|
String? subdistrict;
|
||||||
|
String? street;
|
||||||
|
String? houseNumber;
|
||||||
|
String? countryCodeIsoAlpha2;
|
||||||
|
String? countryCodeIsoAlpha3;
|
||||||
|
String? countryCode;
|
||||||
|
|
||||||
|
Address(
|
||||||
|
{this.countryName,
|
||||||
|
this.state,
|
||||||
|
this.province,
|
||||||
|
this.city,
|
||||||
|
this.district,
|
||||||
|
this.subdistrict,
|
||||||
|
this.street,
|
||||||
|
this.houseNumber,
|
||||||
|
this.countryCodeIsoAlpha2,
|
||||||
|
this.countryCodeIsoAlpha3,
|
||||||
|
this.countryCode});
|
||||||
|
|
||||||
|
Address.fromJson(Map<String, dynamic> json) {
|
||||||
|
countryName = json['countryName'];
|
||||||
|
state = json['state'];
|
||||||
|
province = json['province'];
|
||||||
|
city = json['city'];
|
||||||
|
district = json['district'];
|
||||||
|
subdistrict = json['subdistrict'];
|
||||||
|
street = json['street'];
|
||||||
|
houseNumber = json['houseNumber'];
|
||||||
|
countryCodeIsoAlpha2 = json['countryCodeIsoAlpha2'];
|
||||||
|
countryCodeIsoAlpha3 = json['countryCodeIsoAlpha3'];
|
||||||
|
countryCode = json['countryCode'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['countryName'] = countryName;
|
||||||
|
data['state'] = state;
|
||||||
|
data['province'] = province;
|
||||||
|
data['city'] = city;
|
||||||
|
data['district'] = district;
|
||||||
|
data['subdistrict'] = subdistrict;
|
||||||
|
data['street'] = street;
|
||||||
|
data['houseNumber'] = houseNumber;
|
||||||
|
data['countryCodeIsoAlpha2'] = countryCodeIsoAlpha2;
|
||||||
|
data['countryCodeIsoAlpha3'] = countryCodeIsoAlpha3;
|
||||||
|
data['countryCode'] = countryCode;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Quality {
|
||||||
|
int? distance;
|
||||||
|
|
||||||
|
Quality({this.distance});
|
||||||
|
|
||||||
|
Quality.fromJson(Map<String, dynamic> json) {
|
||||||
|
distance = json['distance'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['distance'] = distance;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,11 +24,12 @@ class GeolocationExample extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: SafeArea(
|
||||||
padding: const EdgeInsets.all(16.0),
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
padding: const EdgeInsets.all(16.0),
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
// Status Card
|
// Status Card
|
||||||
Obx(() => Card(
|
Obx(() => Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -107,8 +108,16 @@ class GeolocationExample extends StatelessWidget {
|
|||||||
'Längengrad:',
|
'Längengrad:',
|
||||||
controller.currentPosition!.longitude.toStringAsFixed(6),
|
controller.currentPosition!.longitude.toStringAsFixed(6),
|
||||||
Icons.location_on,
|
Icons.location_on,
|
||||||
),
|
),
|
||||||
_buildPositionDetail(
|
if (controller.ptvModel != null &&
|
||||||
|
controller.ptvModel!.locations != null &&
|
||||||
|
controller.ptvModel!.locations!.isNotEmpty)
|
||||||
|
_buildPositionDetail(
|
||||||
|
'Adresse:',
|
||||||
|
'${controller.ptvModel!.locations!.first.formattedAddress}',
|
||||||
|
Icons.add_home_rounded,
|
||||||
|
),
|
||||||
|
_buildPositionDetail(
|
||||||
'Genauigkeit:',
|
'Genauigkeit:',
|
||||||
'${controller.currentPosition!.accuracy.toStringAsFixed(1)} m',
|
'${controller.currentPosition!.accuracy.toStringAsFixed(1)} m',
|
||||||
Icons.gps_fixed,
|
Icons.gps_fixed,
|
||||||
@ -137,92 +146,94 @@ class GeolocationExample extends StatelessWidget {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Action Buttons
|
// Action Buttons
|
||||||
Expanded(
|
Column(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
// Aktuelle Position Button
|
||||||
// Aktuelle Position Button
|
Obx(() => SizedBox(
|
||||||
Obx(() => SizedBox(
|
width: double.infinity,
|
||||||
width: double.infinity,
|
child: ElevatedButton.icon(
|
||||||
child: ElevatedButton.icon(
|
onPressed: controller.isLoading ? null : controller.getCurrentPosition,
|
||||||
onPressed: controller.isLoading ? null : controller.getCurrentPosition,
|
icon: controller.isLoading
|
||||||
icon: controller.isLoading
|
? const SizedBox(
|
||||||
? const SizedBox(
|
width: 20,
|
||||||
width: 20,
|
height: 20,
|
||||||
height: 20,
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
)
|
||||||
)
|
: const Icon(Icons.my_location),
|
||||||
: const Icon(Icons.my_location),
|
label: const Text('Aktuelle Position ermitteln'),
|
||||||
label: const Text('Aktuelle Position ermitteln'),
|
style: ElevatedButton.styleFrom(
|
||||||
style: ElevatedButton.styleFrom(
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
|
|
||||||
// Tracking Toggle Button
|
|
||||||
Obx(() => SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: controller.isLoading ? null : controller.toggleTracking,
|
|
||||||
icon: Icon(controller.isTracking ? Icons.stop : Icons.play_arrow),
|
|
||||||
label: Text(controller.isTracking ? 'Tracking stoppen' : 'Tracking starten'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: controller.isTracking ? Colors.red : Colors.green,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
|
|
||||||
// Permissions Button
|
|
||||||
Obx(() => SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: controller.isLoading ? null : controller.checkPermissions,
|
|
||||||
icon: const Icon(Icons.security),
|
|
||||||
label: const Text('Berechtigungen prüfen'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
|
|
||||||
// Settings Buttons Row
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: controller.openLocationSettings,
|
|
||||||
icon: const Icon(Icons.location_city),
|
|
||||||
label: const Text('Location'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: controller.openAppSettings,
|
|
||||||
icon: const Icon(Icons.settings),
|
|
||||||
label: const Text('App'),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
)),
|
||||||
),
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Tracking Toggle Button
|
||||||
|
Obx(() => SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: controller.isLoading ? null : controller.toggleTracking,
|
||||||
|
icon: Icon(controller.isTracking ? Icons.stop : Icons.play_arrow),
|
||||||
|
label: Text(controller.isTracking ? 'Tracking stoppen' : 'Tracking starten'),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: controller.isTracking ? Colors.red : Colors.green,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Permissions Button
|
||||||
|
Obx(() => SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: controller.isLoading ? null : controller.checkPermissions,
|
||||||
|
icon: const Icon(Icons.security),
|
||||||
|
label: const Text('Berechtigungen prüfen'),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Settings Buttons Row
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: controller.openLocationSettings,
|
||||||
|
icon: const Icon(Icons.location_city),
|
||||||
|
label: const Text('Location'),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: controller.openAppSettings,
|
||||||
|
icon: const Icon(Icons.settings),
|
||||||
|
label: const Text('App'),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
|
// Bottom Spacing
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -245,6 +256,7 @@ class GeolocationExample extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
value,
|
value,
|
||||||
style: const TextStyle(fontFamily: 'monospace'),
|
style: const TextStyle(fontFamily: 'monospace'),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
14
lib/pages/login/login_view.dart
Normal file
14
lib/pages/login/login_view.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import '../../controllers/login_controller.dart';
|
||||||
|
|
||||||
|
class LoginPage extends GetView<LoginController> {
|
||||||
|
const LoginPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Container(color: Colors.red.shade300, child: Center(child: Text('Login Page')),),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,14 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import '../bindings/login_binding.dart';
|
||||||
import '../pages/examples/geolocation_example.dart';
|
import '../pages/examples/geolocation_example.dart';
|
||||||
import '../bindings/geolocation_binding.dart';
|
import '../bindings/geolocation_binding.dart';
|
||||||
|
import '../pages/login/login_view.dart';
|
||||||
|
|
||||||
/// App Routes Konfiguration
|
/// App Routes Konfiguration
|
||||||
class AppRoutes {
|
class AppRoutes {
|
||||||
static const String home = '/';
|
static const String home = '/';
|
||||||
static const String geolocation = '/geolocation';
|
static const String geolocation = '/geolocation';
|
||||||
|
static const String login = '/login';
|
||||||
|
|
||||||
/// Route Pages Definition
|
/// Route Pages Definition
|
||||||
static List<GetPage> pages = [
|
static List<GetPage> pages = [
|
||||||
@ -16,13 +19,20 @@ class AppRoutes {
|
|||||||
transition: Transition.cupertino,
|
transition: Transition.cupertino,
|
||||||
transitionDuration: const Duration(milliseconds: 300),
|
transitionDuration: const Duration(milliseconds: 300),
|
||||||
),
|
),
|
||||||
|
GetPage(
|
||||||
|
name: login,
|
||||||
|
page: () => const LoginPage(),
|
||||||
|
binding: LoginBinding(), // Dependency Injection
|
||||||
|
transition: Transition.cupertino,
|
||||||
|
transitionDuration: const Duration(milliseconds: 300),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Route Namen als Konstanten für typsichere Navigation
|
/// Route Namen als Konstanten für typsichere Navigation
|
||||||
class Routes {
|
// class Routes {
|
||||||
static const String geolocationExample = '/geolocation-example';
|
// static const String geolocationExample = '/geolocation-example';
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Navigation Helper Klasse
|
/// Navigation Helper Klasse
|
||||||
class AppNavigation {
|
class AppNavigation {
|
||||||
@ -31,11 +41,6 @@ class AppNavigation {
|
|||||||
Get.toNamed(AppRoutes.geolocation);
|
Get.toNamed(AppRoutes.geolocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Navigate back
|
|
||||||
static void back() {
|
|
||||||
Get.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Navigate and replace current route
|
/// Navigate and replace current route
|
||||||
static void offGeolocation() {
|
static void offGeolocation() {
|
||||||
Get.offNamed(AppRoutes.geolocation);
|
Get.offNamed(AppRoutes.geolocation);
|
||||||
@ -45,4 +50,25 @@ class AppNavigation {
|
|||||||
static void offAllToGeolocation() {
|
static void offAllToGeolocation() {
|
||||||
Get.offAllNamed(AppRoutes.geolocation);
|
Get.offAllNamed(AppRoutes.geolocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Navigate to Login Page
|
||||||
|
static void toLogin() {
|
||||||
|
Get.toNamed(AppRoutes.login);
|
||||||
|
}
|
||||||
|
/// Navigate and replace current route
|
||||||
|
static void offLogin() {
|
||||||
|
Get.offNamed(AppRoutes.login);
|
||||||
|
}
|
||||||
|
/// Navigate and clear all previous routes
|
||||||
|
static void offAllToLogin() {
|
||||||
|
Get.offAllNamed(AppRoutes.login);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Navigate back
|
||||||
|
static void back() {
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
354
lib/services/ptv_api_simple.dart
Normal file
354
lib/services/ptv_api_simple.dart
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
/// Einfacher PTV API Service mit statischen Methoden
|
||||||
|
class PtvApiServiceSimple {
|
||||||
|
/// Private Konstruktor
|
||||||
|
PtvApiServiceSimple._();
|
||||||
|
|
||||||
|
/// Base URL der PTV API
|
||||||
|
static const String _baseUrl = 'https://api.myptv.com/geocoding/v1/locations/by-position';
|
||||||
|
|
||||||
|
/// Standard Sprache
|
||||||
|
static const String _defaultLanguage = 'de';
|
||||||
|
|
||||||
|
/// Timeout in Sekunden
|
||||||
|
static const int _timeoutSeconds = 15;
|
||||||
|
|
||||||
|
/// API Key aus .env Datei
|
||||||
|
static String get _apiKey => dotenv.env['PTVE_API_KEY'] ?? '';
|
||||||
|
|
||||||
|
/// HTTP Headers
|
||||||
|
static Map<String, String> get _headers => {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'ApiKey': _apiKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Hauptmethode: Holt Location-Daten für gegebene Koordinaten
|
||||||
|
///
|
||||||
|
/// Beispiel URL: https://api.myptv.com/geocoding/v1/locations/by-position/48.208282/14.214758?language=de
|
||||||
|
///
|
||||||
|
/// [latitude] - Breitengrad (z.B. 48.208282)
|
||||||
|
/// [longitude] - Längengrad (z.B. 14.214758)
|
||||||
|
/// [language] - Sprache für Antwort (default: 'de')
|
||||||
|
///
|
||||||
|
/// Returns Map mit API-Response oder null bei Fehler
|
||||||
|
static Future<Map<String, dynamic>?> getLocationsByPosition({
|
||||||
|
required double latitude,
|
||||||
|
required double longitude,
|
||||||
|
String language = _defaultLanguage,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
// Validiere Koordinaten
|
||||||
|
if (!_isValidCoordinate(latitude, longitude)) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ Ungültige Koordinaten: lat=$latitude, lng=$longitude');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lade .env falls API Key leer
|
||||||
|
if (_apiKey.isEmpty) {
|
||||||
|
await dotenv.load(fileName: ".env");
|
||||||
|
if (_apiKey.isEmpty) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ PTVE_API_KEY nicht in .env gefunden');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baue URL
|
||||||
|
final url = '$_baseUrl/$latitude/$longitude?language=$language';
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('🌐 PTV API Request: $url');
|
||||||
|
print('🔑 API Key vorhanden: ${_apiKey.isNotEmpty}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP GET Request
|
||||||
|
final response = await http
|
||||||
|
.get(
|
||||||
|
Uri.parse(url),
|
||||||
|
headers: _headers,
|
||||||
|
)
|
||||||
|
.timeout(Duration(seconds: _timeoutSeconds));
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('📡 Response Status: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verarbeite Response
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final jsonData = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('✅ API Request erfolgreich');
|
||||||
|
print('📍 Locations gefunden: ${(jsonData['locations'] as List?)?.length ?? 0}');
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonData;
|
||||||
|
} else {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ API Fehler: ${response.statusCode}');
|
||||||
|
print('📄 Response Body: ${response.body}');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ Exception beim API Aufruf: $e');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Erweiterte Methode mit zusätzlichen Parametern
|
||||||
|
static Future<Map<String, dynamic>?> getLocationsByPositionAdvanced({
|
||||||
|
required double latitude,
|
||||||
|
required double longitude,
|
||||||
|
String language = _defaultLanguage,
|
||||||
|
int? maxResults,
|
||||||
|
int? radius,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
// Baue URL mit zusätzlichen Query-Parametern
|
||||||
|
String url = '$_baseUrl/$latitude/$longitude?language=$language';
|
||||||
|
|
||||||
|
if (maxResults != null && maxResults > 0) {
|
||||||
|
url += '&maxResults=$maxResults';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius != null && radius > 0) {
|
||||||
|
url += '&radius=$radius';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('🌐 PTV API Advanced Request: $url');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http
|
||||||
|
.get(
|
||||||
|
Uri.parse(url),
|
||||||
|
headers: _headers,
|
||||||
|
)
|
||||||
|
.timeout(Duration(seconds: _timeoutSeconds));
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
} else {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ Advanced API Fehler: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ Exception bei erweiterter API Abfrage: $e');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hilfsmethoden
|
||||||
|
|
||||||
|
/// Validiert GPS-Koordinaten
|
||||||
|
static bool _isValidCoordinate(double latitude, double longitude) {
|
||||||
|
return latitude >= -90 &&
|
||||||
|
latitude <= 90 &&
|
||||||
|
longitude >= -180 &&
|
||||||
|
longitude <= 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prüft API-Verfügbarkeit mit Test-Request
|
||||||
|
static Future<bool> testApiConnection() async {
|
||||||
|
try {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('\n🧪 PTV API CONNECTION TEST 🧪');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test mit Wien Koordinaten
|
||||||
|
final result = await getLocationsByPosition(
|
||||||
|
latitude: 48.2082,
|
||||||
|
longitude: 16.3738,
|
||||||
|
);
|
||||||
|
|
||||||
|
final success = result != null;
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(success ? '✅ API Test erfolgreich' : '❌ API Test fehlgeschlagen');
|
||||||
|
print('🧪 TEST ABGESCHLOSSEN\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
} catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ Test Exception: $e');
|
||||||
|
print('🧪 TEST ABGESCHLOSSEN\n');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Debugging: Zeigt Service-Informationen
|
||||||
|
static void printServiceInfo() {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('\n📋 PTV API SERVICE INFO 📋');
|
||||||
|
print('Base URL: $_baseUrl');
|
||||||
|
print('Default Language: $_defaultLanguage');
|
||||||
|
print('Timeout: ${_timeoutSeconds}s');
|
||||||
|
print('API Key verfügbar: ${_apiKey.isNotEmpty}');
|
||||||
|
print('API Key Length: ${_apiKey.length}');
|
||||||
|
print('📋 SERVICE INFO END 📋\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Demonstration der API-Verwendung
|
||||||
|
static Future<void> runDemo() async {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('\n🚀 PTV API DEMO START 🚀');
|
||||||
|
|
||||||
|
// Service Info
|
||||||
|
printServiceInfo();
|
||||||
|
|
||||||
|
// Test Connection
|
||||||
|
await testApiConnection();
|
||||||
|
|
||||||
|
// Beispiel 1: Traun, Österreich
|
||||||
|
print('📍 Beispiel 1: Traun, Österreich');
|
||||||
|
final traunResult = await getLocationsByPosition(
|
||||||
|
latitude: 48.208282,
|
||||||
|
longitude: 14.214758,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (traunResult != null) {
|
||||||
|
final locations = traunResult['locations'] as List?;
|
||||||
|
if (locations != null && locations.isNotEmpty) {
|
||||||
|
final firstLocation = locations.first;
|
||||||
|
print('✅ Gefunden: ${firstLocation['formattedAddress']}');
|
||||||
|
print('📍 Koordinaten: ${firstLocation['referencePosition']['latitude']}, ${firstLocation['referencePosition']['longitude']}');
|
||||||
|
|
||||||
|
final quality = firstLocation['quality'];
|
||||||
|
if (quality != null) {
|
||||||
|
print('🎯 Genauigkeit: ${quality['distance']}m');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print('❌ Keine Daten für Traun erhalten');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beispiel 2: Wien mit erweiterten Parametern
|
||||||
|
print('\n📍 Beispiel 2: Wien (erweitert)');
|
||||||
|
final wienResult = await getLocationsByPositionAdvanced(
|
||||||
|
latitude: 48.2082,
|
||||||
|
longitude: 16.3738,
|
||||||
|
maxResults: 3,
|
||||||
|
radius: 500,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (wienResult != null) {
|
||||||
|
final locations = wienResult['locations'] as List?;
|
||||||
|
print('✅ Wien Locations gefunden: ${locations?.length ?? 0}');
|
||||||
|
|
||||||
|
if (locations != null) {
|
||||||
|
for (int i = 0; i < locations.length && i < 3; i++) {
|
||||||
|
final location = locations[i];
|
||||||
|
print(' ${i + 1}. ${location['formattedAddress']}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('🚀 DEMO ABGESCHLOSSEN 🚀\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility-Klasse für häufige PTV-Operationen
|
||||||
|
class PtvApiUtils {
|
||||||
|
/// Extrahiert die beste Location aus der API-Response
|
||||||
|
static Map<String, dynamic>? getBestLocation(Map<String, dynamic> apiResponse) {
|
||||||
|
final locations = apiResponse['locations'] as List?;
|
||||||
|
if (locations == null || locations.isEmpty) return null;
|
||||||
|
|
||||||
|
// Suche Location mit geringster Distanz
|
||||||
|
Map<String, dynamic>? bestLocation;
|
||||||
|
double? bestDistance;
|
||||||
|
|
||||||
|
for (final location in locations) {
|
||||||
|
final quality = location['quality'];
|
||||||
|
if (quality != null) {
|
||||||
|
final distance = (quality['distance'] as num?)?.toDouble();
|
||||||
|
if (distance != null && (bestDistance == null || distance < bestDistance)) {
|
||||||
|
bestDistance = distance;
|
||||||
|
bestLocation = location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestLocation ?? locations.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extrahiert formatierte Adresse
|
||||||
|
static String? getFormattedAddress(Map<String, dynamic> apiResponse) {
|
||||||
|
final bestLocation = getBestLocation(apiResponse);
|
||||||
|
return bestLocation?['formattedAddress'] as String?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extrahiert Koordinaten
|
||||||
|
static Map<String, double>? getCoordinates(Map<String, dynamic> apiResponse) {
|
||||||
|
final bestLocation = getBestLocation(apiResponse);
|
||||||
|
final refPos = bestLocation?['referencePosition'];
|
||||||
|
|
||||||
|
if (refPos != null) {
|
||||||
|
return {
|
||||||
|
'latitude': (refPos['latitude'] as num?)?.toDouble() ?? 0.0,
|
||||||
|
'longitude': (refPos['longitude'] as num?)?.toDouble() ?? 0.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prüft Qualität der Location
|
||||||
|
static String getQualityLevel(Map<String, dynamic> apiResponse) {
|
||||||
|
final bestLocation = getBestLocation(apiResponse);
|
||||||
|
final quality = bestLocation?['quality'];
|
||||||
|
|
||||||
|
if (quality != null) {
|
||||||
|
final distance = (quality['distance'] as num?)?.toDouble() ?? 999999;
|
||||||
|
|
||||||
|
if (distance <= 10) return 'Sehr hoch';
|
||||||
|
if (distance <= 50) return 'Hoch';
|
||||||
|
if (distance <= 100) return 'Mittel';
|
||||||
|
if (distance <= 500) return 'Niedrig';
|
||||||
|
return 'Sehr niedrig';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Unbekannt';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Konvertiert API-Response zu lesbarem String
|
||||||
|
static String formatLocationInfo(Map<String, dynamic> apiResponse) {
|
||||||
|
final bestLocation = getBestLocation(apiResponse);
|
||||||
|
if (bestLocation == null) return 'Keine Location gefunden';
|
||||||
|
|
||||||
|
final address = bestLocation['formattedAddress'] ?? 'Unbekannte Adresse';
|
||||||
|
final refPos = bestLocation['referencePosition'];
|
||||||
|
final quality = bestLocation['quality'];
|
||||||
|
|
||||||
|
String info = 'Adresse: $address\n';
|
||||||
|
|
||||||
|
if (refPos != null) {
|
||||||
|
info += 'Koordinaten: ${refPos['latitude']}, ${refPos['longitude']}\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quality != null) {
|
||||||
|
info += 'Genauigkeit: ${quality['distance']}m (${getQualityLevel(apiResponse)})\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,18 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||||
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
#include <window_to_front/window_to_front_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin");
|
||||||
|
desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) window_to_front_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin");
|
||||||
|
window_to_front_plugin_register_with_registrar(window_to_front_registrar);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
desktop_webview_window
|
||||||
|
url_launcher_linux
|
||||||
|
window_to_front
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
@ -5,10 +5,22 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import desktop_webview_window
|
||||||
|
import device_info_plus
|
||||||
|
import flutter_web_auth_2
|
||||||
import geolocator_apple
|
import geolocator_apple
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
|
import path_provider_foundation
|
||||||
|
import url_launcher_macos
|
||||||
|
import window_to_front
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||||
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
|
FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin"))
|
||||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
|
WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
234
pubspec.lock
234
pubspec.lock
@ -1,6 +1,14 @@
|
|||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
appwrite:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: appwrite
|
||||||
|
sha256: "358a443ba8366d48fc8cdec88645b97eb8f3941ea4244c2e6d524603e4d7f27e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "17.0.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -49,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
|
cookie_jar:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cookie_jar
|
||||||
|
sha256: a6ac027d3ed6ed756bfce8f3ff60cb479e266f3b0fdabd6242b804b6765e52de
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.8"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -73,6 +89,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.11"
|
version: "0.7.11"
|
||||||
|
desktop_webview_window:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: desktop_webview_window
|
||||||
|
sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
|
device_info_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus
|
||||||
|
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.1.2"
|
||||||
|
device_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: device_info_plus_platform_interface
|
||||||
|
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.3"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -89,6 +129,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -102,6 +150,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_dotenv:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_dotenv
|
||||||
|
sha256: d4130c4a43e0b13fefc593bc3961f2cb46e30cb79e253d4a526b1b5d24ae1ce4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -115,6 +171,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_auth_2:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_web_auth_2
|
||||||
|
sha256: "3c14babeaa066c371f3a743f204dd0d348b7d42ffa6fae7a9847a521aff33696"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
|
flutter_web_auth_2_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_web_auth_2_platform_interface
|
||||||
|
sha256: c63a472c8070998e4e422f6b34a17070e60782ac442107c70000dd1bed645f4d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -296,6 +368,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.9.1"
|
||||||
|
path_provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: e122c5ea805bb6773bb12ce667611265980940145be920cd09a4b0ec0285cb16
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.20"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: efaec349ddfc181528345c56f8eda9d6cccd71c177511b132c6a0ddaefaa2738
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.3"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -304,6 +424,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.6"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -381,6 +509,78 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
|
universal_io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_io
|
||||||
|
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.2"
|
||||||
|
url_launcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.2"
|
||||||
|
url_launcher_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_android
|
||||||
|
sha256: "5c8b6c2d89a78f5a1cca70a73d9d5f86c701b36b42f9c9dac7bad592113c28e9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.24"
|
||||||
|
url_launcher_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_ios
|
||||||
|
sha256: "6b63f1441e4f653ae799166a72b50b1767321ecc263a57aadf825a7a2a5477d9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.5"
|
||||||
|
url_launcher_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_linux
|
||||||
|
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
url_launcher_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_macos
|
||||||
|
sha256: "8262208506252a3ed4ff5c0dc1e973d2c0e0ef337d0a074d35634da5d44397c9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.4"
|
||||||
|
url_launcher_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_platform_interface
|
||||||
|
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
url_launcher_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_web
|
||||||
|
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
url_launcher_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_windows
|
||||||
|
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.4"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -413,6 +613,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket
|
||||||
|
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -421,6 +637,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.15.0"
|
version: "5.15.0"
|
||||||
|
win32_registry:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32_registry
|
||||||
|
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.5"
|
||||||
|
window_to_front:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: window_to_front
|
||||||
|
sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.3"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -439,4 +671,4 @@ packages:
|
|||||||
version: "6.6.1"
|
version: "6.6.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.9.2 <4.0.0"
|
dart: ">=3.9.2 <4.0.0"
|
||||||
flutter: ">=3.19.0"
|
flutter: ">=3.35.0"
|
||||||
|
|||||||
@ -16,6 +16,8 @@ dependencies:
|
|||||||
get: ^4.7.2
|
get: ^4.7.2
|
||||||
http: ^1.5.0
|
http: ^1.5.0
|
||||||
geolocator: ^14.0.2
|
geolocator: ^14.0.2
|
||||||
|
flutter_dotenv: ^6.0.0
|
||||||
|
appwrite: 17.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -28,3 +30,4 @@ flutter:
|
|||||||
|
|
||||||
assets:
|
assets:
|
||||||
- assets/img/
|
- assets/img/
|
||||||
|
- .env
|
||||||
|
|||||||
61
test/ptv_api_simple_test.dart
Normal file
61
test/ptv_api_simple_test.dart
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// ignore_for_file: avoid_print
|
||||||
|
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
import 'package:web_flutter_tank_appwrite_app/services/ptv_api_simple.dart';
|
||||||
|
|
||||||
|
/// Quick Test der PTV API Simple Integration
|
||||||
|
void main() async {
|
||||||
|
print('🚀 PTV API SIMPLE TEST START 🚀');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Lade .env
|
||||||
|
await dotenv.load(fileName: ".env");
|
||||||
|
print('✅ .env Datei geladen');
|
||||||
|
|
||||||
|
// Test Service Info
|
||||||
|
PtvApiServiceSimple.printServiceInfo();
|
||||||
|
|
||||||
|
// Connection Test
|
||||||
|
print('\n🧪 CONNECTION TEST 🧪');
|
||||||
|
final connectionOk = await PtvApiServiceSimple.testApiConnection();
|
||||||
|
print('🔗 Verbindung: ${connectionOk ? "OK" : "FEHLER"}');
|
||||||
|
|
||||||
|
if (connectionOk) {
|
||||||
|
print('\n📍 API TEST MIT BEISPIELKOORDINATEN 📍');
|
||||||
|
|
||||||
|
// Test mit Traun Koordinaten
|
||||||
|
final result = await PtvApiServiceSimple.getLocationsByPosition(
|
||||||
|
latitude: 48.208282,
|
||||||
|
longitude: 14.214758,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
print('✅ API Response erhalten');
|
||||||
|
|
||||||
|
// Verwende Utility-Funktionen
|
||||||
|
final address = PtvApiUtils.getFormattedAddress(result);
|
||||||
|
final coords = PtvApiUtils.getCoordinates(result);
|
||||||
|
final quality = PtvApiUtils.getQualityLevel(result);
|
||||||
|
|
||||||
|
print('📝 Adresse: $address');
|
||||||
|
print('📍 Koordinaten: ${coords?['latitude']}, ${coords?['longitude']}');
|
||||||
|
print('⭐ Qualität: $quality');
|
||||||
|
|
||||||
|
print('\n📄 Komplette Info:');
|
||||||
|
print(PtvApiUtils.formatLocationInfo(result));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
print('❌ Keine API Response - prüfe API Key in .env');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
print('❌ API Connection Test fehlgeschlagen');
|
||||||
|
print('⚠️ Prüfe PTVE_API_KEY in .env Datei');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
print('❌ Test Exception: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
print('\n🚀 TEST ABGESCHLOSSEN 🚀');
|
||||||
|
}
|
||||||
@ -6,9 +6,18 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||||
#include <geolocator_windows/geolocator_windows.h>
|
#include <geolocator_windows/geolocator_windows.h>
|
||||||
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
#include <window_to_front/window_to_front_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
DesktopWebviewWindowPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||||
GeolocatorWindowsRegisterWithRegistrar(
|
GeolocatorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||||
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
|
WindowToFrontPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("WindowToFrontPlugin"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,10 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
desktop_webview_window
|
||||||
geolocator_windows
|
geolocator_windows
|
||||||
|
url_launcher_windows
|
||||||
|
window_to_front
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user