diff --git a/lib/screens/history_screen.dart b/lib/screens/history_screen.dart index dabc5e9..0d82f9d 100644 --- a/lib/screens/history_screen.dart +++ b/lib/screens/history_screen.dart @@ -221,28 +221,43 @@ class HistoryScreenState extends State { if (mounted) { if (_isAtTop) { setState(() { - bool isMerge = false; - Object? mergeResult; - if (_displayItems.isNotEmpty) { - final firstItem = _displayItems.first; - List tempRecords = [newRecord]; - if (firstItem is MergedTrainRecord) { - tempRecords.addAll(firstItem.records); - } else if (firstItem is TrainRecord) { - tempRecords.add(firstItem); - } - final mergeCheckResult = - MergeService.getMixedList(tempRecords, _mergeSettings); - if (mergeCheckResult.length == 1 && - mergeCheckResult.first is MergedTrainRecord) { - isMerge = true; - mergeResult = mergeCheckResult.first; + List allRecords = []; + Set selectedRecordIds = {}; + + for (final item in _displayItems) { + if (item is MergedTrainRecord) { + allRecords.addAll(item.records); + if (_selectedRecords.contains(item.records.first.uniqueId)) { + selectedRecordIds.addAll(item.records.map((r) => r.uniqueId)); + } + } else if (item is TrainRecord) { + allRecords.add(item); + if (_selectedRecords.contains(item.uniqueId)) { + selectedRecordIds.add(item.uniqueId); + } } } - if (isMerge) { - _displayItems[0] = mergeResult!; - } else { - _displayItems.insert(0, newRecord); + + allRecords.insert(0, newRecord); + + final mergedItems = + MergeService.getMixedList(allRecords, _mergeSettings); + + _displayItems.clear(); + _displayItems.addAll(mergedItems); + + _selectedRecords.clear(); + for (final item in _displayItems) { + if (item is MergedTrainRecord) { + if (item.records + .any((r) => selectedRecordIds.contains(r.uniqueId))) { + _selectedRecords.addAll(item.records.map((r) => r.uniqueId)); + } + } else if (item is TrainRecord) { + if (selectedRecordIds.contains(item.uniqueId)) { + _selectedRecords.add(item.uniqueId); + } + } } }); if (_scrollController.hasClients) { @@ -723,8 +738,6 @@ class HistoryScreenState extends State { Widget _buildRecordCard(TrainRecord record, {bool isSubCard = false, Key? key}) { final isSelected = _selectedRecords.contains(record.uniqueId); - final isExpanded = - !isSubCard && (_expandedStates[record.uniqueId] ?? false); return Card( key: key, @@ -752,6 +765,11 @@ class HistoryScreenState extends State { } widget.onSelectionChanged(); }); + } else { + setState(() { + _expandedStates[record.uniqueId] = + !(_expandedStates[record.uniqueId] ?? false); + }); } }, onLongPress: () { @@ -771,7 +789,8 @@ class HistoryScreenState extends State { _buildRecordHeader(record), _buildPositionAndSpeed(record), _buildLocoInfo(record), - if (isExpanded) _buildExpandedContent(record), + if (_expandedStates[record.uniqueId] ?? false) + _buildExpandedContent(record), ])))); } @@ -803,6 +822,7 @@ class HistoryScreenState extends State { final hasLocoInfo = formattedLocoInfo.isNotEmpty && formattedLocoInfo != ""; final shouldShowTrainRow = hasTrainNumber || hasDirection || hasLocoInfo; + final hasPosition = _parsePosition(record.positionInfo) != null; return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -856,7 +876,8 @@ class HistoryScreenState extends State { ])), if (hasLocoInfo) Text(formattedLocoInfo, - style: const TextStyle(fontSize: 14, color: Colors.white70)) + style: + const TextStyle(fontSize: 14, color: Colors.white70)), ]), const SizedBox(height: 2) ] diff --git a/lib/screens/realtime_screen.dart b/lib/screens/realtime_screen.dart index 0c0db2b..5c361b9 100644 --- a/lib/screens/realtime_screen.dart +++ b/lib/screens/realtime_screen.dart @@ -142,7 +142,6 @@ class RealtimeScreenState extends State { } } catch (e) { _selectedGroupKeys.remove(groupKey); - print('记录不存在,移除选中状态: $groupKey'); } } @@ -227,7 +226,6 @@ class RealtimeScreenState extends State { } } catch (e) { _selectedGroupKeys.remove(groupKey); - print('记录不存在,移除选中状态: $groupKey'); } } @@ -275,7 +273,6 @@ class RealtimeScreenState extends State { } } catch (e) { _selectedGroupKeys.remove(groupKey); - print('记录不存在,移除选中状态: $groupKey'); } } @@ -460,25 +457,19 @@ class RealtimeScreenState extends State { void initState() { super.initState(); _scrollController.addListener(() { - print( - '滚动监听器触发 - 当前位置: ${_scrollController.position.pixels}, maxScrollExtent: ${_scrollController.position.maxScrollExtent}, isAtTop: $_isAtTop'); - if (_scrollController.position.atEdge) { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { - print('到达底部(反转后的"顶部")- 设置 _isAtTop = true'); if (!_isAtTop) { setState(() => _isAtTop = true); } } else if (_scrollController.position.pixels == 0) { - print('到达顶部(反转后的"底部")- 设置 _isAtTop = false'); if (_isAtTop) { setState(() => _isAtTop = false); } } } else { if (_isAtTop) { - print('离开底部(反转后的"顶部")- 设置 _isAtTop = false'); setState(() => _isAtTop = false); } } @@ -501,16 +492,12 @@ class RealtimeScreenState extends State { if (mounted && _scrollController.hasClients && _displayItems.isNotEmpty) { try { final maxScrollExtent = _scrollController.position.maxScrollExtent; - print('初始滚动执行:maxScrollExtent=$maxScrollExtent'); _scrollController.jumpTo(maxScrollExtent); - print('初始滚动完成:位置=${_scrollController.position.pixels}'); if (!_isAtTop) { setState(() => _isAtTop = true); } - } catch (e) { - print('初始滚动错误:$e'); - } + } catch (e) {} } }); } @@ -675,13 +662,8 @@ class RealtimeScreenState extends State { try { final maxScrollExtent = _scrollController.position.maxScrollExtent; - print('loadRecords - 滚动到底部, maxScrollExtent: $maxScrollExtent'); _scrollController.jumpTo(maxScrollExtent); - print( - 'loadRecords - 滚动完成,新位置: ${_scrollController.position.pixels}'); - } catch (e) { - print('loadRecords - 滚动错误: $e'); - } + } catch (e) {} } } else { if (_isLoading) { @@ -697,11 +679,9 @@ class RealtimeScreenState extends State { } Future addNewRecord(TrainRecord newRecord) async { - print('addNewRecord - 开始添加新记录, 当前_isAtTop=$_isAtTop'); try { final position = _parsePositionFromRecord(newRecord); if (position == null) { - print('addNewRecord - 记录没有位置信息,忽略'); return; } @@ -721,41 +701,44 @@ class RealtimeScreenState extends State { if (!isNewRecord) return; if (mounted) { - setState(() { - bool isMerge = false; - Object? mergeResult; - String? oldSingleRecordKey; + List allRecords = []; + Set selectedRecordIds = {}; - if (_displayItems.isNotEmpty) { - final firstItem = _displayItems.first; - List tempRecords = [newRecord]; - if (firstItem is MergedTrainRecord) { - tempRecords.addAll(firstItem.records); - } else if (firstItem is TrainRecord) { - tempRecords.add(firstItem); - - oldSingleRecordKey = "single:${firstItem.uniqueId}"; + for (final item in _displayItems) { + if (item is MergedTrainRecord) { + allRecords.addAll(item.records); + if (_selectedGroupKeys.contains(item.groupKey)) { + selectedRecordIds.addAll(item.records.map((r) => r.uniqueId)); } - final mergeCheckResult = - MergeService.getMixedList(tempRecords, _mergeSettings); - if (mergeCheckResult.length == 1 && - mergeCheckResult.first is MergedTrainRecord) { - isMerge = true; - mergeResult = mergeCheckResult.first; + } else if (item is TrainRecord) { + allRecords.add(item); + if (_selectedGroupKeys.contains("single:${item.uniqueId}")) { + selectedRecordIds.add(item.uniqueId); } } + } - if (isMerge) { - final mergedRecord = mergeResult as MergedTrainRecord; - _displayItems[0] = mergedRecord; + allRecords.insert(0, newRecord); - if (oldSingleRecordKey != null && - _selectedGroupKeys.contains(oldSingleRecordKey)) { - _selectedGroupKeys.remove(oldSingleRecordKey); - _selectedGroupKeys.add(mergedRecord.groupKey); + final mergedItems = + MergeService.getMixedList(allRecords, _mergeSettings); + + setState(() { + _displayItems.clear(); + _displayItems.addAll(mergedItems); + + _selectedGroupKeys.clear(); + for (final item in _displayItems) { + if (item is MergedTrainRecord) { + if (item.records + .any((r) => selectedRecordIds.contains(r.uniqueId))) { + _selectedGroupKeys.add(item.groupKey); + } + } else if (item is TrainRecord) { + if (selectedRecordIds.contains(item.uniqueId)) { + _selectedGroupKeys.add("single:${item.uniqueId}"); + } } - } else { - _displayItems.insert(0, newRecord); } }); @@ -765,23 +748,16 @@ class RealtimeScreenState extends State { _adjustMapViewToSelectedGroups(); } - print( - 'addNewRecord - 检查滚动条件: _isAtTop=$_isAtTop, hasClients=${_scrollController.hasClients}, 当前位置: ${_scrollController.position.pixels}'); if (_isAtTop && _scrollController.hasClients) { WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && _scrollController.hasClients) { final newMaxScrollExtent = _scrollController.position.maxScrollExtent; - print( - 'addNewRecord - 执行滚动到底部, maxScrollExtent: $newMaxScrollExtent'); + _scrollController.jumpTo(newMaxScrollExtent); - print( - 'addNewRecord - 滚动完成,新位置: ${_scrollController.position.pixels}'); } }); - } else { - print('addNewRecord - 不执行滚动,条件不满足'); - } + } else {} } } catch (e) {} } diff --git a/pubspec.yaml b/pubspec.yaml index 12e0021..106a386 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.6.0-flutter+60 +version: 0.6.1-flutter+61 environment: sdk: ^3.5.4