feat: add the function to hide records that are only valid for time.
This commit is contained in:
@@ -60,6 +60,10 @@ class HistoryScreenState extends State<HistoryScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> reloadRecords() async {
|
||||
await loadRecords(scrollToTop: false);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -93,7 +97,71 @@ class HistoryScreenState extends State<HistoryScreen> {
|
||||
final allRecords = await DatabaseService.instance.getAllRecords();
|
||||
final settingsMap = await DatabaseService.instance.getAllSettings() ?? {};
|
||||
_mergeSettings = MergeSettings.fromMap(settingsMap);
|
||||
final items = MergeService.getMixedList(allRecords, _mergeSettings);
|
||||
|
||||
List<TrainRecord> filteredRecords = allRecords;
|
||||
if ((settingsMap['hideTimeOnlyRecords'] ?? 0) == 1) {
|
||||
int hiddenCount = 0;
|
||||
int shownCount = 0;
|
||||
|
||||
filteredRecords = allRecords.where((record) {
|
||||
bool isFieldMeaningful(String field) {
|
||||
if (field.isEmpty) return false;
|
||||
String cleaned = field.replaceAll('<NUL>', '').trim();
|
||||
if (cleaned.isEmpty) return false;
|
||||
if (cleaned.runes
|
||||
.every((r) => r == '*'.runes.first || r == ' '.runes.first))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
final hasTrainNumber = isFieldMeaningful(record.fullTrainNumber) &&
|
||||
!record.fullTrainNumber.contains("-----");
|
||||
|
||||
final hasDirection = record.direction == 1 || record.direction == 3;
|
||||
|
||||
final hasLocoInfo = isFieldMeaningful(record.locoType) ||
|
||||
isFieldMeaningful(record.loco);
|
||||
|
||||
final hasRoute = isFieldMeaningful(record.route);
|
||||
|
||||
final hasPosition = isFieldMeaningful(record.position);
|
||||
|
||||
final hasSpeed =
|
||||
isFieldMeaningful(record.speed) && record.speed != "NUL";
|
||||
|
||||
final hasPositionInfo = isFieldMeaningful(record.positionInfo);
|
||||
|
||||
final hasTrainType =
|
||||
isFieldMeaningful(record.trainType) && record.trainType != "未知";
|
||||
|
||||
final hasLbjClass =
|
||||
isFieldMeaningful(record.lbjClass) && record.lbjClass != "NA";
|
||||
|
||||
final hasTrain = isFieldMeaningful(record.train) &&
|
||||
!record.train.contains("-----");
|
||||
|
||||
final shouldShow = hasTrainNumber ||
|
||||
hasDirection ||
|
||||
hasLocoInfo ||
|
||||
hasRoute ||
|
||||
hasPosition ||
|
||||
hasSpeed ||
|
||||
hasPositionInfo ||
|
||||
hasTrainType ||
|
||||
hasLbjClass ||
|
||||
hasTrain;
|
||||
|
||||
if (!shouldShow) {
|
||||
hiddenCount++;
|
||||
} else {
|
||||
shownCount++;
|
||||
}
|
||||
|
||||
return shouldShow;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
final items = MergeService.getMixedList(filteredRecords, _mergeSettings);
|
||||
|
||||
if (mounted) {
|
||||
final hasDataChanged = _hasDataChanged(items);
|
||||
@@ -124,6 +192,58 @@ class HistoryScreenState extends State<HistoryScreen> {
|
||||
final settingsMap = await DatabaseService.instance.getAllSettings() ?? {};
|
||||
_mergeSettings = MergeSettings.fromMap(settingsMap);
|
||||
|
||||
if ((settingsMap['hideTimeOnlyRecords'] ?? 0) == 1) {
|
||||
bool isFieldMeaningful(String field) {
|
||||
if (field.isEmpty) return false;
|
||||
String cleaned = field.replaceAll('<NUL>', '').trim();
|
||||
if (cleaned.isEmpty) return false;
|
||||
if (cleaned.runes
|
||||
.every((r) => r == '*'.runes.first || r == ' '.runes.first))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
final hasTrainNumber = isFieldMeaningful(newRecord.fullTrainNumber) &&
|
||||
!newRecord.fullTrainNumber.contains("-----");
|
||||
|
||||
final hasDirection =
|
||||
newRecord.direction == 1 || newRecord.direction == 3;
|
||||
|
||||
final hasLocoInfo = isFieldMeaningful(newRecord.locoType) ||
|
||||
isFieldMeaningful(newRecord.loco);
|
||||
|
||||
final hasRoute = isFieldMeaningful(newRecord.route);
|
||||
|
||||
final hasPosition = isFieldMeaningful(newRecord.position);
|
||||
|
||||
final hasSpeed =
|
||||
isFieldMeaningful(newRecord.speed) && newRecord.speed != "NUL";
|
||||
|
||||
final hasPositionInfo = isFieldMeaningful(newRecord.positionInfo);
|
||||
|
||||
final hasTrainType = isFieldMeaningful(newRecord.trainType) &&
|
||||
newRecord.trainType != "未知";
|
||||
|
||||
final hasLbjClass =
|
||||
isFieldMeaningful(newRecord.lbjClass) && newRecord.lbjClass != "NA";
|
||||
|
||||
final hasTrain = isFieldMeaningful(newRecord.train) &&
|
||||
!newRecord.train.contains("-----");
|
||||
|
||||
if (!hasTrainNumber &&
|
||||
!hasDirection &&
|
||||
!hasLocoInfo &&
|
||||
!hasRoute &&
|
||||
!hasPosition &&
|
||||
!hasSpeed &&
|
||||
!hasPositionInfo &&
|
||||
!hasTrainType &&
|
||||
!hasLbjClass &&
|
||||
!hasTrain) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final isNewRecord = !_displayItems.any((item) {
|
||||
if (item is TrainRecord) {
|
||||
return item.uniqueId == newRecord.uniqueId;
|
||||
@@ -624,7 +744,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
||||
|
||||
final hasTrainNumber = record.fullTrainNumber.isNotEmpty;
|
||||
final hasDirection = record.direction == 1 || record.direction == 3;
|
||||
final hasLocoInfo = formattedLocoInfo.isNotEmpty && formattedLocoInfo != "<NUL>";
|
||||
final hasLocoInfo =
|
||||
formattedLocoInfo.isNotEmpty && formattedLocoInfo != "<NUL>";
|
||||
final shouldShowTrainRow = hasTrainNumber || hasDirection || hasLocoInfo;
|
||||
|
||||
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
@@ -661,7 +782,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white),
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
if (hasTrainNumber && hasDirection) const SizedBox(width: 6),
|
||||
if (hasTrainNumber && hasDirection)
|
||||
const SizedBox(width: 6),
|
||||
if (hasDirection)
|
||||
Container(
|
||||
width: 20,
|
||||
|
||||
@@ -397,7 +397,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
selectedIndex: _currentIndex,
|
||||
onDestinationSelected: (index) {
|
||||
if (_currentIndex == 2 && index == 0) {
|
||||
_historyScreenKey.currentState?.loadRecords();
|
||||
_historyScreenKey.currentState?.reloadRecords();
|
||||
}
|
||||
setState(() {
|
||||
if (_isHistoryEditMode) _isHistoryEditMode = false;
|
||||
|
||||
@@ -32,6 +32,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
bool _notificationsEnabled = true;
|
||||
int _recordCount = 0;
|
||||
bool _mergeRecordsEnabled = false;
|
||||
bool _hideTimeOnlyRecords = false;
|
||||
GroupBy _groupBy = GroupBy.trainAndLoco;
|
||||
TimeWindow _timeWindow = TimeWindow.unlimited;
|
||||
|
||||
@@ -61,6 +62,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
(settingsMap['backgroundServiceEnabled'] ?? 0) == 1;
|
||||
_notificationsEnabled = (settingsMap['notificationEnabled'] ?? 1) == 1;
|
||||
_mergeRecordsEnabled = settings.enabled;
|
||||
_hideTimeOnlyRecords = (settingsMap['hideTimeOnlyRecords'] ?? 0) == 1;
|
||||
_groupBy = settings.groupBy;
|
||||
_timeWindow = settings.timeWindow;
|
||||
});
|
||||
@@ -82,6 +84,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
'backgroundServiceEnabled': _backgroundServiceEnabled ? 1 : 0,
|
||||
'notificationEnabled': _notificationsEnabled ? 1 : 0,
|
||||
'mergeRecordsEnabled': _mergeRecordsEnabled ? 1 : 0,
|
||||
'hideTimeOnlyRecords': _hideTimeOnlyRecords ? 1 : 0,
|
||||
'groupBy': _groupBy.name,
|
||||
'timeWindow': _timeWindow.name,
|
||||
});
|
||||
@@ -236,6 +239,29 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('隐藏只有时间有效的记录', style: AppTheme.bodyLarge),
|
||||
Text('不显示只有时间信息的记录', style: AppTheme.caption),
|
||||
],
|
||||
),
|
||||
Switch(
|
||||
value: _hideTimeOnlyRecords,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_hideTimeOnlyRecords = value;
|
||||
});
|
||||
_saveSettings();
|
||||
},
|
||||
activeColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -13,7 +13,7 @@ class DatabaseService {
|
||||
DatabaseService._internal();
|
||||
|
||||
static const String _databaseName = 'train_database';
|
||||
static const _databaseVersion = 1;
|
||||
static const _databaseVersion = 2;
|
||||
|
||||
static const String trainRecordsTable = 'train_records';
|
||||
static const String appSettingsTable = 'app_settings';
|
||||
@@ -34,9 +34,17 @@ class DatabaseService {
|
||||
path,
|
||||
version: _databaseVersion,
|
||||
onCreate: _onCreate,
|
||||
onUpgrade: _onUpgrade,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
|
||||
if (oldVersion < 2) {
|
||||
await db.execute(
|
||||
'ALTER TABLE $appSettingsTable ADD COLUMN hideTimeOnlyRecords INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onCreate(Database db, int version) async {
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS $trainRecordsTable (
|
||||
@@ -79,6 +87,7 @@ class DatabaseService {
|
||||
backgroundServiceEnabled INTEGER NOT NULL DEFAULT 0,
|
||||
notificationEnabled INTEGER NOT NULL DEFAULT 0,
|
||||
mergeRecordsEnabled INTEGER NOT NULL DEFAULT 0,
|
||||
hideTimeOnlyRecords INTEGER NOT NULL DEFAULT 0,
|
||||
groupBy TEXT NOT NULL DEFAULT 'trainAndLoco',
|
||||
timeWindow TEXT NOT NULL DEFAULT 'unlimited'
|
||||
)
|
||||
@@ -102,6 +111,7 @@ class DatabaseService {
|
||||
'backgroundServiceEnabled': 0,
|
||||
'notificationEnabled': 0,
|
||||
'mergeRecordsEnabled': 0,
|
||||
'hideTimeOnlyRecords': 0,
|
||||
'groupBy': 'trainAndLoco',
|
||||
'timeWindow': 'unlimited',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user