未確認だが問題回避のためプッシュ

This commit is contained in:
2024-04-09 01:58:25 +09:00
parent dd9dd0d087
commit 1b4073f690
59 changed files with 2384 additions and 410 deletions

View File

@ -33,6 +33,8 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:geolocator/geolocator.dart';
// 目的地に関連する状態管理とロジックを担当するクラスです。
//
class DestinationController extends GetxController {
@ -44,6 +46,8 @@ class DestinationController extends GetxController {
List<Destination> destinations = <Destination>[].obs; // 目的地のリストを保持するObservable変数です。
double currentLat = 0.0; // 現在の緯度と経度を保持する変数です。
double currentLon = 0.0;
double lastValidLat = 0.0; // 最後に中・強信号で拾ったGPS位置。ロゲ開始を屋内でやったら 0 のままなので、屋外で行うこと。
double lastValidLon = 0.0;
DateTime lastGPSCollectedTime = DateTime.now(); // 最後にGPSデータが収集された時刻を保持する変数です。
bool shouldShowBottomSheet = true; // ボトムシートを表示すべきかどうかを示すフラグです。
@ -75,6 +79,7 @@ class DestinationController extends GetxController {
var travelMode = 0.obs; // 移動モードを保持するReactive変数です。
bool skipGps = false; // GPSをスキップするかどうかを示すフラグです。
bool okToUseGPS = false; // 最新のGPS情報を使用して良いかを示すフラグ。
Map<String, dynamic> matrix = {}; // 行列データを保持する変数です。
@ -199,6 +204,10 @@ class DestinationController extends GetxController {
// 目的地がデータベースに存在しない場合は、新しい目的地としてデータベースに挿入します。
// 目的地に応じて、チェックイン、ゴール、買い物ポイントの処理を行います。
//
// 2024-4-8 akira: GPS信号が弱い場合でも、最後に取得した位置情報を使用してチェックインやゴールの処理を続行できるようになります。また、チェックインやゴールの処理では、GPS信号の精度チェックを緩和することで、GPS信号が弱い場合でもボタンを押せるようになります。
//
// 要検討:エラーが発生した場合のエラーハンドリングを追加し、適切なメッセージを表示することを検討してください。
//
Future<void> startTimer(Destination d, double distance) async {
//print("=== passed dest is ${d.location_id} ${d.checkedin} ====");
skipGps = true;
@ -240,6 +249,31 @@ class DestinationController extends GetxController {
// comment out by Akira, 2024-4-5
// skipGps = false;
// return;
// GPS信号が弱い場合、最後に取得した高いまたは中程度の位置情報を使用
if (okToUseGPS) {
double lastValidDistance = Geolocator.distanceBetween(
lastValidLat, lastValidLon,
d.lat!, d.lon!
);
/*
double lastValidDistance = distance.as(
LengthUnit.Meter,
LatLng(lastValidLat, lastValidLon),
LatLng(d.lat!, d.lon!),
);
*/
if (checkinRadious >= lastValidDistance || checkinRadious == -1) {
indexController.currentDestinationFeature.clear();
indexController.currentDestinationFeature.add(d);
} else {
skipGps = false;
return;
}
} else {
skipGps = false;
return;
}
}
if (isPhotoShoot.value == true) {
@ -407,10 +441,10 @@ class DestinationController extends GetxController {
context: Get.context!,
isScrollControlled: true,
builder: ((context) => CameraPage(
buyPointPhoto: true,
destination: d,
dbDest: ds.first,
))).whenComplete(() {
destination: d,
buyPointPhoto: true,
dbDest: ds.first,
))).whenComplete(() {
shouldShowBottomSheet = true;
skipGps = false;
rogainingCounted.value = true;
@ -641,13 +675,14 @@ class DestinationController extends GetxController {
});
} else {
Get.snackbar(
"始まっていません",
"ロゲ開始ボタンをタップして、ロゲイニングを始める必要があります",
icon: const Icon(Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 3),
backgroundColor: Colors.yellow,
);
"ロゲが始まっていません",
"ロゲ開始ボタンをタップして、ロゲイニングを始める必要があります",
icon: const Icon(
Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 3),
backgroundColor: Colors.yellow,
);
}
}
}
@ -680,6 +715,9 @@ class DestinationController extends GetxController {
// 目的地のリストを走査し、現在位置がチェックイン半径内にある場合は、チェックインの処理を行います。
// GPSデータの送信を開始します。
//
// 2024-4-8 Akira : See 2809
// checkForCheckinメソッドの再帰呼び出しをunawaitedで囲んで、非同期処理の結果を待たずに先に進むようにしました。また、再帰呼び出しの前に一定時間待機するようにしました。
//
Future<void> checkForCheckin() async {
//print("--- Start of checkForCheckin function ---");
dbService.updateDatabase();
@ -705,15 +743,16 @@ class DestinationController extends GetxController {
});
if (gps_push_started == false) {
pushGPStoServer();
unawaited( pushGPStoServer() );
}
//print("--- 123 ---- $skip_gps----");
} catch (e) {
//print("An error occurred: $e");
await checkForCheckin();
print("An error occurred: $e");
// await checkForCheckin();
} finally {
await Future.delayed(const Duration(seconds: 5)); // 一定時間待機してから再帰呼び出し
//print("--- End of checkForCheckin function, calling recursively ---");
await checkForCheckin();
unawaited( checkForCheckin() );
}
}
@ -772,6 +811,8 @@ class DestinationController extends GetxController {
// 買い物ポイントを作成する関数です。 指定された目的地に対して買い物ポイントの処理を行います。
//
// 買い物ポイントの作成に失敗した場合のエラーハンドリングを追加することを検討してください。
//
Future<void> makeBuyPoint(Destination destination, String imageurl) async {
DatabaseHelper db = DatabaseHelper.instance;
await db.updateBuyPoint(destination, imageurl);
@ -804,6 +845,8 @@ class DestinationController extends GetxController {
// チェックインを行う関数です。 指定された目的地に対してチェックインの処理を行います。
//
// 要検討:チェックインのリクエストが失敗した場合のエラーハンドリングを追加することをお勧めします。
//
Future<void> makeCheckin(
Destination destination, bool action, String imageurl) async {
// print("~~~~ calling checkin function ~~~~");
@ -873,6 +916,9 @@ class DestinationController extends GetxController {
@override
void onInit() async {
super.onInit();
// 要検討:エラーメッセージを表示するなどの適切な処理を追加することを検討してください。
//
locationController.locationMarkerPositionStream.listen(
(locationMarkerPosition) {
if (locationMarkerPosition != null) {
@ -896,9 +942,49 @@ class DestinationController extends GetxController {
// 現在位置とスタート地点との距離を計算します。
// 現在位置と前回の位置情報との距離と時間差を確認し、一定の条件を満たす場合はGPSデータをデータベースに追加します。
//
// 要検討GPSデータの追加に失敗した場合のエラーハンドリングを追加することをお勧めします。
//
void handleLocationUpdate(LocationMarkerPosition? position) async {
try {
if (position != null) {
final DestinationController destinationController = Get.find<DestinationController>();
final signalStrength = destinationController.getGpsSignalStrength();
okToUseGPS = false;
double prevLat = lastValidLat; // 一つ前の位置情報を記録
double prevLon = lastValidLon;
if (position!=null && (signalStrength == 'high' || signalStrength == 'medium')) {
// 信号強度が高いまたは中程度の場合、現在の位置情報を更新
currentLat = position.latitude;
currentLon = position.longitude;
lastValidLat = position.latitude;
lastValidLon = position.longitude;
okToUseGPS = true;
} else {
// 信号強度が低い場合、最後に取得した高いまたは中程度の位置情報を使用
// 但し、最初から高精度のものがない場合、どうするか?
//
if (lastValidLat != 0.0 && lastValidLon != 0.0) {
currentLat = lastValidLat;
currentLon = lastValidLon;
okToUseGPS = true;
} else {
// GPSの届く場所に行って、信号を拾ってください。とメッセージを出す。
position = null;
print("GPSの届く場所に行って、信号を拾ってください。");
Get.snackbar(
"GPS信号を正確に拾えていません",
"空が大きく見えるところへ行ってGPS信号を拾ってください。",
icon: const Icon(
Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 3),
backgroundColor: Colors.yellow,
);
}
}
if (okToUseGPS && position!=null) {
// スタート位置から150m離れたら、ready_for_goal
if (distanceToStart() >= 150) {
ready_for_goal = true;
}
@ -907,10 +993,11 @@ class DestinationController extends GetxController {
double distanceToDest = distance.as(
LengthUnit.Meter,
LatLng(position.latitude, position.longitude),
LatLng(currentLat, currentLon));
LatLng(prevLat, prevLon)
);
Duration difference =
lastGPSCollectedTime.difference(DateTime.now()).abs();
Duration difference = lastGPSCollectedTime.difference(DateTime.now()).abs();
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過普通に歩くスピード
if (difference.inSeconds >= 10 || distanceToDest >= 10) {
// print(
// "^^^^^^^^ GPS data collected ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}, ^^^ ${position.latitude}, ${position.longitude}");
@ -931,10 +1018,10 @@ class DestinationController extends GetxController {
currentLon = position.longitude;
}
*/
if (position != null) {
if (okToUseGPS) {
// 位置情報が取得できた場合、精度に関わらず最後の位置情報を更新
currentLat = position.latitude;
currentLon = position.longitude;
//currentLat = position.latitude;
//currentLon = position.longitude;
}
}
}
@ -1020,25 +1107,32 @@ class DestinationController extends GetxController {
if (token != null && token.isNotEmpty) {
await indexController.loadUserDetailsForToken(token);
fixMapBound(token);
return;
}else {
Get.toNamed(AppPages.LOGIN)!.then((value) {
if (indexController.currentUser.isNotEmpty) {
final tk = indexController.currentUser[0]["token"];
fixMapBound(tk);
} else {
Get.toNamed(AppPages.TRAVEL);
PerfectureService.getSubExt("9").then((value) {
if (value != null) {
LatLngBounds bnds = LatLngBounds(
LatLng(value[1], value[0]), LatLng(value[3], value[2]));
indexController.mapController
.fitBounds(bnds); //.centerZoomFitBounds(bnds);
}
});
}
});
}
Get.toNamed(AppPages.LOGIN)!.then((value) {
if (indexController.currentUser.isNotEmpty) {
final tk = indexController.currentUser[0]["token"];
fixMapBound(tk);
} else {
Get.toNamed(AppPages.TRAVEL);
PerfectureService.getSubExt("9").then((value) {
if (value != null) {
LatLngBounds bnds = LatLngBounds(
LatLng(value[1], value[0]), LatLng(value[3], value[2]));
indexController.mapController
.fitBounds(bnds); //.centerZoomFitBounds(bnds);
}
});
// 地図のイベントリスナーを設定
indexController.mapController.mapEventStream.listen((MapEvent mapEvent) {
if (mapEvent is MapEventMoveEnd) {
indexController.loadLocationsBound();
}
});
super.onReady();
}
@ -1106,7 +1200,7 @@ class DestinationController extends GetxController {
print("center is ${currentLon}, ${currentLon}");
return true;
}());
// Akira
// Akira ... 状況によって呼ぶか呼ばないか
if (currentLat != 0 || currentLon != 0) {
indexController.mapController.move(LatLng(currentLat, currentLon), 17.0);
}
@ -1236,22 +1330,36 @@ class DestinationController extends GetxController {
// 目的地の選択状態を切り替える関数です。
//
void toggleSelection(Destination dest) async {
DatabaseHelper db = DatabaseHelper.instance;
await db.toggleSelecttion(dest);
destinations.clear();
db.getDestinations().then((value) {
destinationCount.value = 0;
currentSelectedDestinations.clear();
for (Destination d in value) {
//print("------ destination controller populating destination-------- ${d.checkedin}-------- :::::");
//print("-----populated----- ${d.toMap()}");
if (d.selected!) {
currentSelectedDestinations.add(d);
try {
DatabaseHelper db = DatabaseHelper.instance;
await db.toggleSelecttion(dest);
destinations.clear();
db.getDestinations().then((value) {
destinationCount.value = 0;
currentSelectedDestinations.clear();
for (Destination d in value) {
//print("------ destination controller populating destination-------- ${d.checkedin}-------- :::::");
//print("-----populated----- ${d.toMap()}");
if (d.selected!) {
currentSelectedDestinations.add(d);
}
destinations.add(d);
}
destinations.add(d);
}
destinationCount.value = destinations.length;
});
destinationCount.value = destinations.length;
});
} catch( e ){
print('Error in toggleSelection: $e');
Get.snackbar(
"画面切り替えでエラー",
"画面の切り替えができませんでした",
icon: const Icon(
Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 3),
backgroundColor: Colors.yellow,
);
}
}
// ダイアログを表示する関数です。

View File

@ -1,252 +0,0 @@
// import 'package:flutter/material.dart';
// import 'package:geolocator/geolocator.dart';
// import 'package:get/get.dart';
// import 'package:latlong2/latlong.dart';
// import 'package:rogapp/pages/destination/destination_controller.dart';
// import 'package:rogapp/pages/destination_map/destination_map_page.dart';
// import 'package:rogapp/pages/drawer/drawer_page.dart';
// import 'package:rogapp/pages/index/index_controller.dart';
// import 'package:rogapp/routes/app_pages.dart';
// import 'package:rogapp/widgets/destination_widget.dart';
// class XDestnationPage extends StatelessWidget {
// XDestnationPage({Key? key}) : super(key: key);
// final DestinationController destinationController =
// Get.find<DestinationController>();
// final IndexController indexController = Get.find<IndexController>();
// final List<int> _items = List<int>.generate(50, (int index) => index);
// Future<void> showCurrentPosition() async {
// LocationPermission permission = await Geolocator.checkPermission();
// if (permission != LocationPermission.whileInUse ||
// permission != LocationPermission.always) {
// permission = await Geolocator.requestPermission();
// }
// Position position = await Geolocator.getCurrentPosition(
// desiredAccuracy: LocationAccuracy.high,
// forceAndroidLocationManager: true);
// indexController.rogMapController
// .move(LatLng(position.latitude, position.longitude), 14);
// }
// Image getImage(int index) {
// if (destinationController.destinations[index].photos == null ||
// destinationController.destinations[index].photos == "") {
// return const Image(image: AssetImage('assets/images/empty_image.png'));
// } else {
// return Image(
// image:
// NetworkImage(destinationController.destinations[index].photos!));
// }
// }
// Widget getRoutingImage(int route) {
// switch (route) {
// case 0:
// return const Image(
// image: AssetImage('assets/images/p4_9_man.png'),
// width: 35.0,
// );
// case 1:
// return const Image(
// image: AssetImage('assets/images/p4_8_car.png'),
// width: 35.0,
// );
// case 2:
// return const Image(
// image: AssetImage('assets/images/p4_10_train.png'),
// width: 35.0,
// );
// default:
// return const Image(
// image: AssetImage('assets/images/p4_9_man.png'),
// width: 35.0,
// );
// }
// }
// @override
// Widget build(BuildContext context) {
// return WillPopScope(
// onWillPop: () async {
// indexController.switchPage(AppPages.INITIAL);
// return false;
// },
// child: Scaffold(
// drawer: DrawerPage(),
// bottomNavigationBar: BottomAppBar(
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: <Widget>[
// Padding(
// padding: const EdgeInsets.only(left: 13.0),
// child: InkWell(
// child: Obx((() => getRoutingImage(
// destinationController.travelMode.value))),
// onTap: () {
// Get.bottomSheet(
// Obx(
// () => ListView(
// children: [
// Padding(
// padding: const EdgeInsets.only(
// top: 30.0, bottom: 30),
// child: Center(
// child: Text(
// "select_travel_mode".tr,
// style: const TextStyle(
// fontSize: 22.0,
// color: Colors.red,
// fontWeight: FontWeight.bold),
// ),
// ),
// ),
// ListTile(
// selected:
// destinationController.travelMode.value ==
// 0
// ? true
// : false,
// selectedTileColor: Colors.amber.shade200,
// leading: const Image(
// image: AssetImage(
// 'assets/images/p4_9_man.png'),
// ),
// title: Text("walking".tr),
// onTap: () {
// destinationController.travelMode.value = 0;
// destinationController
// .populateDestinations();
// Get.back();
// },
// ),
// ListTile(
// selected:
// destinationController.travelMode.value ==
// 1
// ? true
// : false,
// selectedTileColor: Colors.amber.shade200,
// leading: const Image(
// image: AssetImage(
// 'assets/images/p4_8_car.png'),
// ),
// title: Text("driving".tr),
// onTap: () {
// destinationController.travelMode.value = 1;
// destinationController
// .populateDestinations();
// Get.back();
// },
// ),
// // ListTile(
// // selected: destinationController.travelMode == 2 ? true : false,
// // selectedTileColor: Colors.amber.shade200,
// // leading: Image(image: AssetImage('assets/images/p4_10_train.png'),),
// // title: Text("transit".tr),
// // onTap:(){
// // destinationController.travelMode.value = 2;
// // destinationController.PopulateDestinations();
// // Get.back();
// // },
// // ),
// ],
// ),
// ),
// isScrollControlled: false,
// backgroundColor: Colors.white,
// );
// //destinationController.PopulateDestinations();
// }),
// ),
// IconButton(
// icon: const Icon(
// Icons.travel_explore,
// size: 35,
// ),
// onPressed: () {
// indexController.switchPage(AppPages.INITIAL);
// }),
// ],
// ),
// ),
// floatingActionButton: FloatingActionButton(
// onPressed: () {
// //print("######");
// indexController.toggleDestinationMode();
// },
// tooltip: 'Increment',
// elevation: 4.0,
// child: Obx(() => indexController.desinationMode.value == 1
// ? const Image(image: AssetImage('assets/images/list2.png'))
// : const Image(image: AssetImage('assets/images/map.png'))),
// ),
// floatingActionButtonLocation:
// FloatingActionButtonLocation.centerDocked,
// appBar: AppBar(
// automaticallyImplyLeading: true,
// title: Text("app_title".tr),
// actions: [
// InkWell(
// onTap: () {
// Get.toNamed(AppPages.CAMERA_PAGE);
// },
// child: destinationController.isInRog.value == true
// ? Image.asset(
// "assets/images/basic-walking.gif",
// height: 10.0,
// )
// : destinationController.isAtGoal.value == true
// ? IconButton(
// onPressed: () {
// Get.toNamed(AppPages.CAMERA_PAGE);
// },
// icon: const Icon(Icons.assistant_photo),
// )
// : IconButton(
// onPressed: () {
// Get.toNamed(AppPages.CAMERA_PAGE);
// },
// icon: const Icon(Icons.accessibility),
// ),
// ),
// // Obx(() =>
// // Text(indexController.connectionStatusName.value)
// // ),
// Obx(
// () => ToggleButtons(
// disabledColor: Colors.grey.shade200,
// selectedColor: Colors.red,
// onPressed: (int index) {
// destinationController.isGpsSelected.value =
// !destinationController.isGpsSelected.value;
// if (destinationController.isGpsSelected.value) {
// destinationController.chekcs = 0;
// destinationController.skipGps = false;
// //destinationController.resetRogaining();
// }
// },
// isSelected: [destinationController.isGpsSelected.value],
// children: const <Widget>[
// Icon(
// Icons.explore,
// size: 35.0,
// )
// ],
// ),
// ),
// // IconButton(onPressed: (){
// // showCurrentPosition();
// // },
// // icon: Icon(Icons.location_on_outlined))
// ],
// ),
// body: Obx(() => indexController.desinationMode.value == 0
// ? DestinationWidget()
// : DestinationMapPage())),
// );
// }
// }