mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2025-08-05 04:36:41 +00:00
save geolocation
This commit is contained in:
parent
1412ce2b3e
commit
39501ee4ac
16 changed files with 163 additions and 14 deletions
|
@ -47,6 +47,9 @@
|
|||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="true" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.MICROPHONE" tools:node="remove" />
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="false" />
|
||||
|
|
|
@ -53,5 +53,9 @@
|
|||
<false/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Provide camera permissions in order to make measurements</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Provide location permissions to save coordinates with your photos</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Provide location permissions to save coordinates with your photos</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:lightmeter/data/analytics/analytics.dart';
|
|||
import 'package:lightmeter/data/analytics/api/analytics_firebase.dart';
|
||||
import 'package:lightmeter/data/caffeine_service.dart';
|
||||
import 'package:lightmeter/data/camera_info_service.dart';
|
||||
import 'package:lightmeter/data/geolocation_service.dart';
|
||||
import 'package:lightmeter/data/haptics_service.dart';
|
||||
import 'package:lightmeter/data/light_sensor_service.dart';
|
||||
import 'package:lightmeter/data/permissions_service.dart';
|
||||
|
@ -71,6 +72,7 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
|
|||
analytics: const LightmeterAnalytics(api: LightmeterAnalyticsFirebase()),
|
||||
caffeineService: const CaffeineService(),
|
||||
environment: widget.env.copyWith(hasLightSensor: hasLightSensor),
|
||||
geolocationService: const GeolocationService(),
|
||||
hapticsService: const HapticsService(),
|
||||
lightSensorService: const LightSensorService(LocalPlatform()),
|
||||
permissionsService: const PermissionsService(),
|
||||
|
|
55
lib/data/geolocation_service.dart
Normal file
55
lib/data/geolocation_service.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class GeolocationService {
|
||||
const GeolocationService();
|
||||
|
||||
/// Gets the current position and returns Coordinates if successful
|
||||
/// Returns null if location services are disabled or permission is denied
|
||||
Future<Coordinates?> getCurrentPosition() async {
|
||||
try {
|
||||
// Check if location services are enabled
|
||||
final isLocationServiceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!isLocationServiceEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check location permission
|
||||
final permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
final requestedPermission = await Geolocator.requestPermission();
|
||||
if (requestedPermission == LocationPermission.denied ||
|
||||
requestedPermission == LocationPermission.deniedForever) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current position
|
||||
final position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: const LocationSettings(
|
||||
timeLimit: Duration(seconds: 10),
|
||||
),
|
||||
);
|
||||
|
||||
return Coordinates(position.latitude, position.longitude);
|
||||
} catch (e) {
|
||||
// Return null if any error occurs (timeout, no GPS signal, etc.)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if location services are enabled
|
||||
Future<bool> isLocationServiceEnabled() async {
|
||||
return await Geolocator.isLocationServiceEnabled();
|
||||
}
|
||||
|
||||
/// Checks current location permission status
|
||||
Future<LocationPermission> checkPermission() async {
|
||||
return await Geolocator.checkPermission();
|
||||
}
|
||||
|
||||
/// Requests location permission
|
||||
Future<LocationPermission> requestPermission() async {
|
||||
return await Geolocator.requestPermission();
|
||||
}
|
||||
}
|
|
@ -171,5 +171,7 @@
|
|||
"ndFilter": "ND Filter",
|
||||
"film": "Film",
|
||||
"note": "Notiz",
|
||||
"notSet": "Nicht gesetzt"
|
||||
"notSet": "Nicht gesetzt",
|
||||
"location": "Standort",
|
||||
"noMapsAppFound": "Keine Kartenanwendung gefunden."
|
||||
}
|
|
@ -171,5 +171,7 @@
|
|||
"ndFilter": "ND Filter",
|
||||
"film": "Film",
|
||||
"note": "Note",
|
||||
"notSet": "Not set"
|
||||
"notSet": "Not set",
|
||||
"location": "Location",
|
||||
"noMapsAppFound": "No maps application found."
|
||||
}
|
|
@ -162,5 +162,7 @@
|
|||
"ndFilter": "Filtre ND",
|
||||
"film": "Film",
|
||||
"note": "Note",
|
||||
"notSet": "Non défini"
|
||||
"notSet": "Non défini",
|
||||
"location": "Emplacement",
|
||||
"noMapsAppFound": "Aucune application de cartes trouvée."
|
||||
}
|
|
@ -161,5 +161,7 @@
|
|||
"ndFilter": "ND фильтр",
|
||||
"film": "Плёнка",
|
||||
"note": "Заметка",
|
||||
"notSet": "Не задано"
|
||||
"notSet": "Не задано",
|
||||
"location": "Местоположение",
|
||||
"noMapsAppFound": "Приложение карт не найдено."
|
||||
}
|
|
@ -159,5 +159,7 @@
|
|||
"ndFilter": "ND 滤镜",
|
||||
"film": "胶片",
|
||||
"note": "备注",
|
||||
"notSet": "未设置"
|
||||
"notSet": "未设置",
|
||||
"location": "位置",
|
||||
"noMapsAppFound": "未找到地图应用程序。"
|
||||
}
|
|
@ -2,7 +2,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/providers/services_provider.dart';
|
||||
import 'package:lightmeter/utils/context_utils.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
@ -63,6 +63,10 @@ class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
|
|||
required int nd,
|
||||
}) async {
|
||||
if (context.isPro) {
|
||||
// Get coordinates from geolocation service
|
||||
final geolocationService = ServicesProvider.of(context).geolocationService;
|
||||
final coordinates = await geolocationService.getCurrentPosition();
|
||||
|
||||
final photo = LogbookPhoto(
|
||||
id: const UuidV8().generate(),
|
||||
name: path,
|
||||
|
@ -70,9 +74,9 @@ class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
|
|||
ev: ev100,
|
||||
iso: iso,
|
||||
nd: nd,
|
||||
coordinates: null, // TODO
|
||||
coordinates: coordinates,
|
||||
);
|
||||
//await widget.storageService.addPhoto(photo);
|
||||
await widget.storageService.addPhoto(photo);
|
||||
_photos[photo.id] = photo;
|
||||
setState(() {});
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/analytics/analytics.dart';
|
||||
import 'package:lightmeter/data/caffeine_service.dart';
|
||||
import 'package:lightmeter/data/geolocation_service.dart';
|
||||
import 'package:lightmeter/data/haptics_service.dart';
|
||||
import 'package:lightmeter/data/light_sensor_service.dart';
|
||||
import 'package:lightmeter/data/permissions_service.dart';
|
||||
|
@ -13,6 +14,7 @@ class ServicesProvider extends InheritedWidget {
|
|||
final LightmeterAnalytics analytics;
|
||||
final CaffeineService caffeineService;
|
||||
final Environment environment;
|
||||
final GeolocationService geolocationService;
|
||||
final HapticsService hapticsService;
|
||||
final LightSensorService lightSensorService;
|
||||
final PermissionsService permissionsService;
|
||||
|
@ -23,6 +25,7 @@ class ServicesProvider extends InheritedWidget {
|
|||
required this.analytics,
|
||||
required this.caffeineService,
|
||||
required this.environment,
|
||||
required this.geolocationService,
|
||||
required this.hapticsService,
|
||||
required this.lightSensorService,
|
||||
required this.permissionsService,
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/navigation/routes.dart';
|
||||
import 'package:lightmeter/platform_config.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/logbook_photos_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/equipment_profile_edit/flow_equipment_profile_edit.dart';
|
||||
import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart';
|
||||
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
|
|||
iso: photo.iso,
|
||||
nd: photo.nd,
|
||||
coordinates: photo.coordinates,
|
||||
aperture: null,
|
||||
shutterSpeed: null,
|
||||
note: photo.note,
|
||||
canSave: false,
|
||||
),
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/state_logbook_photo_edit.dart';
|
||||
import 'package:map_launcher/map_launcher.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class LogbookPhotoCoordinatesListTile extends StatefulWidget {
|
||||
const LogbookPhotoCoordinatesListTile();
|
||||
|
||||
@override
|
||||
State<LogbookPhotoCoordinatesListTile> createState() => LogbookPhotoCoordinatesListTileState();
|
||||
}
|
||||
|
||||
class LogbookPhotoCoordinatesListTileState extends State<LogbookPhotoCoordinatesListTile> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (previous, current) => previous.note != current.note,
|
||||
builder: (context, state) {
|
||||
final coords = state.coordinates;
|
||||
final hasCoords = coords != null;
|
||||
final text = hasCoords ? '${coords.latitude.toStringAsFixed(6)}, ${coords.longitude.toStringAsFixed(6)}' : '-';
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.location_on_outlined),
|
||||
title: Text(S.of(context).location),
|
||||
trailing: Text(text),
|
||||
onTap: hasCoords
|
||||
? () async {
|
||||
final lat = coords.latitude;
|
||||
final lng = coords.longitude;
|
||||
final availableMaps = await MapLauncher.installedMaps;
|
||||
if (availableMaps.isEmpty) {
|
||||
// Fallback to Google Maps in browser
|
||||
final url = Uri.parse('https://www.google.com/maps/search/?api=1&query=$lat,$lng');
|
||||
if (await canLaunchUrl(url)) {
|
||||
await launchUrl(url, mode: LaunchMode.externalApplication);
|
||||
} else if (mounted) {
|
||||
_showSnackBar();
|
||||
}
|
||||
return;
|
||||
}
|
||||
await MapLauncher.showMarker(
|
||||
mapType: availableMaps.first.mapType,
|
||||
coords: Coords(lat, lng),
|
||||
title: text,
|
||||
description: state.note,
|
||||
);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showSnackBar() async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(S.of(context).youDontHaveMailApp),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import 'package:lightmeter/generated/l10n.dart';
|
|||
import 'package:lightmeter/platform_config.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/components/coordinates_list_tile/widget_list_tile_coordinates_logbook_photo.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/components/picker_list_tile/widget_list_tile_picker.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/event_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/state_logbook_photo_edit.dart';
|
||||
|
@ -77,6 +78,7 @@ class _LogbookPhotoEditScreenState extends State<LogbookPhotoEditScreen> {
|
|||
child: const Column(
|
||||
children: [
|
||||
_DateListTile(),
|
||||
LogbookPhotoCoordinatesListTile(),
|
||||
_NoteListTile(),
|
||||
_EvListTile(),
|
||||
_IsoListTile(),
|
||||
|
|
|
@ -26,6 +26,7 @@ dependencies:
|
|||
flutter_localizations:
|
||||
sdk: flutter
|
||||
flutter_native_splash: 2.4.4
|
||||
geolocator: 13.0.1
|
||||
intl: 0.19.0
|
||||
intl_utils: 2.8.7
|
||||
light_sensor: 3.0.1
|
||||
|
@ -46,6 +47,7 @@ dependencies:
|
|||
url_launcher_ios: 6.3.2
|
||||
uuid: 4.5.1
|
||||
vibration: 2.0.1
|
||||
map_launcher: 3.2.0
|
||||
|
||||
dev_dependencies:
|
||||
args: 2.6.0
|
||||
|
@ -65,6 +67,11 @@ dev_dependencies:
|
|||
test: 1.25.7
|
||||
|
||||
dependency_overrides:
|
||||
geolocator_android: 4.6.1
|
||||
m3_lightmeter_iap:
|
||||
path: /Users/vodemn/Documents/GitHub/Vodemn/m3_lightmeter_iap
|
||||
m3_lightmeter_resources:
|
||||
path: /Users/vodemn/Documents/GitHub/Vodemn/m3_lightmeter_resources
|
||||
material_color_utilities: 0.11.1
|
||||
|
||||
flutter:
|
||||
|
|
Loading…
Reference in a new issue