Files
Tomas Dvorak 37ffb93923 feat: Complete Phase 1 - Full Flutter app implementation with comprehensive features
Version: 1.1.0

Major changes:
- Implemented complete Flutter app structure with all core features
- Added comprehensive UI screens for auth, countdown, goals, profile, settings, and social features
- Integrated Supabase backend with authentication and data repositories
- Added offline support with Hive caching and local storage
- Implemented comprehensive routing with go_router
- Added location services with Google Maps integration
- Implemented notifications and home widget support
- Added voice recording capabilities and AI chat features
- Created comprehensive test suite and documentation
- Added Android and iOS platform configurations
- Implemented achievements system and social features
- Added calendar integration and bucket list functionality

This represents a complete Phase 1 milestone with 3,775 additions across 31 files.
2026-01-04 14:33:54 +01:00

202 lines
6.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class LocationPickerResult {
final LatLng position;
final String address;
LocationPickerResult({
required this.position,
required this.address,
});
}
class LocationPickerScreen extends StatefulWidget {
final LatLng? initialPosition;
const LocationPickerScreen({
super.key,
this.initialPosition,
});
@override
State<LocationPickerScreen> createState() => _LocationPickerScreenState();
}
class _LocationPickerScreenState extends State<LocationPickerScreen> {
late GoogleMapController _mapController;
LatLng _selectedPosition = const LatLng(0, 0);
Set<Marker> _markers = {};
bool _isLoading = true;
final String _selectedAddress = 'Selected Location';
@override
void initState() {
super.initState();
_initializeMap();
}
Future<void> _initializeMap() async {
try {
if (widget.initialPosition != null) {
_selectedPosition = widget.initialPosition!;
} else {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
_selectedPosition = LatLng(position.latitude, position.longitude);
}
_updateMarker();
setState(() => _isLoading = false);
} catch (e) {
setState(() => _isLoading = false);
}
}
void _updateMarker() {
setState(() {
_markers = {
Marker(
markerId: const MarkerId('selected_location'),
position: _selectedPosition,
draggable: true,
onDragEnd: (LatLng newPosition) {
setState(() {
_selectedPosition = newPosition;
_markers = {
Marker(
markerId: const MarkerId('selected_location'),
position: newPosition,
draggable: true,
),
};
});
},
),
};
});
}
void _onMapCreated(GoogleMapController controller) {
_mapController = controller;
}
Future<void> _getCurrentLocation() async {
try {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
final newLatLng = LatLng(position.latitude, position.longitude);
setState(() => _selectedPosition = newLatLng);
_updateMarker();
_mapController.animateCamera(
CameraUpdate.newLatLngZoom(newLatLng, 15),
);
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error getting location: $e')),
);
}
}
}
void _confirmLocation() {
Navigator.pop(
context,
LocationPickerResult(
position: _selectedPosition,
address: _selectedAddress,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Select Location'),
actions: [
IconButton(
icon: const Icon(Icons.my_location),
onPressed: _getCurrentLocation,
tooltip: 'Use current location',
),
],
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: Column(
children: [
Expanded(
child: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: _selectedPosition,
zoom: 15,
),
markers: _markers,
onTap: (LatLng position) {
setState(() => _selectedPosition = position);
_updateMarker();
},
myLocationEnabled: true,
myLocationButtonEnabled: false,
),
),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 10,
offset: const Offset(0, -2),
),
],
),
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
const Icon(Icons.location_on),
const SizedBox(width: 8),
Expanded(
child: Text(
'${_selectedPosition.latitude.toStringAsFixed(6)}, ${_selectedPosition.longitude.toStringAsFixed(6)}',
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _confirmLocation,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text('Confirm Location'),
),
),
],
),
),
),
],
),
);
}
}