2 Commits

9 changed files with 185 additions and 65 deletions

View File

@ -18,7 +18,8 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:rogapp/services/device_info_service.dart';
import 'package:rogapp/services/error_service.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:async';
//import 'dart:async';
//import 'package:get/get.dart';
Map<String, dynamic> deviceInfo = {};
@ -69,9 +70,13 @@ void main() async {
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
Get.log('Flutter error: ${details.exception}');
Get.log('Stack trace: ${details.stack}');
ErrorService.reportError(details.exception, details.stack ?? StackTrace.current, deviceInfo);
};
//Get.put(LocationController());
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
runZonedGuarded(() {
@ -185,8 +190,8 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
void didChangeAppLifecycleState(AppLifecycleState state) {
LocationController locationController = Get.find<LocationController>();
DestinationController destinationController =
Get.find<DestinationController>();
//DestinationController destinationController =
// Get.find<DestinationController>();
switch (state) {
case AppLifecycleState.resumed:
locationController.resumePositionStream();

View File

@ -46,7 +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 lastValidLat = 0.0; // 最後に中・強信号で拾ったGPS位置。
// ロゲ開始を屋内でやったら 0 のままなので、屋外で行うこと。
double lastValidLon = 0.0;
DateTime lastGPSCollectedTime = DateTime.now(); // 最後にGPSデータが収集された時刻を保持する変数です。
@ -93,6 +94,7 @@ class DestinationController extends GetxController {
int chekcs = 0; // チェックポイントの数を保持する変数です。
var rogainingCounted = false.obs; // ロゲイニングがカウントされたかどうかを示すReactive変数です。
/*
//==== Akira .. GPS信号シミュレーション用 ===== ここから、2024-4-5
//
@ -106,6 +108,11 @@ class DestinationController extends GetxController {
isSimulationMode.value = value;
}
// 現在位置の取得メソッドを追加
LatLng getCurrentLocation() {
return LatLng(lastValidLat, lastValidLon);
}
//
// GPS信号の強弱を判断するメソッドを追加します。
//
@ -129,6 +136,7 @@ class DestinationController extends GetxController {
//
//==== Akira .. GPS信号シミュレーション用 ======= ここまで
*/
// 日時をフォーマットされた文字列に変換する関数です。
//
@ -919,6 +927,9 @@ class DestinationController extends GetxController {
// 要検討:エラーメッセージを表示するなどの適切な処理を追加することを検討してください。
//
// locationController からデバイスの受け取るGPS情報を取得し、
// handleLocationUpdate を呼び出している。
//
locationController.locationMarkerPositionStream.listen(
(locationMarkerPosition) {
if (locationMarkerPosition != null) {
@ -947,18 +958,17 @@ class DestinationController extends GetxController {
void handleLocationUpdate(LocationMarkerPosition? position) async {
try {
final DestinationController destinationController = Get.find<DestinationController>();
final signalStrength = destinationController.getGpsSignalStrength();
okToUseGPS = false;
double prevLat = lastValidLat; // 一つ前の位置情報を記録
double prevLon = lastValidLon;
//final signalStrength = locationController.getGpsSignalStrength();
if (position!=null && (signalStrength == 'high' || signalStrength == 'medium')) {
// 信号強度が高いまたは中程度の場合、現在の位置情報を更新
okToUseGPS = false;
double prevLat = currentLat; // 直前の位置
double prevLon = currentLon;
if (position!=null){
currentLat = position.latitude;
currentLon = position.longitude;
lastValidLat = position.latitude;
lastValidLon = position.longitude;
okToUseGPS = true;
} else {
// 信号強度が低い場合、最後に取得した高いまたは中程度の位置情報を使用
// 但し、最初から高精度のものがない場合、どうするか?
@ -1048,6 +1058,8 @@ class DestinationController extends GetxController {
return distanceToDest;
}
//final currentLocation = getCurrentLocation(); // GPS信号中以上での現在位置
Destination des = festuretoDestination(gfs);
//print("=== gfs == ${des.toMap()}");
@ -1055,6 +1067,7 @@ class DestinationController extends GetxController {
var distance = const Distance();
distanceToDest = distance.as(LengthUnit.Meter,
LatLng(currentLat,currentLon), LatLng(des.lat!, des.lon!));
// LatLng(currentLat, currentLon), LatLng(des.lat!, des.lon!));
//print("==== dist==${distanceToDest}");
return distanceToDest;
}
@ -1197,7 +1210,7 @@ class DestinationController extends GetxController {
//
void centerMapToCurrentLocation() {
assert(() {
print("center is ${currentLon}, ${currentLon}");
print("center is ${currentLat}, ${currentLon}");
return true;
}());
// Akira ... 状況によって呼ぶか呼ばないか

View File

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
import 'package:flutter_map_marker_popup/flutter_map_marker_popup.dart';
//import 'package:flutter_map_marker_popup/flutter_map_marker_popup.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
@ -22,7 +22,7 @@ class DestinationMapPage extends StatelessWidget {
final DestinationController destinationController =
Get.find<DestinationController>();
StreamSubscription? subscription;
final PopupController _popupLayerController = PopupController();
//final PopupController _popupLayerController = PopupController();
List<LatLng>? getPoints() {
//print("##### --- route point ${indexController.routePoints.length}");
@ -38,7 +38,7 @@ class DestinationMapPage extends StatelessWidget {
//
List<Marker>? getMarkers() {
List<Marker> pts = [];
int index = -1;
//int index = -1;
for (int i = 0; i < destinationController.destinations.length; i++) {
Destination d = destinationController.destinations[i];
//print("^^^^ $d ^^^^");
@ -151,10 +151,10 @@ class DestinationMapPage extends StatelessWidget {
bounds: indexController.currentBound.isNotEmpty
? indexController.currentBound[0]
: LatLngBounds.fromPoints([
LatLng(35.03999881162295, 136.40587119778962),
LatLng(36.642756778706904, 137.95226720406063)
const LatLng(35.03999881162295, 136.40587119778962),
const LatLng(36.642756778706904, 137.95226720406063)
]),
zoom: 1,
initialZoom: 1,
maxZoom: 42,
interactiveFlags: InteractiveFlag.pinchZoom | InteractiveFlag.drag,
),

View File

@ -47,7 +47,7 @@ class IndexController extends GetxController {
//final mapControllerReadyStream = Stream<bool>.value(false); // MapControllerの初期化状態を通知するためのストリーム
MapController mapController = MapController();
//MapController rogMapController = MapController();
MapController rogMapController = MapController();
String? userToken;
@ -439,9 +439,8 @@ class IndexController extends GetxController {
print("Error in loadLocationsBound: $e");
// エラーが発生した場合のリトライ処理や適切なエラーメッセージの表示を行う
// 例えば、一定時間後に再度loadLocationsBound()を呼び出すなど
}
}));
}

View File

@ -1,14 +1,9 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rogapp/model/destination.dart';
import 'package:rogapp/model/gps_data.dart';
import 'package:rogapp/pages/destination/destination_controller.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/services/DatabaseService.dart';
import 'package:rogapp/utils/database_gps.dart';
import 'package:rogapp/utils/database_helper.dart';
import 'package:rogapp/widgets/list_widget.dart';
import 'package:rogapp/widgets/map_widget.dart';
import 'package:rogapp/utils/location_controller.dart';
@ -43,8 +38,8 @@ class IndexPage extends GetView<IndexController> {
//
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
return PopScope(
canPop: false,
child: Scaffold(
//
// Scaffoldウィジェットを使用して、アプリのメインページのレイアウトを構築しています。
@ -109,8 +104,7 @@ class IndexPage extends GetView<IndexController> {
// タップすることでGPS信号の強弱をシミュレーションできるようにする
// Akira 2024-4-5
//
Obx(
() => destinationController.isSimulationMode.value
Obx(() => locationController.isSimulationMode
? DropdownButton<String>(
value: locationController.getSimulatedSignalStrength(),
onChanged: (value) {

View File

@ -2,7 +2,8 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:geolocator/geolocator.dart';
import 'package:rogapp/widgets/debug_widget.dart';
import 'package:latlong2/latlong.dart';
//import 'package:rogapp/widgets/debug_widget.dart';
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
// LocationControllerクラスは、GetxControllerを継承したクラスであり、位置情報の管理を担当しています。
@ -10,12 +11,21 @@ import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
// 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);
@ -25,6 +35,57 @@ class LocationController extends GetxController {
StreamSubscription<Position>? positionStream;
// 位置情報のストリームを保持する変数です。StreamSubscription<Position>型で宣言されています。
//===== Akira Added 2024-4-9 start
// GPSシミュレーション用の変数を追加
bool isSimulationMode = true;
LatLng? lastValidLocation;
// GPSシミュレーション用のメソッドを追加
void setSimulationMode(bool value) {
isSimulationMode = value;
}
String latestSignalStrength="low";
// GPS信号の強弱を判断するメソッドを追加. 10m 以内強、30m以内中、それ以上
//
String getGpsSignalStrength(Position? position) {
if (position == null) {
latestSignalStrength="low";
return 'low';
}
final accuracy = position.accuracy;
if(isSimulationMode){
return _simulatedSignalStrength.value; // GPS信号強度シミュレーション
}else {
if (accuracy <= 10) {
latestSignalStrength="high";
return 'high';
} else if (accuracy <= 30) {
latestSignalStrength="medium";
return 'medium';
} else {
latestSignalStrength="low";
return 'low';
}
}
}
// 現在位置を調整するメソッドを追加
LatLng? adjustCurrentLocation(Position? position) {
if (position == null) {
return null;
//return lastValidLocation ?? LatLng(0, 0);
}
final signalStrength = getGpsSignalStrength(position);
if (signalStrength == 'high' || signalStrength == 'medium') {
lastValidLocation = LatLng(position.latitude, position.longitude);
}
return lastValidLocation ?? LatLng(position.latitude, position.longitude);
}
//===== Akira Added 2024-4-9 end
final locationMarkerPositionStreamController =
StreamController<LocationMarkerPosition?>.broadcast();
// 位置マーカーの位置情報を送信するためのStreamControllerです。
@ -36,7 +97,7 @@ class LocationController extends GetxController {
//
// GPS信号強度をシミュレートするための変数
Rx<String> _simulatedSignalStrength = Rx<String>('high');
final Rx<String> _simulatedSignalStrength = Rx<String>('high');
// GPS信号強度をシミュレートするための関数
void setSimulatedSignalStrength(String strength) {
@ -82,6 +143,8 @@ class LocationController extends GetxController {
//
void startPositionStream() async {
// Check for location service and permissions before starting the stream
// 位置情報サービスの有効性をチェックし、無効な場合はエラーハンドリングを行います。
//
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// Use GetX's context to show a dialog
@ -107,6 +170,8 @@ class LocationController extends GetxController {
return;
}
// 位置情報の権限をチェックし、拒否されている場合はエラーハンドリングを行います。
//
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
@ -158,15 +223,37 @@ class LocationController extends GetxController {
return;
}
// 位置情報の設定を行います。
// Set up the location options
const locationOptions =
LocationSettings(accuracy: LocationAccuracy.high, distanceFilter: 0);
// 既存の位置情報のストリームをキャンセルします。
await positionStream?.cancel();
// 新しい位置情報のストリームを開始します。
//
positionStream = Geolocator.getPositionStream(locationSettings: locationOptions).listen(
(Position? position) {
final adjustedLocation = adjustCurrentLocation(position);
if (adjustedLocation!=null) {
final locationMarkerPosition = LocationMarkerPosition(
latitude: adjustedLocation.latitude,
longitude: adjustedLocation.longitude,
accuracy: position?.accuracy ?? 0,
);
locationMarkerPositionStreamController.add(locationMarkerPosition);
}else{
// 位置情報が取得できなかった場合、
// locationMarkerPositionStreamControllerにnullを追加します。
locationMarkerPositionStreamController.add(null);
}
/*
if (position != null) {
// ストリームから位置情報を受信した場合、
// LocationMarkerPositionオブジェクトを作成し、
// locationMarkerPositionStreamControllerに追加します。
//
final LocationMarkerPosition locationMarkerPosition =
LocationMarkerPosition(
latitude: position.latitude,
@ -174,10 +261,14 @@ class LocationController extends GetxController {
accuracy: position.accuracy);
locationMarkerPositionStreamController.add(locationMarkerPosition);
} else {
// 位置情報が取得できなかった場合、
// locationMarkerPositionStreamControllerにnullを追加します。
locationMarkerPositionStreamController.add(null);
}
*/
},
onError: (e) {
// エラーが発生した場合、locationMarkerPositionStreamControllerにエラーを追加します。
locationMarkerPositionStreamController.addError(e);
},
onDone: () {
@ -187,6 +278,8 @@ class LocationController extends GetxController {
);
// Resume stream if it was paused previously
// ストリームが一時停止中の場合、ストリームを再開します。
//
if (isStreamPaused) {
isStreamPaused = false;
positionStream!.resume();

View File

@ -1,5 +1,5 @@
import 'dart:ffi';
import 'dart:math';
//import 'dart:ffi';
//import 'dart:math';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@ -7,13 +7,14 @@ import 'package:rogapp/model/destination.dart';
import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/services/DatabaseService.dart';
import 'package:rogapp/utils/database_helper.dart';
//import 'package:rogapp/utils/database_helper.dart';
import 'package:rogapp/widgets/GameState/CheckinState.dart';
import 'package:rogapp/widgets/GameState/ConnectionStatus.dart';
import 'package:rogapp/widgets/GameState/DashboardWidget.dart';
//import 'package:rogapp/widgets/GameState/DashboardWidget.dart';
import 'package:rogapp/widgets/GameState/game_on_off.dart';
import 'package:rogapp/widgets/GameState/Colors.dart';
//import 'package:rogapp/widgets/GameState/Colors.dart';
import 'package:rogapp/widgets/gps_status.dart';
import 'package:rogapp/utils/location_controller.dart';
class GameStateManager {
static final GameStateManager _instance = GameStateManager._internal();
@ -24,8 +25,8 @@ class GameStateManager {
GameStateManager._internal();
List<String> _logs = [];
List<VoidCallback> _listeners = [];
final List<String> _logs = [];
final List<VoidCallback> _listeners = [];
List<String> get logs => _logs;
@ -103,9 +104,10 @@ class _GameStateWidgetState extends State<GameStateWidget> {
@override
Widget build(BuildContext context) {
final DatabaseService dbService = DatabaseService();
//final LocationController locationController = Get.find<LocationController>();
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.black12),
decoration: const BoxDecoration(color: Colors.black12),
child: GestureDetector(
onTap: toggleExpanded,
child: AnimatedContainer(
@ -117,15 +119,15 @@ class _GameStateWidgetState extends State<GameStateWidget> {
// Top bar with clear button
if (isExpanded)
Container(
padding: EdgeInsets.symmetric(horizontal: 10.0),
padding: const EdgeInsets.symmetric(horizontal: 10.0),
color: Colors.blueGrey, // Adjust color as needed
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('ゲームステータス', style: TextStyle(color: Colors.white)),
const Text('ゲームステータス', style: TextStyle(color: Colors.white)),
IconButton(
icon: Icon(Icons.clear, color: Colors.white),
icon: const Icon(Icons.clear, color: Colors.white),
onPressed: toggleExpanded,
),
],
@ -196,7 +198,7 @@ class _GameStateWidgetState extends State<GameStateWidget> {
Padding(
padding: const EdgeInsets.all(4.0),
child:GpsSignalStrengthIndicator(
destinationController: Get.find<DestinationController>(),
locationController: Get.find<LocationController>(),
minimized: !isExpanded, // isExpanded はあなたのロジックに依存した変数),
)
),

View File

@ -1,26 +1,26 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rogapp/widgets/GameState/Colors.dart';
import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/widgets/custom_icons.dart';
import 'package:rogapp/utils/location_controller.dart';
enum GPSStatus { high, middle, low }
class GpsSignalStrengthIndicator extends StatelessWidget {
final DestinationController destinationController; // = Get.find<DestinationController>();
LocationController locationController;
final bool minimized;
// コンストラクタにminimizedパラメータを追加し、デフォルト値をfalseに設定
const GpsSignalStrengthIndicator({
GpsSignalStrengthIndicator({
Key? key,
required this.destinationController,
required this.locationController,
this.minimized = false, // ここでデフォルト値を指定
}) : super(key: key);
});
@override
Widget build(BuildContext context) {
// final LocationController locationController = Get.find<LocationController>();
return Obx(() {
final signalStrength = destinationController.getGpsSignalStrength();
String signalStrength = locationController.latestSignalStrength;
print("signalStrength=${signalStrength}");
IconData iconData;
Color backgroundColor;
String text;

View File

@ -34,7 +34,7 @@ import 'package:rogapp/widgets/game_state_view.dart';
// StatefulWidgetを継承したクラスで、地図表示のメインウィジェットです。
//
class MapWidget extends StatefulWidget {
MapWidget({Key? key}) : super(key: key);
const MapWidget({Key? key}) : super(key: key);
@override
State<MapWidget> createState() => _MapWidgetState();
@ -117,7 +117,7 @@ class _MapWidgetState extends State<MapWidget> {
),
i.properties!['cp'] == -1
? Transform.translate(
offset: Offset(18, 0),
offset: const Offset(18, 0),
child: Transform.rotate(
alignment: Alignment.centerLeft,
origin: Offset.fromDirection(1, 26),
@ -134,7 +134,7 @@ class _MapWidgetState extends State<MapWidget> {
],
)),
Transform.translate(
offset: Offset(45, 0),
offset: const Offset(45, 0),
child: Align(
alignment: Alignment.center,
child: Container(
@ -162,7 +162,7 @@ class _MapWidgetState extends State<MapWidget> {
// Text with black fill
Text(
TextUtils.getDisplayTextFeture(i),
style: TextStyle(
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
color: Colors.black,
@ -269,14 +269,15 @@ class _MapWidgetState extends State<MapWidget> {
if (mapEvent is MapEventMoveEnd) {}
});
},
//center: LatLng(37.15319600454702, 139.58765950528198),
initialCenter: const LatLng(37.15319600454702, 139.58765950528198),
bounds: indexController.currentBound.isNotEmpty
? indexController.currentBound[0]
: LatLngBounds.fromPoints([
LatLng(35.03999881162295, 136.40587119778962),
LatLng(36.642756778706904, 137.95226720406063)
const LatLng(35.03999881162295, 136.40587119778962),
const LatLng(36.642756778706904, 137.95226720406063)
]),
zoom: 1,
initialZoom: 1,
interactiveFlags:
InteractiveFlag.pinchZoom | InteractiveFlag.drag,
@ -312,15 +313,28 @@ class _MapWidgetState extends State<MapWidget> {
.locationMarkerPositionStreamController.stream,
// locationMarkerPositionStreamController.streamを設定して、現在位置の更新を監視しています。
alignDirectionOnUpdate: AlignOnUpdate.never,
turnOnHeadingUpdate: TurnOnHeadingUpdate.never,
//turnOnHeadingUpdate: TurnOnHeadingUpdate.never,
style: const LocationMarkerStyle(
// styleプロパティで、現在位置のマーカーのスタイルを設定しています。
marker: Stack(
children: [
CircleAvatar(
radius: 13.5,
backgroundColor: Colors.blue,
child: Icon(Icons.navigation, color: Colors.white),
),
//if (locationController.getGpsSignalStrength() == 'low')
// child: Icon(Icons.warning, color: Colors.red),
],
),
/*
marker: DefaultLocationMarker(
child: Icon(
Icons.navigation,
color: Colors.yellowAccent,
),
),
*/
markerSize: Size(27, 27),
markerDirection: MarkerDirection.heading,
),
@ -333,7 +347,7 @@ class _MapWidgetState extends State<MapWidget> {
indexController.locations[0].features.map((i) {
//print("i si ${i.properties!['location_id']}");
RegExp regex = RegExp(r'([.]*0)(?!.*\d)');
//RegExp regex = RegExp(r'([.]*0)(?!.*\d)');
GeoJSONMultiPoint p =
i!.geometry as GeoJSONMultiPoint;
//print(