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_polyline_points/flutter_polyline_points.dart'; import 'package:geojson_vi/geojson_vi.dart'; import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; import 'package:rogapp/pages/settings/settings_binding.dart'; 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/utils/database_helper.dart'; import 'package:rogapp/utils/location_controller.dart'; import 'package:rogapp/utils/text_util.dart'; import 'package:rogapp/widgets/base_layer_widget.dart'; import 'package:rogapp/widgets/bottom_sheet_new.dart'; import 'package:rogapp/widgets/current_position_widget.dart'; import 'package:rogapp/widgets/game_state_view.dart'; import 'package:rogapp/pages/settings/settings_controller.dart'; import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; class MapResetController { void Function()? resetIdleTimer; } class MapWidget extends StatefulWidget { const MapWidget({Key? key}) : super(key: key); @override State createState() => _MapWidgetState(); } class _MapWidgetState extends State with WidgetsBindingObserver { //class _MapWidgetState extends State { final IndexController indexController = Get.find(); final DestinationController destinationController = Get.find(); final LocationController locationController = Get.find(); final SettingsController settingsController = Get.find(); late MapController mapController; final Completer mapControllerCompleter = Completer(); StreamSubscription? subscription; Timer? _timer; bool curr_marker_display = false; Map _markerCache = {}; List _markers = []; @override void initState() { super.initState(); SettingsBinding().dependencies(); // これを追加 _startIdleTimer(); mapController = MapController(); indexController.mapController = mapController; // added by Akira WidgetsBinding.instance.addObserver(this); _startIdleTimer(); // マップの操作イベントをリッスンして、_resetTimerを呼び出す mapController.mapEventStream.listen((MapEvent mapEvent) { if (mapEvent is MapEventMove || mapEvent is MapEventFlingAnimation) { _resetTimer(); } }); // MapControllerの初期化が完了するまで待機 WidgetsBinding.instance.addPostFrameCallback((_) { debugPrint("MapControllerの初期化が完了"); setState(() { indexController.isMapControllerReady.value = true; }); // MapControllerの初期化が完了したら、IndexControllerのonInitを呼び出す indexController.checkPermission(); }); late MapResetController mapResetController = MapResetController(); mapResetController.resetIdleTimer = _resetIdleTimer; Get.put(mapResetController); // indexController.mapController = MapController(initCompleter: mapControllerCompleter); } void _resetIdleTimer() { debugPrint("_resetIdleTimer..."); _timer?.cancel(); _startIdleTimer(); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); // added mapController?.dispose(); _timer?.cancel(); super.dispose(); } // added by Akira /* @override void didChangeAppLifecycleState(AppLifecycleState state) { debugPrint("MapWidget:didChangeAppLifecycleState...state=${state}"); if (state == AppLifecycleState.resumed) { _resetTimer(); } } */ // _centerMapOnUser を10秒間でコール void _startIdleTimer() { //debugPrint("_startIdleTimer ...."); final settingsController = Get.find(); if (!settingsController.autoReturnDisabled.value) { _timer = Timer(settingsController.timerDuration.value, _centerMapOnUser); } } // タイマーをリセットして_startIdleTimer をコール void _resetTimer() { //debugPrint("_resetTimer ...."); _timer?.cancel(); _startIdleTimer(); } // マッぷを現在位置を中心にする。 void _centerMapOnUser() { //debugPrint("_centerMapOnUser ...."); if (mounted) { //debugPrint("_centerMapOnUser => centering ...."); destinationController.centerMapToCurrentLocation(); } } Future _initMarkers() async { List markers = await _getMarkers(); setState(() { _markers = markers; }); } Future> _getMarkers() async { List markers = []; if (indexController.locations.isNotEmpty && indexController.locations[0].features.isNotEmpty) { for (var feature in indexController.locations[0].features) { GeoJSONMultiPoint point = feature!.geometry as GeoJSONMultiPoint; LatLng latLng = LatLng(point.coordinates[0][1], point.coordinates[0][0]); markers.add(Marker( point: latLng, width: 30.0, height: 30.0, child: getMarkerShape(feature), )); } } return markers; } // Widget getMarkerShape(GeoJSONFeature i, BuildContext context) { Widget getMarkerShape(GeoJSONFeature i) { GeoJSONMultiPoint p = i.geometry as GeoJSONMultiPoint; return InkWell( onTap: () { GeoJSONFeature? fs = indexController.getFeatureForLatLong( p.coordinates[0][1], p.coordinates[0][0]); if (fs != null) { indexController.currentFeature.clear(); indexController.currentFeature.add(fs); Destination des = destinationController.festuretoDestination(fs); DatabaseHelper db = DatabaseHelper.instance; db.getDestinationByLatLon(des.lat!, des.lon!).then((value) { destinationController.shouldShowBottomSheet = false; showModalBottomSheet( constraints: BoxConstraints.loose(Size(Get.width, Get.height * 0.85)), context: context, isScrollControlled: true, isDismissible: true, builder: ((context) => BottomSheetNew( destination: des, isAlreadyCheckedIn: value.isNotEmpty)), ).whenComplete(() { destinationController.shouldShowBottomSheet = true; destinationController.skipGps = false; }); }); } }, child: Stack( fit: StackFit.expand, children: [ Container( // マーカー height: 32, width: 32, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.transparent, border: Border.all( color: i.properties!['buy_point'] > 0 ? Colors.blue : Colors.red, width: 3, style: BorderStyle.solid, ), ), child: Stack( alignment: Alignment.center, children: [ const Icon( Icons.circle, size: 6.0, ), i.properties!['cp'] <= 0 ? Transform.translate ( offset: const Offset(-3, 0), //-3 child: Transform.rotate( alignment: Alignment.centerLeft, origin: Offset.fromDirection(1, 26), angle: 270 * pi / 180, child: const Icon( Icons.play_arrow_outlined, color: Colors.red, size: 70, )), ) : Container( color: Colors.transparent, ), ], ), ), Transform.translate( offset: const Offset(30, 0), // 30,0 child: Align( alignment: Alignment.center, child: Container ( //width: 80, // 幅を指定 //height: 60, // 40 //color: Colors.purple.withOpacity(0.2), color: Colors.transparent, //child: Text(' '). //constraints: const BoxConstraints(maxWidth: 60.0), // 最大幅を設定 //constraints: BoxConstraints(maxWidth: maxWidth), // 最大幅を設定 //color: Colors.purple.withOpacity(0.2), child: Stack( children: [ Text( // アウトライン TextUtils.getDisplayTextFeture(i), style: TextStyle( fontSize: 16, // 16 fontWeight: FontWeight.w700, overflow: TextOverflow.visible, //height: 1.2, foreground: Paint() ..style = PaintingStyle.stroke ..strokeWidth = 1 // 2 ..color = Colors.white, ), maxLines: 1, // テキストを1行に制限 softWrap: false, // テキストの折り返しを無効化 ), Text( // テキスト TextUtils.getDisplayTextFeture(i), style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w700, overflow: TextOverflow.visible, //fontWeight: FontWeight.bold, //height: 1.2, color: Colors.black, ), maxLines: 1, // テキストを1行に制限 softWrap: false, // テキストの折り返しを無効化 ), ], ), ), ), ) ], ), ); } List? getPoints() { List pts = []; for (PointLatLng p in indexController.routePoints) { LatLng l = LatLng(p.latitude, p.longitude); pts.add(l); } return pts; } @override Widget build(BuildContext context) { final settingsController = Get.find(); // これを追加 //final PopupController popupController = PopupController(); return Stack( children: [ Obx(() => indexController.isLoading.value == true ? const Padding( padding: EdgeInsets.only(top: 60.0), child: CircularProgressIndicator(), ) : FlutterMap( mapController: mapController, //mapController: indexController.mapController, options: MapOptions( maxZoom: 18.4, onMapReady: () { _initMarkers(); //indexController.isMapControllerReady.value = true; }, initialCenter: const LatLng(37.15319600454702, 139.58765950528198), bounds: indexController.currentBound.isNotEmpty ? indexController.currentBound[0] : LatLngBounds.fromPoints([ const LatLng(35.03999881162295, 136.40587119778962), const LatLng(36.642756778706904, 137.95226720406063) ]), initialZoom: 1, interactiveFlags: InteractiveFlag.pinchZoom | InteractiveFlag.drag, onPositionChanged: (MapPosition pos, hasGesture) { if (hasGesture) { _resetTimer(); } indexController.currentBound = [pos.bounds!]; }, onMapEvent: (MapEvent mapEvent) { if (mapEvent is MapEventMove) { destinationController.shouldShowBottomSheet = true; } }, //onTap: (_, __) => popupController.hideAllPopups(), ), children: [ const BaseLayer(), Obx( () => indexController.routePointLenght > 0 ? PolylineLayer( polylines: [ Polyline( points: getPoints()!, strokeWidth: 6.0, color: Colors.indigo, ), ], ) : Container(), ), CurrentLocationLayer( positionStream: locationController .locationMarkerPositionStreamController.stream, //alignDirectionOnUpdate: AlignOnUpdate.never, style: const LocationMarkerStyle( marker: Stack( children: [ CircleAvatar( radius: 13.5, backgroundColor: Colors.blue, child: Icon(Icons.navigation, color: Colors.white), ), ], ), markerSize: Size(27, 27), markerDirection: MarkerDirection.heading, ), //child: const Icon(Icons.navigation), ), FutureBuilder>( future: indexController.locations.isNotEmpty ? _getMarkers() : null, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return const Center(child: Text('マーカーの読み込みに失敗しました')); } else { return MarkerLayer(markers: snapshot.data ?? []); } }, ), //MarkerLayer(markers: indexController.locations.isNotEmpty ? _getMarkers() : []), ], )), const Positioned(top: 0, left: 0, child: GameStateWidget()), const Positioned(bottom: 10, right: 10, child: CurrentPosition()), StreamBuilder( stream: locationController.locationMarkerPositionStream, builder: (context, snapshot) { if (!snapshot.hasData) { //debugPrint("====== Not display current marker"); curr_marker_display = true; }else if(curr_marker_display){ debugPrint("====== Displayed current marker"); curr_marker_display = false; } return Container(); }, ) ], ); } }