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) {
e.stopPropagation();
showTrainDetails(lat, lng, recordData);
if (window.flutter_inappwebview) {
window.flutter_inappwebview.callHandler("showTrainDetails", {
if (window.showTrainDetails) {
window.showTrainDetails.postMessage(JSON.stringify({
id: recordData.id || Date.now(),
trainNumber: trainNumber || "未知车次",
trainType: recordData.trainType || "未知类型",
@@ -14858,7 +14858,7 @@
latitude: lat,
longitude: lng,
timestamp: Date.now(),
});
}));
}
});
const marker = new maplibregl.Marker({
@@ -14931,11 +14931,21 @@
.addTo(map);
}
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],
zoom: zoom !== undefined ? zoom : map.getZoom(),
bearing: bearing !== undefined ? bearing : map.getBearing(),
zoom: zoom !== undefined ? zoom : window.map.getZoom(),
bearing: bearing !== undefined ? bearing : window.map.getBearing(),
});
const mapContainer = window.map.getContainer();
if (mapContainer.style.opacity === "0") {
mapContainer.style.opacity = "1";
}
}
function getMapState() {
const center = map.getCenter();
@@ -14948,17 +14958,19 @@
}
function setupMapEventListeners() {
if (!map) return;
map.on("moveend", function () {
map.on("move", function () {
const center = map.getCenter();
const zoom = map.getZoom();
const bearing = map.getBearing();
if (window.flutter_inappwebview) {
window.flutter_inappwebview.callHandler("onMapStateChanged", {
if (window.onMapStateChanged) {
const mapState = JSON.stringify({
lat: center.lat,
lng: center.lng,
zoom: zoom,
bearing: bearing,
});
window.onMapStateChanged.postMessage(mapState);
}
});
}

View File

@@ -32,13 +32,41 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
double _currentRotation = 0.0;
LatLng? _currentLocation;
LatLng? _lastTrainLocation;
bool _isDataLoaded = false;
final Completer<void> _webViewReadyCompleter = Completer<void>();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_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
@@ -48,16 +76,7 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
}
}
Future<void> _initializeServices() async {
try {
await _loadSettings();
await _loadTrainRecordsFromDatabase();
_initializeLocation();
_startAutoRefresh();
} catch (e) {}
}
void _initializeWebView() {
Future<void> _initializeWebView() async {
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0xFF121212))
@@ -92,9 +111,8 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
_isLoading = false;
});
if (mounted) {
_initializeMap();
_initializeLocation();
if (!_webViewReadyCompleter.isCompleted) {
_webViewReadyCompleter.complete();
}
},
onWebResourceError: (WebResourceError error) {
@@ -107,6 +125,8 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
..loadFlutterAsset('assets/mapbox_map.html')
.then((_) {})
.catchError((error) {});
await Future.delayed(const Duration(milliseconds: 500));
}
Future<void> _initializeLocation() async {
@@ -266,10 +286,6 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
} else {}
} else {}
} else {}
if (mounted) {
_initializeMapPosition();
}
});
Future.delayed(const Duration(milliseconds: 3000), () {
@@ -351,25 +367,38 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
}
}
void _initializeMapPosition() {
void _initializeMapCamera() {
if (_isMapInitialized) return;
LatLng? targetLocation;
LatLng targetLocation;
double targetZoom = _currentZoom;
double targetRotation = _currentRotation;
if (_lastTrainLocation != null) {
targetLocation = _lastTrainLocation;
} else if (_currentPosition != null) {
targetLocation =
LatLng(_currentPosition!.latitude, _currentPosition!.longitude);
}
if (targetLocation != null) {
_centerMap(targetLocation,
zoom: _currentZoom, rotation: _currentRotation);
_isMapInitialized = true;
if (_currentLocation != null) {
targetLocation = _currentLocation!;
} else if (_lastTrainLocation != null) {
targetLocation = _lastTrainLocation!;
targetZoom = 14.0;
targetRotation = 0.0;
} 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}) {
@@ -430,91 +459,6 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
} 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) {
if (positionInfo == null ||
positionInfo.isEmpty ||
@@ -943,10 +887,10 @@ class MapWebViewScreenState extends State<MapWebViewScreen>
void _onMapStateChanged(Map<String, dynamic> mapState) {
try {
final lat = mapState['lat'] as double;
final lng = mapState['lng'] as double;
final zoom = mapState['zoom'] as double;
final bearing = mapState['bearing'] as double;
final lat = (mapState['lat'] as num).toDouble();
final lng = (mapState['lng'] as num).toDouble();
final zoom = (mapState['zoom'] as num).toDouble();
final bearing = (mapState['bearing'] as num).toDouble();
setState(() {
_currentLocation = LatLng(lat, lng);

View File

@@ -13,7 +13,7 @@ class DatabaseService {
DatabaseService._internal();
static const String _databaseName = 'train_database';
static const _databaseVersion = 6;
static const _databaseVersion = 7;
static const String trainRecordsTable = 'train_records';
static const String appSettingsTable = 'app_settings';
@@ -87,6 +87,10 @@ class DatabaseService {
await db.execute(
'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 {
@@ -136,7 +140,8 @@ class DatabaseService {
groupBy TEXT NOT NULL DEFAULT 'trainAndLoco',
timeWindow 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',
'mapTimeFilter': 'unlimited',
'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
# 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.
version: 0.5.0-flutter+50
version: 0.5.1-flutter+51
environment:
sdk: ^3.5.4