feat: improve map initialization process and communication
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user