Files
rog_app/lib/utils/location_controller.dart
2024-09-08 18:16:51 +09:00

434 lines
18 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
//import 'package:gifunavi/widgets/debug_widget.dart';
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
import 'package:gifunavi/pages/destination/destination_controller.dart';
import 'package:gifunavi/pages/permission/permission.dart';
// LocationControllerクラスは、GetxControllerを継承したクラスであり、位置情報の管理を担当しています。
// LocationControllerは以下の機能を提供しています。
// LocationControllerは、アプリ全体で位置情報を一元管理するための重要なコンポーネントです。
// 他のコンポーネントは、LocationControllerから位置情報を取得し、位置情報に関連する機能を実装することができます。
//
// Features:
// * 現在の位置情報を保持し、他のコンポーネントからアクセスできるようにします。
// * 位置情報のストリームを管理し、位置情報の更新を監視します。
// * 位置情報サービスの有効性と権限の確認を行い、適切な処理を行います。
// * 位置情報のストリームを開始、停止、再開する機能を提供します。
// * 位置マーカーの位置情報をStreamControllerを通じて他のコンポーネントに通知します。
//
// Logic:
// 1. startPositionStreamメソッドで、Geolocator.getPositionStreamを使用して位置情報のストリームを開始します。
// 2. ストリームから位置情報を受信すると、LocationMarkerPositionオブジェクトを作成し、locationMarkerPositionStreamControllerに追加します。
// 3. 位置情報が取得できなかった場合や、エラーが発生した場合は、適切な処理を行います。
// 4. stopPositionStreamメソッドで、位置情報のストリームを一時停止することができます。
// 5. resumePositionStreamメソッドで、一時停止中の位置情報のストリームを再開することができます。
// 6. onCloseメソッドで、コントローラーのクローズ時に位置情報のストリームをキャンセルします。
//
class LocationController extends GetxController {
// Reactive variable to hold the current position
Rx<Position?> currentPosition = Rx<Position?>(null);
// 現在の位置情報を保持するReactive変数です。Rx<Position?>型で宣言されています。
final locationMarkerPositionStreamController = StreamController<LocationMarkerPosition?>.broadcast();
// Subscription to the position stream
StreamSubscription<Position>? positionStream;
// 位置情報のストリームを保持する変数です。StreamSubscription<Position>型で宣言されています。
LatLng? lastValidLocation;
DateTime lastGPSDataReceivedTime = DateTime.now(); // 最後にGPSデータを受け取った時刻
bool gpsDebugMode = true;
/*
// GPSシミュレーション用のメソッドを追加
void setSimulationMode(bool value) {
isSimulationMode = value;
}
// ====== Akira , GPS信号強度をシミュレート ==== ここから
//
//===== Akira Added 2024-4-9 start
// GPSシミュレーション用の変数を追加 ===> 本番では false にする。
bool isSimulationMode = false;
// GPS信号強度をシミュレートするための変数
final Rx<String> _simulatedSignalStrength = Rx<String>('high');
// GPS信号強度をシミュレートするための関数
void setSimulatedSignalStrength(String strength) {
if( strength!='real') {
isSimulationMode = true;
_simulatedSignalStrength.value = strength;
latestSignalStrength.value = strength;
}else{
isSimulationMode = false;
_simulatedSignalStrength.value = strength;
}
}
// シミュレートされた信号強度を取得するための関数
String getSimulatedSignalStrength() {
//debugPrint("strength : ${_simulatedSignalStrength.value}");
return _simulatedSignalStrength.value;
}
*/
//
// ====== Akira , GPS信号強度をシミュレート ==== ここまで
// GPS信号が弱い場合のフラグ. 本番では、false,high にする。
bool isGpsSignalWeak = false;
RxString latestSignalStrength = 'high'.obs;
//final _latestSignalStrength = 'low'.obs; // 初期値を設定
//String get latestSignalStrength => _latestSignalStrength.value;
Stream<String> get gpsSignalStrengthStream => latestSignalStrength.stream;
bool isRunningBackgroundGPS=false;
int activeEngineCount = 0;
// GPS信号の強弱を判断するメソッドを追加. 10m 以内強、30m以内中、それ以上
//
String getGpsSignalStrength(Position? position) {
if (isSimulationMode.value) {
return getSimulatedSignalStrength();
}
if (position == null) {
//gpsDebugMode ? debugPrint("getGpsSignalStrength position is null.") : null;
latestSignalStrength.value = "low";
isGpsSignalWeak = true;
return 'low';
}
final accuracy = position.accuracy;
//gpsDebugMode ? debugPrint("getGpsSignalStrength : ${accuracy}") : null;
/*
if(isSimulationMode){
return _simulatedSignalStrength.value; // GPS信号強度シミュレーション
}else {
*/
if (accuracy <= 10) {
latestSignalStrength.value = "high";
isGpsSignalWeak = false;
return 'high';
} else if (accuracy <= 50) {
latestSignalStrength.value = "medium";
isGpsSignalWeak = false;
return 'medium';
} else {
latestSignalStrength.value = "low";
isGpsSignalWeak = true;
return 'low';
}
// }
}
// 現在位置を調整するメソッドを追加
LatLng? adjustCurrentLocation(Position? position) {
if (position == null) { // positionがnullなら、lastValidLocationを使用する。
if( lastValidLocation!=null ) {
debugPrint("== 現在位置なし。最後の位置を使用 ==");
//debugPrint("=== adjustCurrentLocation (Position:Null and using LastValidLocation ${lastValidLocation})===");
return LatLng(lastValidLocation!.latitude, lastValidLocation!.longitude);
}else {
debugPrint("== 現在位置なし。最後の位置も無し ==");
//print("=== adjustCurrentLocation (Position:Null and No LastValidLocation ... )===");
return null;
}
//return lastValidLocation ?? LatLng(0, 0);
}
final signalStrength = getGpsSignalStrength(position);
if (signalStrength == 'high' || signalStrength == 'medium') {
debugPrint("== 信号強度 ${signalStrength} ==> 最新位置を使用 ==");
//debugPrint("=== adjustCurrentLocation (Position:Get and return Valid location:${position} ... )===");
lastValidLocation = LatLng(position.latitude, position.longitude);
}else{
debugPrint("== 信号強度 ${signalStrength} ==> 最後の位置を使用 ==");
}
return lastValidLocation ?? LatLng(lastValidLocation!.latitude, lastValidLocation!.longitude);
}
//===== Akira Added 2024-4-9 end
//final locationMarkerPositionStreamController =
// StreamController<LocationMarkerPosition?>.broadcast();
// 位置マーカーの位置情報を送信するためのStreamControllerです。
// StreamController<LocationMarkerPosition?>型で宣言されています。
bool isStreamPaused = false; // 位置情報のストリームが一時停止中かどうかを示すフラグです。bool型で宣言されています。
// 位置マーカーの位置情報のストリームを取得するゲッター関数です。
// locationMarkerPositionStreamController.streamを返します。
//
Stream<LocationMarkerPosition?> get locationMarkerPositionStream =>
locationMarkerPositionStreamController.stream;
// コントローラーの初期化時に呼び出されるライフサイクルメソッドです。
// startPositionStreamメソッドを呼び出して、位置情報のストリームを開始します。
//
@override
void onInit() {
super.onInit();
// Start listening to location updates when the controller is initialized
_initLocationService();
}
Future<void> _initLocationService() async {
try {
bool serviceEnabled;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
startPositionStream();
debugPrint("Started startPositionStream");
} catch( e ){
print('Error initializing location service: $e');
}
}
// 位置情報のストリームを開始するメソッドです。
// 位置情報サービスが有効か確認し、無効な場合はダイアログを表示します。
// 位置情報の権限を確認し、必要な権限がない場合は権限をリクエストします。
// 既存の位置情報のストリームをキャンセルします。
// Geolocator.getPositionStreamを使用して、新しい位置情報のストリームを開始します。
// ストリームから受信した位置情報をlocationMarkerPositionStreamControllerに追加します。
// エラーが発生した場合は、locationMarkerPositionStreamControllerにエラーを追加します。
// ストリームが一時停止中の場合は、ストリームを再開します。
//
// 2024-4-8 Akira : See 2809
// stopPositionStreamメソッドを追加して、既存のストリームをキャンセルするようにしました。また、ストリームが完了したらnullに設定し、エラー発生時にストリームをキャンセルするようにしました。
//
void startPositionStream() {
positionStream = Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 5, //10, 10mから5mに変更
),
).listen((Position position) {
currentPosition.value = position;
//debugPrint("== startPositionStream: ${position} ==");
locationMarkerPositionStreamController.add(
LocationMarkerPosition(
latitude: position.latitude,
longitude: position.longitude,
accuracy: position.accuracy,
),
);
},
onError: (error) {
debugPrint('Error in Geolocator stream: $error');
locationMarkerPositionStreamController.addError(error);
},
);
}
void startPositionStream_old() async {
// Check for location service and permissions before starting the stream
// 位置情報サービスの有効性をチェックし、無効な場合はエラーハンドリングを行います。
//
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
Get.snackbar('位置情報サービスが無効です', '設定から位置情報サービスを有効にしてください');
return;
}
//await PermissionController.checkAndRequestPermissions();
// 位置情報の設定を行います。z11
// Set up the location options
const locationOptions =
LocationSettings(accuracy: LocationAccuracy.medium, distanceFilter: 0);
// 既存の位置情報のストリームをキャンセルします。
await positionStream?.cancel();
// 新しい位置情報のストリームを開始します。
//
positionStream = Geolocator.getPositionStream(locationSettings: locationOptions).listen(
(Position? position) {
//gpsDebugMode ? debugPrint("Position = ${position}"):null;
final signalStrength = getGpsSignalStrength(position);
if (signalStrength == 'low') {
isGpsSignalWeak = true;
//gpsDebugMode ? debugPrint("LocationController.getPositionStream : isGpsSignalWeak = ${isGpsSignalWeak}"):null;
} else {
isGpsSignalWeak = false;
//gpsDebugMode ? debugPrint("LocationController.getPositionStream : isGpsSignalWeak = ${isGpsSignalWeak}"):null;
}
final DestinationController destinationController = Get.find<DestinationController>();
// ロゲ開始前、終了後、GPS=low の場合は更新しない。
//
if (isGpsSignalWeak == false) {
//if (destinationController.isInRog.value && isGpsSignalWeak == false) {
final adjustedLocation = adjustCurrentLocation(position);
if (adjustedLocation != null) {
final locationMarkerPosition = LocationMarkerPosition(
latitude: adjustedLocation.latitude,
longitude: adjustedLocation.longitude,
accuracy: position?.accuracy ?? 0,
);
handleLocationUpdate(locationMarkerPosition);
//locationMarkerPositionStreamController.add(locationMarkerPosition); // 位置データ送信
} else {
// 位置情報が取得できなかった場合、
// locationMarkerPositionStreamControllerにnullを追加します。
locationMarkerPositionStreamController.add(null); // null 送信?
//forceUpdateLocation(Position? position);
}
//}else{
// debugPrint("GPS処理対象外");
}
},
onError: (e) {
// エラーが発生した場合、locationMarkerPositionStreamControllerにエラーを追加します。
locationMarkerPositionStreamController.addError(e);
},
onDone: () {
positionStream = null; // ストリームが完了したらnullに設定
},
cancelOnError: true // エラー発生時にストリームをキャンセル
);
// Resume stream if it was paused previously
// ストリームが一時停止中の場合、ストリームを再開します。
//
if (isStreamPaused) {
isStreamPaused = false;
positionStream!.resume();
}
}
// Method to stop the position stream
// 位置情報のストリームを停止するメソッドです。
// positionStreamが存在する場合、ストリームを一時停止します。
// isStreamPausedフラグをtrueに設定します。
//
void stopPositionStream() async {
if (positionStream != null) {
// updated Akira 2024-4-8
await positionStream!.cancel();
positionStream = null;
//positionStream!.pause();
//isStreamPaused = true;
}
}
// Method to resume the position stream
// 位置情報のストリームを再開するメソッドです。
// positionStreamが存在し、ストリームが一時停止中の場合、ストリームを再開します。
// isStreamPausedフラグをfalseに設定します。
//
void resumePositionStream() {
if (positionStream != null && isStreamPaused) {
positionStream!.resume();
isStreamPaused = false;
}
}
void handleLocationUpdate(LocationMarkerPosition? position) async {
//debugPrint("locationController.handleLocationUpdate");
try {
if (position != null) {
double currentLat = position.latitude;
double currentLon = position.longitude;
//debugPrint("Flutter: Received GPS signal. Latitude: $currentLat, Longitude: $currentLon");
//debugPrint("position = ${position}");
/*
currentPosition.value = position;
final locationMarkerPosition = LocationMarkerPosition(
latitude: position.latitude,
longitude: position.longitude,
accuracy: position.accuracy,
);
*/
lastGPSDataReceivedTime = DateTime.now(); // 最後にGPS信号を受け取った時刻
locationMarkerPositionStreamController.add(position);
}else{
gpsDebugMode ? debugPrint("Flutter: No GPS signal received."):null;
}
} catch( e ) {
debugPrint("Flutter: Error in handleLocationUpdate: $e");
}
}
// このメソッドは、現在の位置情報を locationMarkerPositionStreamController に送信します。
//
void forceUpdateLocation(Position? position) {
if (position != null) {
final adjustedLocation = adjustCurrentLocation(position);
if (adjustedLocation != null) {
final locationMarkerPosition = LocationMarkerPosition(
latitude: adjustedLocation.latitude,
longitude: adjustedLocation.longitude,
accuracy: position.accuracy,
);
locationMarkerPositionStreamController.add(locationMarkerPosition);
}
}
}
// コントローラーのクローズ時に呼び出されるライフサイクルメソッドです。
// positionStreamをキャンセルします。
//
@override
void onClose() {
// Cancel the position stream subscription when the controller is closed
positionStream?.cancel();
super.onClose();
}
// シミュレーションモードのフラグ
RxBool isSimulationMode = RxBool(false);
// シミュレーションモードを切り替えるための関数
void setSimulationMode(bool value) {
isSimulationMode.value = value;
}
// GPS信号強度をシミュレートするための変数
final Rx<String> _simulatedSignalStrength = Rx<String>('high');
// GPS信号強度をシミュレートするための関数
void setSimulatedSignalStrength(String strength) {
_simulatedSignalStrength.value = strength;
}
// シミュレートされた信号強度を取得するための関数
String getSimulatedSignalStrength() {
return _simulatedSignalStrength.value;
}
}