From b9c641954d23a7c4533f74142721596f3fdc8e15 Mon Sep 17 00:00:00 2001 From: Akira Date: Fri, 26 Apr 2024 01:30:41 +0900 Subject: [PATCH] adjust position of bottom_sheet title, fix popup while checkin --- lib/widgets/bottom_sheet_new.dart | 4 +- lib/widgets/map_widget.dart | 26 +- lib/widgets/map_widget.dart.20240425 | 432 +++++++++++++++++++++++++++ 3 files changed, 450 insertions(+), 12 deletions(-) create mode 100644 lib/widgets/map_widget.dart.20240425 diff --git a/lib/widgets/bottom_sheet_new.dart b/lib/widgets/bottom_sheet_new.dart index 3bec38d..01b9b4d 100644 --- a/lib/widgets/bottom_sheet_new.dart +++ b/lib/widgets/bottom_sheet_new.dart @@ -272,8 +272,10 @@ class BottomSheetNew extends GetView { ? null : () async { try{ + destinationController.isCheckingIn.value = true; // ここを追加 Get.back(); await destinationController.callforCheckin(destination); + destinationController.isCheckingIn.value = false; } catch (e) { // エラーハンドリング Get.snackbar( @@ -444,7 +446,7 @@ class BottomSheetNew extends GetView { ), Expanded( child: Container( - alignment: Alignment.center, + alignment: Alignment.centerLeft, child: Obx(() => Text( "${TextUtils.getDisplayTextFeture(indexController.currentFeature[0])} : ${indexController.currentFeature[0].properties!["location_name"]}", // indexController diff --git a/lib/widgets/map_widget.dart b/lib/widgets/map_widget.dart index 4d19bad..f62061d 100644 --- a/lib/widgets/map_widget.dart +++ b/lib/widgets/map_widget.dart @@ -184,10 +184,10 @@ class _MapWidgetState extends State with WidgetsBindingObserver { //}else{ // labelText=i.properties!['cp']; } - if( i.properties!['cp'] <= 0 ) { - debugPrint("Text=${labelText}"); - } - final double maxWidth = labelText.length * 16.0; + //if( i.properties!['cp'] <= 0 ) { + // debugPrint("Text=${labelText}"); + //} + final double maxWidth = labelText.length * 16.0; //16.0; GeoJSONMultiPoint p = i.geometry as GeoJSONMultiPoint; return InkWell( onTap: () { @@ -260,23 +260,25 @@ class _MapWidgetState extends State with WidgetsBindingObserver { ), ), Transform.translate( - offset: const Offset(30, 0), + offset: const Offset(30, 0), // 30,0 child: Align( alignment: Alignment.centerLeft, child: Container ( - width: 800, // 幅を指定 - height: 40, + //width: 200, // 幅を指定 + //height: 60, // 40 color: Colors.transparent, - //constraints: const BoxConstraints(maxWidth: 1000), // 最大幅を設定 - //constraints: BoxConstraints(maxWidth: maxWidth), // 最大幅を設定 + //child: Text(' '). + //constraints: const BoxConstraints(maxWidth: 1000.0), // 最大幅を設定 + constraints: BoxConstraints(maxWidth: maxWidth), // 最大幅を設定 //color: Colors.purple.withOpacity(0.2), child: Stack( children: [ Text( // アウトライン labelText, style: TextStyle( - fontSize: 16, + fontSize: 14, // 16 fontWeight: FontWeight.w700, + height: 1.2, foreground: Paint() ..style = PaintingStyle.stroke ..strokeWidth = 2 @@ -288,8 +290,10 @@ class _MapWidgetState extends State with WidgetsBindingObserver { Text( // テキスト labelText, style: const TextStyle( - fontSize: 16, + fontSize: 14, fontWeight: FontWeight.w700, + //fontWeight: FontWeight.bold, + height: 1.2, color: Colors.black, ), maxLines: 1, // テキストを1行に制限 diff --git a/lib/widgets/map_widget.dart.20240425 b/lib/widgets/map_widget.dart.20240425 new file mode 100644 index 0000000..e247b2e --- /dev/null +++ b/lib/widgets/map_widget.dart.20240425 @@ -0,0 +1,432 @@ +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/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:flutter_map_tile_caching/flutter_map_tile_caching.dart'; + +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(); + + 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(); + _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((_) { + setState(() { + indexController.isMapControllerReady.value = true; + }); + }); + +// indexController.mapController = MapController(initCompleter: mapControllerCompleter); + + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); // added + + mapController?.dispose(); + _timer?.cancel(); + super.dispose(); + } + + // added by Akira + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.resumed) { + _resetTimer(); + } + } + + // _centerMapOnUser を10秒間でコール + void _startIdleTimer() { + _timer = Timer(const Duration(milliseconds: (1000 * 10)), _centerMapOnUser); + } + + // タイマーをリセットして_startIdleTimer をコール + void _resetTimer() { + _timer?.cancel(); + _startIdleTimer(); + } + + // マッぷを現在位置を中心にする。 + void _centerMapOnUser() { + if (mounted) { + 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), + )); + + /* + if (_markerCache.containsKey(latLng)) { + markers.add(_markerCache[latLng]!); + } else { + Marker marker = Marker( + point: latLng, + width: 30.0, + height: 30.0, + child: getMarkerShape(feature), +// child: getMarkerShape(feature, context), + ); + _markerCache[latLng] = marker; + markers.add(marker); + } + */ + } + } + return markers; + } + + /* + Future> _getMarkers() async { + List markers = []; + 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]); + + if (_markerCache.containsKey(latLng)) { + markers.add(_markerCache[latLng]!); + } else { + Marker marker = Marker( + point: latLng, + width: 30.0, + height: 30.0, + builder: (ctx) => getMarkerShape(feature, ctx), + //child: null, + ); + _markerCache[latLng] = marker; + markers.add(marker); + } + } + return markers; + } + */ + +// Widget getMarkerShape(GeoJSONFeature i, BuildContext context) { + Widget getMarkerShape(GeoJSONFeature i) { + String labelText = TextUtils.getDisplayTextFeture(i); + if( i.properties!['cp'] == 0 ){ + labelText="Start/Goal"; + }else if(i.properties!['cp'] == -1 ){ + labelText="Start"; + }else if(i.properties!['cp'] == -2 ){ + labelText="Goal"; + //}else{ + // labelText=i.properties!['cp']; + } + if( i.properties!['cp'] <= 0 ) { + debugPrint("Text=${labelText}"); + } + final double maxWidth = labelText.length * 16.0; + 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), + 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), + child: Align( + alignment: Alignment.centerLeft, + child: Container ( + width: 200, // 幅を指定 + height: 60, // 40 + color: Colors.transparent, + //child: Text(' '). + //constraints: const BoxConstraints(maxWidth: 1000.0), // 最大幅を設定 + //constraints: BoxConstraints(maxWidth: maxWidth), // 最大幅を設定 + //color: Colors.purple.withOpacity(0.2), + child: Stack( + children: [ + Text( // アウトライン + labelText, + style: TextStyle( + fontSize: 14, // 16 + fontWeight: FontWeight.w700, + height: 1.2, + foreground: Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 2 + ..color = Colors.white, + ), + maxLines: 1, // テキストを1行に制限 + softWrap: false, // テキストの折り返しを無効化 + ), + Text( // テキスト + labelText, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w700, + //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 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(); + }, + ) + ], + ); + } +}