From a47c6a574506d63e467ee6afca49ad697a33bf9e Mon Sep 17 00:00:00 2001 From: Nedifinita Date: Sun, 23 Nov 2025 21:43:47 +0800 Subject: [PATCH] refactor --- README.md | 2 + lib/main.dart | 2 - lib/models/map_state.dart | 2 +- lib/screens/history_screen.dart | 16 ----- lib/screens/main_screen.dart | 15 ++-- lib/screens/map_screen.dart | 26 +++---- lib/screens/map_webview_screen.dart | 4 +- lib/screens/realtime_screen.dart | 9 ++- lib/screens/settings_screen.dart | 63 ++++++++--------- lib/services/background_service.dart | 5 +- lib/services/ble_service.dart | 11 ++- lib/services/database_service.dart | 10 ++- lib/services/loco_type_service.dart | 1 - lib/services/merge_service.dart | 98 +------------------------- lib/services/notification_service.dart | 4 +- lib/services/rtl_tcp_service.dart | 7 +- lib/themes/app_theme.dart | 18 +++-- lib/util/loco_info_util.dart | 1 - lib/util/train_type_util.dart | 1 - pubspec.yaml | 2 +- 20 files changed, 88 insertions(+), 209 deletions(-) diff --git a/README.md b/README.md index bb3561d..10307f4 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ LBJ Console 是一款应用程序,用于通过 BLE 从 [SX1276_Receive_LBJ](ht [android](https://github.com/undef-i/LBJ_Console/tree/android) 分支包含项目早期基于 Android 平台的实现代码,已实现基本功能,现已停止开发。 +本项目为个人业余项目,代码质量和实现细节可能不尽如人意,敬请见谅。 + ## 数据文件 LBJ Console 依赖以下数据文件,位于 `assets` 目录,用于支持机车配属和车次信息的展示: diff --git a/lib/main.dart b/lib/main.dart index 39937ec..2856ec2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,9 +3,7 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:lbjconsole/screens/main_screen.dart'; import 'package:lbjconsole/util/train_type_util.dart'; import 'package:lbjconsole/util/loco_info_util.dart'; -import 'package:lbjconsole/util/loco_type_util.dart'; import 'package:lbjconsole/services/loco_type_service.dart'; -import 'package:lbjconsole/services/database_service.dart'; import 'package:lbjconsole/services/background_service.dart'; void main() async { diff --git a/lib/models/map_state.dart b/lib/models/map_state.dart index e695fe0..0e88ae7 100644 --- a/lib/models/map_state.dart +++ b/lib/models/map_state.dart @@ -45,7 +45,7 @@ class MapState { @override String toString() { - return 'MapState(zoom: ' + zoom.toString() + ', centerLat: ' + centerLat.toString() + ', centerLng: ' + centerLng.toString() + ', bearing: ' + bearing.toString() + ')'; + return 'MapState(zoom: $zoom, centerLat: $centerLat, centerLng: $centerLng, bearing: $bearing)'; } @override diff --git a/lib/screens/history_screen.dart b/lib/screens/history_screen.dart index 0d82f9d..cd998ff 100644 --- a/lib/screens/history_screen.dart +++ b/lib/screens/history_screen.dart @@ -340,22 +340,6 @@ class HistoryScreenState extends State { } catch (e) {} } - String _getGroupKeyForRecord(TrainRecord record, MergeSettings settings) { - switch (settings.groupBy) { - case GroupBy.trainOnly: - return record.train.trim(); - case GroupBy.locoOnly: - return record.loco.trim(); - case GroupBy.trainAndLoco: - return '${record.train.trim()}-${record.loco.trim()}'; - case GroupBy.trainOrLoco: - final train = record.train.trim(); - if (train.isNotEmpty) return train; - final loco = record.loco.trim(); - if (loco.isNotEmpty) return loco; - return ''; - } - } bool _hasDataChanged(List newItems) { if (_displayItems.length != newItems.length) return true; diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index 7413aae..69c73da 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -3,8 +3,6 @@ import 'package:flutter/services.dart'; import 'dart:async'; import 'dart:developer' as developer; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; -import 'package:lbjconsole/models/merged_record.dart'; -import 'package:lbjconsole/models/train_record.dart'; import 'package:lbjconsole/screens/history_screen.dart'; import 'package:lbjconsole/screens/map_screen.dart'; import 'package:lbjconsole/screens/map_webview_screen.dart'; @@ -307,17 +305,17 @@ class _MainScreenState extends State with WidgetsBindingObserver { developer.log('rtl_tcp: setup_listener'); _settingsSubscription = DatabaseService.instance.onSettingsChanged((settings) { - developer.log('rtl_tcp: settings_changed: enabled=${(settings?['rtlTcpEnabled'] ?? 0) == 1}, host=${settings?['rtlTcpHost']?.toString() ?? '127.0.0.1'}, port=${settings?['rtlTcpPort']?.toString() ?? '14423'}'); + developer.log('rtl_tcp: settings_changed: enabled=${(settings['rtlTcpEnabled'] ?? 0) == 1}, host=${settings['rtlTcpHost']?.toString() ?? '127.0.0.1'}, port=${settings['rtlTcpPort']?.toString() ?? '14423'}'); if (mounted) { - final rtlTcpEnabled = (settings?['rtlTcpEnabled'] ?? 0) == 1; + final rtlTcpEnabled = (settings['rtlTcpEnabled'] ?? 0) == 1; if (rtlTcpEnabled != _rtlTcpEnabled) { setState(() { _rtlTcpEnabled = rtlTcpEnabled; }); if (rtlTcpEnabled) { - final host = settings?['rtlTcpHost']?.toString() ?? '127.0.0.1'; - final port = settings?['rtlTcpPort']?.toString() ?? '14423'; + final host = settings['rtlTcpHost']?.toString() ?? '127.0.0.1'; + final port = settings['rtlTcpPort']?.toString() ?? '14423'; _connectToRtlTcp(host, port); } else { _rtlTcpConnectionSubscription?.cancel(); @@ -661,11 +659,12 @@ class _PixelPerfectBluetoothDialogState Future _startScan() async { if (_scanState == _ScanState.scanning) return; - if (mounted) + if (mounted) { setState(() { _devices.clear(); _scanState = _ScanState.scanning; }); + } await widget.bleService.startScan( timeout: const Duration(seconds: 8), onScanResults: (devices) { @@ -784,7 +783,7 @@ class _PixelPerfectBluetoothDialogState .titleMedium ?.copyWith(fontWeight: FontWeight.bold)), const SizedBox(height: 8), - Text('$currentAddress', + Text(currentAddress, style: TextStyle(color: isConnected ? Colors.green : Colors.grey)), const SizedBox(height: 16), if (_lastReceivedTime != null && isConnected) ...[ diff --git a/lib/screens/map_screen.dart b/lib/screens/map_screen.dart index 3460e74..4cd8b5a 100644 --- a/lib/screens/map_screen.dart +++ b/lib/screens/map_screen.dart @@ -1,5 +1,5 @@ import 'dart:async'; -import 'dart:math' show sin, cos, sqrt, atan2, pi; +import 'dart:math' show sin, cos, sqrt, atan2; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; @@ -26,19 +26,19 @@ class _MapScreenState extends State { double _currentRotation = 0.0; bool _isMapInitialized = false; - bool _isFollowingLocation = false; + final bool _isFollowingLocation = false; bool _isLocationPermissionGranted = false; Timer? _locationTimer; String _selectedTimeFilter = 'unlimited'; final Map _timeFilterOptions = { 'unlimited': Duration.zero, - '1hour': Duration(hours: 1), - '6hours': Duration(hours: 6), - '12hours': Duration(hours: 12), - '24hours': Duration(hours: 24), - '7days': Duration(days: 7), - '30days': Duration(days: 30), + '1hour': const Duration(hours: 1), + '6hours': const Duration(hours: 6), + '12hours': const Duration(hours: 12), + '24hours': const Duration(hours: 24), + '7days': const Duration(days: 7), + '30days': const Duration(days: 30), }; @override @@ -81,8 +81,8 @@ class _MapScreenState extends State { if (lat == 39.9042 && lon == 116.4074) { } else if (lat == 0.0 && lon == 0.0) { } else { - final beijingLat = 39.9042; - final beijingLon = 116.4074; + const beijingLat = 39.9042; + const beijingLon = 116.4074; final distance = _calculateDistance(lat, lon, beijingLat, beijingLon); @@ -411,7 +411,7 @@ class _MapScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( - color: Colors.black.withOpacity(0.8), + color: Colors.black.withValues(alpha: 0.8), borderRadius: BorderRadius.circular(3), ), child: Text( @@ -572,8 +572,8 @@ class _MapScreenState extends State { decoration: BoxDecoration( color: Theme.of(context) .colorScheme - .surfaceVariant - .withOpacity(0.3), + .surfaceContainerHighest + .withValues(alpha: 0.3), borderRadius: BorderRadius.circular(16), ), child: Padding( diff --git a/lib/screens/map_webview_screen.dart b/lib/screens/map_webview_screen.dart index d86967b..bbe9dbf 100644 --- a/lib/screens/map_webview_screen.dart +++ b/lib/screens/map_webview_screen.dart @@ -32,7 +32,7 @@ class MapWebViewScreenState extends State double _currentRotation = 0.0; LatLng? _currentLocation; LatLng? _lastTrainLocation; - bool _isDataLoaded = false; + final bool _isDataLoaded = false; final Completer _webViewReadyCompleter = Completer(); @override @@ -299,7 +299,7 @@ class MapWebViewScreenState extends State _updateTrainMarkers(); } }); - } catch (e, stackTrace) { + } catch (e) { setState(() { _isLoading = false; }); diff --git a/lib/screens/realtime_screen.dart b/lib/screens/realtime_screen.dart index 41dbfed..e610528 100644 --- a/lib/screens/realtime_screen.dart +++ b/lib/screens/realtime_screen.dart @@ -30,7 +30,7 @@ class RealtimeScreenState extends State { List _selectedGroupRoute = []; List _mapMarkers = []; bool _showMap = true; - Set _selectedGroupKeys = {}; + final Set _selectedGroupKeys = {}; LatLng? _userLocation; bool _isLocationPermissionGranted = false; Timer? _locationTimer; @@ -376,8 +376,7 @@ class RealtimeScreenState extends State { } LatLng? _parsePositionFromRecord(TrainRecord record) { - if (record.positionInfo == null || - record.positionInfo.isEmpty || + if (record.positionInfo.isEmpty || record.positionInfo == '') { return null; } @@ -916,8 +915,8 @@ class RealtimeScreenState extends State { flex: 1, child: FlutterMap( mapController: _mapController, - options: MapOptions( - initialCenter: const LatLng(35.8617, 104.1954), + options: const MapOptions( + initialCenter: LatLng(35.8617, 104.1954), initialZoom: 2.0, ), children: [ diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 24a6129..ecd8f7e 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -4,17 +4,13 @@ import 'dart:io'; import 'package:lbjconsole/models/merged_record.dart'; import 'package:lbjconsole/services/database_service.dart'; -import 'package:lbjconsole/services/ble_service.dart'; import 'package:lbjconsole/services/background_service.dart'; import 'package:lbjconsole/themes/app_theme.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:file_picker/file_picker.dart'; -import 'package:path/path.dart' as path; -import 'package:path_provider/path_provider.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:share_plus/share_plus.dart'; -import 'package:cross_file/cross_file.dart'; class SettingsScreen extends StatefulWidget { final VoidCallback? onSettingsChanged; @@ -73,14 +69,14 @@ class _SettingsScreenState extends State { Icon(Icons.wifi, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 12), - Text('RTL-TCP 源', style: AppTheme.titleMedium), + const Text('RTL-TCP 源', style: AppTheme.titleMedium), ], ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('启用 RTL-TCP 源', style: AppTheme.bodyLarge), @@ -94,7 +90,7 @@ class _SettingsScreenState extends State { }); _saveSettings(); }, - activeColor: Theme.of(context).colorScheme.primary, + activeThumbColor: Theme.of(context).colorScheme.primary, ), ], ), @@ -273,7 +269,7 @@ class _SettingsScreenState extends State { Icon(Icons.bluetooth, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 12), - Text('蓝牙设备', style: AppTheme.titleMedium), + const Text('蓝牙设备', style: AppTheme.titleMedium), ], ), const SizedBox(height: 16), @@ -329,14 +325,14 @@ class _SettingsScreenState extends State { Icon(Icons.settings, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 12), - Text('应用设置', style: AppTheme.titleMedium), + const Text('应用设置', style: AppTheme.titleMedium), ], ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('后台保活服务', style: AppTheme.bodyLarge), @@ -356,7 +352,7 @@ class _SettingsScreenState extends State { await BackgroundService.stopService(); } }, - activeColor: Theme.of(context).colorScheme.primary, + activeThumbColor: Theme.of(context).colorScheme.primary, ), ], ), @@ -364,7 +360,7 @@ class _SettingsScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('通知服务', style: AppTheme.bodyLarge), @@ -378,7 +374,7 @@ class _SettingsScreenState extends State { }); _saveSettings(); }, - activeColor: Theme.of(context).colorScheme.primary, + activeThumbColor: Theme.of(context).colorScheme.primary, ), ], ), @@ -386,7 +382,7 @@ class _SettingsScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('地图组件类型', style: AppTheme.bodyLarge), @@ -394,7 +390,7 @@ class _SettingsScreenState extends State { ), DropdownButton( value: _mapType, - items: [ + items: const [ DropdownMenuItem( value: 'webview', child: Text('矢量铁路地图', style: AppTheme.bodyMedium), @@ -422,7 +418,7 @@ class _SettingsScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('隐藏只有时间有效的记录', style: AppTheme.bodyLarge), @@ -436,7 +432,7 @@ class _SettingsScreenState extends State { }); _saveSettings(); }, - activeColor: Theme.of(context).colorScheme.primary, + activeThumbColor: Theme.of(context).colorScheme.primary, ), ], ), @@ -463,14 +459,14 @@ class _SettingsScreenState extends State { Icon(Icons.merge_type, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 12), - Text('记录合并', style: AppTheme.titleMedium), + const Text('记录合并', style: AppTheme.titleMedium), ], ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('启用记录合并', style: AppTheme.bodyLarge), @@ -484,7 +480,7 @@ class _SettingsScreenState extends State { }); _saveSettings(); }, - activeColor: Theme.of(context).colorScheme.primary, + activeThumbColor: Theme.of(context).colorScheme.primary, ), ], ), @@ -494,11 +490,11 @@ class _SettingsScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), - Text('分组方式', style: AppTheme.bodyLarge), + const Text('分组方式', style: AppTheme.bodyLarge), const SizedBox(height: 8), DropdownButtonFormField( - value: _groupBy, - items: [ + initialValue: _groupBy, + items: const [ DropdownMenuItem( value: GroupBy.trainOnly, child: Text('仅车次号', style: AppTheme.bodyMedium)), @@ -532,11 +528,11 @@ class _SettingsScreenState extends State { style: AppTheme.bodyMedium, ), const SizedBox(height: 16), - Text('时间窗口', style: AppTheme.bodyLarge), + const Text('时间窗口', style: AppTheme.bodyLarge), const SizedBox(height: 8), DropdownButtonFormField( - value: _timeWindow, - items: [ + initialValue: _timeWindow, + items: const [ DropdownMenuItem( value: TimeWindow.oneHour, child: Text('1小时内', style: AppTheme.bodyMedium)), @@ -579,7 +575,7 @@ class _SettingsScreenState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( + const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('隐藏不可分组记录', style: AppTheme.bodyLarge), @@ -593,7 +589,7 @@ class _SettingsScreenState extends State { }); _saveSettings(); }, - activeColor: Theme.of(context).colorScheme.primary, + activeThumbColor: Theme.of(context).colorScheme.primary, ), ], ), @@ -623,7 +619,7 @@ class _SettingsScreenState extends State { Icon(Icons.storage, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 12), - Text('数据管理', style: AppTheme.titleMedium), + const Text('数据管理', style: AppTheme.titleMedium), ], ), const SizedBox(height: 16), @@ -705,7 +701,7 @@ class _SettingsScreenState extends State { ], ), ), - Icon( + const Icon( Icons.chevron_right, color: Colors.white54, size: 20, @@ -760,7 +756,6 @@ class _SettingsScreenState extends State { if (exportedPath != null) { final file = File(exportedPath); - final fileName = file.path.split(Platform.pathSeparator).last; await Share.shareXFiles( [XFile(file.path)], @@ -954,11 +949,11 @@ class _SettingsScreenState extends State { children: [ Icon(Icons.info, color: Theme.of(context).colorScheme.primary), const SizedBox(width: 12), - Text('关于', style: AppTheme.titleMedium), + const Text('关于', style: AppTheme.titleMedium), ], ), const SizedBox(height: 16), - Text('LBJ Console', style: AppTheme.titleMedium), + const Text('LBJ Console', style: AppTheme.titleMedium), const SizedBox(height: 8), FutureBuilder( future: _getAppVersion(), @@ -979,7 +974,7 @@ class _SettingsScreenState extends State { await launchUrl(url); } }, - child: Text( + child: const Text( 'https://github.com/undef-i/LBJConsole', style: AppTheme.caption, ), diff --git a/lib/services/background_service.dart b/lib/services/background_service.dart index 5c76a3a..82e6735 100644 --- a/lib/services/background_service.dart +++ b/lib/services/background_service.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'dart:ui'; import 'package:flutter_background_service/flutter_background_service.dart'; -import 'package:flutter_background_service_android/flutter_background_service_android.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:lbjconsole/services/ble_service.dart'; @@ -107,7 +106,7 @@ class BackgroundService { _notificationId, 'LBJ Console', '蓝牙连接监控中', - NotificationDetails( + const NotificationDetails( android: AndroidNotificationDetails( _notificationChannelId, _notificationChannelName, @@ -146,7 +145,7 @@ class BackgroundService { _notificationId, 'LBJ Console', isConnected ? '蓝牙已连接 - $deviceStatus' : '蓝牙未连接 - 自动重连中', - NotificationDetails( + const NotificationDetails( android: AndroidNotificationDetails( _notificationChannelId, _notificationChannelName, diff --git a/lib/services/ble_service.dart b/lib/services/ble_service.dart index 4bf41b7..e6e8e29 100644 --- a/lib/services/ble_service.dart +++ b/lib/services/ble_service.dart @@ -145,7 +145,9 @@ class BLEService { if (isConnected || _isConnecting || _isManualDisconnect || - _isAutoConnectBlocked) return; + _isAutoConnectBlocked) { + return; + } for (var device in allFoundDevices) { if (_shouldAutoConnectTo(device)) { @@ -168,10 +170,13 @@ class BLEService { final deviceAddress = device.remoteId.str; if (_targetDeviceName.isNotEmpty && - deviceName.toLowerCase() == _targetDeviceName.toLowerCase()) + deviceName.toLowerCase() == _targetDeviceName.toLowerCase()) { return true; + } if (_lastKnownDeviceAddress != null && - _lastKnownDeviceAddress == deviceAddress) return true; + _lastKnownDeviceAddress == deviceAddress) { + return true; + } return false; } diff --git a/lib/services/database_service.dart b/lib/services/database_service.dart index 6e66947..d009b62 100644 --- a/lib/services/database_service.dart +++ b/lib/services/database_service.dart @@ -27,7 +27,7 @@ class DatabaseService { } _database = await _initDatabase(); return _database!; - } catch (e, stackTrace) { + } catch (e) { rethrow; } } @@ -38,8 +38,6 @@ class DatabaseService { return false; } - final db = await database; - final result = await db.rawQuery('SELECT 1'); return true; } catch (e) { return false; @@ -59,7 +57,7 @@ class DatabaseService { ); return db; - } catch (e, stackTrace) { + } catch (e) { rethrow; } } @@ -206,7 +204,7 @@ class DatabaseService { final records = result.map((json) => TrainRecord.fromDatabaseJson(json)).toList(); return records; - } catch (e, stackTrace) { + } catch (e) { rethrow; } } @@ -239,7 +237,7 @@ class DatabaseService { final records = result.map((json) => TrainRecord.fromDatabaseJson(json)).toList(); return records; - } catch (e, stackTrace) { + } catch (e) { rethrow; } } diff --git a/lib/services/loco_type_service.dart b/lib/services/loco_type_service.dart index d4e60fb..e3bb691 100644 --- a/lib/services/loco_type_service.dart +++ b/lib/services/loco_type_service.dart @@ -1,4 +1,3 @@ -import 'package:lbjconsole/util/loco_type_util.dart'; class LocoTypeService { static final LocoTypeService _instance = LocoTypeService._internal(); diff --git a/lib/services/merge_service.dart b/lib/services/merge_service.dart index 2be92de..6c90395 100644 --- a/lib/services/merge_service.dart +++ b/lib/services/merge_service.dart @@ -111,7 +111,7 @@ class MergeService { } }); - final reusedRecords = _reuseDiscardedRecords( + _reuseDiscardedRecords( discardedRecords, mergedRecordIds, settings.groupBy); final singleRecords = filteredRecords @@ -283,100 +283,4 @@ class MergeService { return result; } - static List _groupByTrainOrLoco(List records) { - final List mergedRecords = []; - final List singleRecords = []; - final Set usedRecordIds = {}; - - for (int i = 0; i < records.length; i++) { - final record = records[i]; - if (usedRecordIds.contains(record.uniqueId)) continue; - - final group = [record]; - - for (int j = i + 1; j < records.length; j++) { - final otherRecord = records[j]; - if (usedRecordIds.contains(otherRecord.uniqueId)) continue; - - final recordTrain = record.train.trim(); - final otherTrain = otherRecord.train.trim(); - final recordLoco = record.loco.trim(); - final otherLoco = otherRecord.loco.trim(); - - final trainMatch = recordTrain.isNotEmpty && - recordTrain != "" && - !recordTrain.contains("-----") && - otherTrain.isNotEmpty && - otherTrain != "" && - !otherTrain.contains("-----") && - recordTrain == otherTrain; - - final locoMatch = recordLoco.isNotEmpty && - recordLoco != "" && - otherLoco.isNotEmpty && - otherLoco != "" && - recordLoco == otherLoco; - - final bothTrainEmpty = (recordTrain.isEmpty || - recordTrain == "" || - recordTrain.contains("----")) && - (otherTrain.isEmpty || - otherTrain == "" || - otherTrain.contains("----")); - - if (trainMatch || locoMatch || (bothTrainEmpty && locoMatch)) { - group.add(otherRecord); - } - } - - if (group.length >= 2) { - for (final record in group) { - usedRecordIds.add(record.uniqueId); - } - - final firstRecord = group.first; - final train = firstRecord.train.trim(); - final loco = firstRecord.loco.trim(); - String uniqueGroupKey; - - if (train.isNotEmpty && - train != "" && - !train.contains("-----") && - loco.isNotEmpty && - loco != "") { - uniqueGroupKey = "train_or_loco:${train}_$loco"; - } else if (train.isNotEmpty && - train != "" && - !train.contains("-----")) { - uniqueGroupKey = "train_or_loco:train:$train"; - } else if (loco.isNotEmpty && loco != "") { - uniqueGroupKey = "train_or_loco:loco:$loco"; - } else { - uniqueGroupKey = "train_or_loco:group_${mergedRecords.length}"; - } - - mergedRecords.add(MergedTrainRecord( - groupKey: uniqueGroupKey, - records: group, - latestRecord: group.first, - )); - } else { - singleRecords.add(record); - usedRecordIds.add(record.uniqueId); - } - } - - final List result = [...mergedRecords, ...singleRecords]; - result.sort((a, b) { - final aTime = a is MergedTrainRecord - ? a.latestRecord.receivedTimestamp - : (a as TrainRecord).receivedTimestamp; - final bTime = b is MergedTrainRecord - ? b.latestRecord.receivedTimestamp - : (b as TrainRecord).receivedTimestamp; - return bTime.compareTo(aTime); - }); - - return result; - } } diff --git a/lib/services/notification_service.dart b/lib/services/notification_service.dart index f9adc17..8ccd464 100644 --- a/lib/services/notification_service.dart +++ b/lib/services/notification_service.dart @@ -20,7 +20,7 @@ class NotificationService { const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); - final InitializationSettings initializationSettings = + const InitializationSettings initializationSettings = InitializationSettings( android: initializationSettingsAndroid, ); @@ -61,7 +61,7 @@ class NotificationService { return; } - final String title = '列车信息'; + const String title = '列车信息'; final String body = _buildNotificationContent(record); final AndroidNotificationDetails androidPlatformChannelSpecifics = diff --git a/lib/services/rtl_tcp_service.dart b/lib/services/rtl_tcp_service.dart index ae9b2f7..fdfb2bf 100644 --- a/lib/services/rtl_tcp_service.dart +++ b/lib/services/rtl_tcp_service.dart @@ -149,8 +149,9 @@ class _LbJState { break; case _lbjSyncAddr: - if (numeric.length >= 5) + if (numeric.length >= 5) { time = "${numeric.substring(1, 3)}:${numeric.substring(3, 5)}"; + } break; } } @@ -167,11 +168,11 @@ class _LbJState { String gpsPosition = ""; if (posLatDeg.isNotEmpty && posLatMin.isNotEmpty) { - gpsPosition = "${posLatDeg}°${posLatMin}′"; + gpsPosition = "$posLatDeg°$posLatMin′"; } if (posLonDeg.isNotEmpty && posLonMin.isNotEmpty) { gpsPosition += - (gpsPosition.isEmpty ? "" : " ") + "${posLonDeg}°${posLonMin}′"; + "${gpsPosition.isEmpty ? "" : " "}$posLonDeg°$posLonMin′"; } String kmPosition = positionKm.replaceAll(' ', ''); diff --git a/lib/themes/app_theme.dart b/lib/themes/app_theme.dart index 3c09907..7ac9a26 100644 --- a/lib/themes/app_theme.dart +++ b/lib/themes/app_theme.dart @@ -9,13 +9,11 @@ class AppTheme { canvasColor: Colors.black, cardColor: const Color(0xFF121212), primaryColor: Colors.blue, - colorScheme: ColorScheme.dark( + colorScheme: const ColorScheme.dark( primary: Colors.blue, secondary: Colors.blueAccent, - surface: const Color(0xFF121212), - background: Colors.black, + surface: Color(0xFF121212), onSurface: Colors.white, - onBackground: Colors.white, ), appBarTheme: const AppBarTheme( backgroundColor: Colors.black, @@ -67,16 +65,16 @@ class AppTheme { thickness: 1, ), switchTheme: SwitchThemeData( - thumbColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.selected)) { + thumbColor: WidgetStateProperty.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { return Colors.blue; } return Colors.grey; }), - trackColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.selected)) { + trackColor: WidgetStateProperty.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { return Colors.blue.withOpacity(0.5); } return Colors.grey.withOpacity(0.5); diff --git a/lib/util/loco_info_util.dart b/lib/util/loco_info_util.dart index abe117c..0e6b6cd 100644 --- a/lib/util/loco_info_util.dart +++ b/lib/util/loco_info_util.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:flutter/services.dart'; class LocoInfoUtil { diff --git a/lib/util/train_type_util.dart b/lib/util/train_type_util.dart index 4a8e88c..80c044e 100644 --- a/lib/util/train_type_util.dart +++ b/lib/util/train_type_util.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:flutter/services.dart'; class TrainTypeUtil { diff --git a/pubspec.yaml b/pubspec.yaml index ac44c27..bc6ab81 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.8.0-flutter+80 +version: 0.8.1-flutter+81 environment: sdk: ^3.5.4