feat: improve map initialization process and communication

This commit is contained in:
Nedifinita
2025-09-29 20:17:05 +08:00
parent 6718ef7129
commit cc2a495984
4 changed files with 95 additions and 133 deletions

View File

@@ -14848,8 +14848,8 @@
el.addEventListener("click", function (e) { el.addEventListener("click", function (e) {
e.stopPropagation(); e.stopPropagation();
showTrainDetails(lat, lng, recordData); showTrainDetails(lat, lng, recordData);
if (window.flutter_inappwebview) { if (window.showTrainDetails) {
window.flutter_inappwebview.callHandler("showTrainDetails", { window.showTrainDetails.postMessage(JSON.stringify({
id: recordData.id || Date.now(), id: recordData.id || Date.now(),
trainNumber: trainNumber || "未知车次", trainNumber: trainNumber || "未知车次",
trainType: recordData.trainType || "未知类型", trainType: recordData.trainType || "未知类型",
@@ -14858,7 +14858,7 @@
latitude: lat, latitude: lat,
longitude: lng, longitude: lng,
timestamp: Date.now(), timestamp: Date.now(),
}); }));
} }
}); });
const marker = new maplibregl.Marker({ const marker = new maplibregl.Marker({
@@ -14931,11 +14931,21 @@
.addTo(map); .addTo(map);
} }
function setCenter(lat, lng, zoom, bearing) { function setCenter(lat, lng, zoom, bearing) {
map.jumpTo({ if (!window.map) {
console.error("[JS] Map object not ready in setCenter");
return;
}
window.map.jumpTo({
center: [lng, lat], center: [lng, lat],
zoom: zoom !== undefined ? zoom : map.getZoom(), zoom: zoom !== undefined ? zoom : window.map.getZoom(),
bearing: bearing !== undefined ? bearing : map.getBearing(), bearing: bearing !== undefined ? bearing : window.map.getBearing(),
}); });
const mapContainer = window.map.getContainer();
if (mapContainer.style.opacity === "0") {
mapContainer.style.opacity = "1";
}
} }
function getMapState() { function getMapState() {
const center = map.getCenter(); const center = map.getCenter();
@@ -14948,17 +14958,19 @@
} }
function setupMapEventListeners() { function setupMapEventListeners() {
if (!map) return; if (!map) return;
map.on("moveend", function () { map.on("move", function () {
const center = map.getCenter(); const center = map.getCenter();
const zoom = map.getZoom(); const zoom = map.getZoom();
const bearing = map.getBearing(); const bearing = map.getBearing();
if (window.flutter_inappwebview) {
window.flutter_inappwebview.callHandler("onMapStateChanged", { if (window.onMapStateChanged) {
const mapState = JSON.stringify({
lat: center.lat, lat: center.lat,
lng: center.lng, lng: center.lng,
zoom: zoom, zoom: zoom,
bearing: bearing, bearing: bearing,
}); });
window.onMapStateChanged.postMessage(mapState);
} }
}); });
} }

View File

@@ -32,13 +32,41 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
double _currentRotation = 0.0; double _currentRotation = 0.0;
LatLng? _currentLocation; LatLng? _currentLocation;
LatLng? _lastTrainLocation; LatLng? _lastTrainLocation;
bool _isDataLoaded = false;
final Completer<void> _webViewReadyCompleter = Completer<void>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
_initializeWebView(); _initializeWebView();
_initializeServices(); _startInitialization();
}
Future<void> _startInitialization() async {
setState(() {
_isLoading = true;
});
try {
await _loadSettings();
await _loadTrainRecordsFromDatabase();
await _webViewReadyCompleter.future;
_initializeMapCamera();
_initializeLocation();
_startAutoRefresh();
} catch (e, s) {
print('[Flutter] Init Map WebView Screen Failed: $e\n$s');
} finally {
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
} }
@override @override
@@ -48,16 +76,7 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
} }
} }
Future<void> _initializeServices() async { Future<void> _initializeWebView() async {
try {
await _loadSettings();
await _loadTrainRecordsFromDatabase();
_initializeLocation();
_startAutoRefresh();
} catch (e) {}
}
void _initializeWebView() {
_controller = WebViewController() _controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted) ..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0xFF121212)) ..setBackgroundColor(const Color(0xFF121212))
@@ -92,9 +111,8 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
_isLoading = false; _isLoading = false;
}); });
if (mounted) { if (!_webViewReadyCompleter.isCompleted) {
_initializeMap(); _webViewReadyCompleter.complete();
_initializeLocation();
} }
}, },
onWebResourceError: (WebResourceError error) { onWebResourceError: (WebResourceError error) {
@@ -107,6 +125,8 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
..loadFlutterAsset('assets/mapbox_map.html') ..loadFlutterAsset('assets/mapbox_map.html')
.then((_) {}) .then((_) {})
.catchError((error) {}); .catchError((error) {});
await Future.delayed(const Duration(milliseconds: 500));
} }
Future<void> _initializeLocation() async { Future<void> _initializeLocation() async {
@@ -266,10 +286,6 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
} else {} } else {}
} else {} } else {}
} else {} } else {}
if (mounted) {
_initializeMapPosition();
}
}); });
Future.delayed(const Duration(milliseconds: 3000), () { Future.delayed(const Duration(milliseconds: 3000), () {
@@ -351,25 +367,38 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
} }
} }
void _initializeMapPosition() { void _initializeMapCamera() {
if (_isMapInitialized) return; if (_isMapInitialized) return;
LatLng? targetLocation; LatLng targetLocation;
double targetZoom = _currentZoom;
double targetRotation = _currentRotation;
if (_lastTrainLocation != null) { if (_currentLocation != null) {
targetLocation = _lastTrainLocation; targetLocation = _currentLocation!;
} else if (_currentPosition != null) { } else if (_lastTrainLocation != null) {
targetLocation = targetLocation = _lastTrainLocation!;
LatLng(_currentPosition!.latitude, _currentPosition!.longitude); targetZoom = 14.0;
} targetRotation = 0.0;
if (targetLocation != null) {
_centerMap(targetLocation,
zoom: _currentZoom, rotation: _currentRotation);
_isMapInitialized = true;
} else { } else {
_isMapInitialized = true; targetLocation = const LatLng(39.9042, 116.4074);
targetZoom = 10.0;
} }
_centerMap(targetLocation, zoom: targetZoom, rotation: targetRotation);
_isMapInitialized = true;
Future.delayed(const Duration(milliseconds: 500), () {
if (mounted) {
_updateUserLocation();
_updateTrainMarkers();
_controller.runJavaScript('''
if (window.MapInterface) {
window.MapInterface.setRailwayVisible($_isRailwayLayerVisible);
}
''');
}
});
} }
void _centerMap(LatLng location, {double? zoom, double? rotation}) { void _centerMap(LatLng location, {double? zoom, double? rotation}) {
@@ -430,91 +459,6 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
} catch (e) {} } catch (e) {}
} }
Future<void> _initializeMap() async {
try {
LatLng? targetLocation;
double targetZoom = 14.0;
double targetRotation = _currentRotation;
if (_lastTrainLocation != null) {
targetLocation = _lastTrainLocation;
targetZoom = 14.0;
targetRotation = 0.0;
} else if (_currentPosition != null) {
targetLocation =
LatLng(_currentPosition!.latitude, _currentPosition!.longitude);
targetZoom = 16.0;
targetRotation = 0.0;
}
if (targetLocation != null) {
_centerMap(targetLocation, zoom: targetZoom, rotation: targetRotation);
try {
await _controller.runJavaScript('''
(function() {
if (window.map && window.map.getContainer) {
window.map.getContainer().style.opacity = '1';
return true;
} else {
return false;
}
})();
''');
} catch (e) {
print('显示地图失败: $e');
Future.delayed(const Duration(milliseconds: 500), () {
_controller.runJavaScript('''
(function() {
if (window.map && window.map.getContainer) {
window.map.getContainer().style.opacity = '1';
console.log('延迟显示地图成功');
}
})();
''');
});
}
}
setState(() {
_isMapInitialized = true;
});
} catch (e, stackTrace) {}
Future.delayed(const Duration(milliseconds: 1000), () {
if (mounted && _isMapInitialized) {
_updateTrainMarkers();
_controller.runJavaScript('''
(function() {
if (window.MapInterface) {
try {
window.MapInterface.setRailwayVisible($_isRailwayLayerVisible);
console.log('初始化铁路图层状态: $_isRailwayLayerVisible');
} catch (error) {
console.error('初始化铁路图层失败:', error);
}
}
})();
''');
}
});
Future.delayed(const Duration(milliseconds: 3000), () {
if (mounted && _isMapInitialized) {
_updateTrainMarkers();
}
});
Future.delayed(const Duration(seconds: 5), () {
if (mounted && _isLoading) {
setState(() {
_isLoading = false;
});
}
});
}
LatLng? _parseDmsCoordinate(String? positionInfo) { LatLng? _parseDmsCoordinate(String? positionInfo) {
if (positionInfo == null || if (positionInfo == null ||
positionInfo.isEmpty || positionInfo.isEmpty ||
@@ -943,10 +887,10 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
void _onMapStateChanged(Map<String, dynamic> mapState) { void _onMapStateChanged(Map<String, dynamic> mapState) {
try { try {
final lat = mapState['lat'] as double; final lat = (mapState['lat'] as num).toDouble();
final lng = mapState['lng'] as double; final lng = (mapState['lng'] as num).toDouble();
final zoom = mapState['zoom'] as double; final zoom = (mapState['zoom'] as num).toDouble();
final bearing = mapState['bearing'] as double; final bearing = (mapState['bearing'] as num).toDouble();
setState(() { setState(() {
_currentLocation = LatLng(lat, lng); _currentLocation = LatLng(lat, lng);

View File

@@ -13,7 +13,7 @@ class DatabaseService {
DatabaseService._internal(); DatabaseService._internal();
static const String _databaseName = 'train_database'; static const String _databaseName = 'train_database';
static const _databaseVersion = 6; static const _databaseVersion = 7;
static const String trainRecordsTable = 'train_records'; static const String trainRecordsTable = 'train_records';
static const String appSettingsTable = 'app_settings'; static const String appSettingsTable = 'app_settings';
@@ -87,6 +87,10 @@ class DatabaseService {
await db.execute( await db.execute(
'ALTER TABLE $appSettingsTable ADD COLUMN hideUngroupableRecords INTEGER NOT NULL DEFAULT 0'); 'ALTER TABLE $appSettingsTable ADD COLUMN hideUngroupableRecords INTEGER NOT NULL DEFAULT 0');
} }
if (oldVersion < 7) {
await db.execute(
'ALTER TABLE $appSettingsTable ADD COLUMN mapSettingsTimestamp INTEGER');
}
} }
Future<void> _onCreate(Database db, int version) async { Future<void> _onCreate(Database db, int version) async {
@@ -136,7 +140,8 @@ class DatabaseService {
groupBy TEXT NOT NULL DEFAULT 'trainAndLoco', groupBy TEXT NOT NULL DEFAULT 'trainAndLoco',
timeWindow TEXT NOT NULL DEFAULT 'unlimited', timeWindow TEXT NOT NULL DEFAULT 'unlimited',
mapTimeFilter TEXT NOT NULL DEFAULT 'unlimited', mapTimeFilter TEXT NOT NULL DEFAULT 'unlimited',
hideUngroupableRecords INTEGER NOT NULL DEFAULT 0 hideUngroupableRecords INTEGER NOT NULL DEFAULT 0,
mapSettingsTimestamp INTEGER
) )
'''); ''');
@@ -164,6 +169,7 @@ class DatabaseService {
'timeWindow': 'unlimited', 'timeWindow': 'unlimited',
'mapTimeFilter': 'unlimited', 'mapTimeFilter': 'unlimited',
'hideUngroupableRecords': 0, 'hideUngroupableRecords': 0,
'mapSettingsTimestamp': null,
}); });
} }

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.5.0-flutter+50 version: 0.5.1-flutter+51
environment: environment:
sdk: ^3.5.4 sdk: ^3.5.4