diff --git a/das_client/assets/icons/icon_balise.svg b/das_client/assets/icons/icon_balise.svg
new file mode 100644
index 00000000..7075001a
--- /dev/null
+++ b/das_client/assets/icons/icon_balise.svg
@@ -0,0 +1,5 @@
+
diff --git a/das_client/assets/icons/icon_km_indicator.svg b/das_client/assets/icons/icon_km_indicator.svg
new file mode 100644
index 00000000..cbe7719a
--- /dev/null
+++ b/das_client/assets/icons/icon_km_indicator.svg
@@ -0,0 +1,4 @@
+
diff --git a/das_client/assets/icons/icon_tram_area.svg b/das_client/assets/icons/icon_tram_area.svg
new file mode 100644
index 00000000..2b994738
--- /dev/null
+++ b/das_client/assets/icons/icon_tram_area.svg
@@ -0,0 +1,4 @@
+
diff --git a/das_client/assets/icons/icon_whistle.svg b/das_client/assets/icons/icon_whistle.svg
new file mode 100644
index 00000000..14674ab4
--- /dev/null
+++ b/das_client/assets/icons/icon_whistle.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/das_client/integration_test/test/train_journey_table_test.dart b/das_client/integration_test/test/train_journey_table_test.dart
index 8fe991f7..fc1f2445 100644
--- a/das_client/integration_test/test/train_journey_table_test.dart
+++ b/das_client/integration_test/test/train_journey_table_test.dart
@@ -1,4 +1,5 @@
import 'package:das_client/app/pages/journey/train_journey/widgets/table/additional_speed_restriction_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/balise_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/cab_signaling_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/cells/bracket_station_cell_body.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/cells/graduated_speeds_cell_body.dart';
@@ -8,6 +9,8 @@ import 'package:das_client/app/pages/journey/train_journey/widgets/table/curve_p
import 'package:das_client/app/pages/journey/train_journey/widgets/table/protection_section_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/service_point_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/signal_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/tram_area_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/whistle_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/train_journey.dart';
import 'package:das_client/app/pages/profile/profile_page.dart';
import 'package:das_client/app/widgets/table/das_table.dart';
@@ -20,6 +23,94 @@ import '../util/test_utils.dart';
void main() {
group('train journey table test', () {
+
+ testWidgets('test balise multiple level crossings', (tester) async {
+ await prepareAndStartApp(tester);
+
+ // load train journey by filling out train selection page
+ await _loadTrainJourney(tester, trainNumber: 'T7');
+
+ final scrollableFinder = find.byType(ListView);
+ expect(scrollableFinder, findsOneWidget);
+
+ final baliseMultiLevelCrossing = findDASTableRowByText('(2 ${l10n.p_train_journey_table_level_crossing})');
+ expect(baliseMultiLevelCrossing, findsOneWidget);
+
+ final baliseIcon = find.descendant(of: baliseMultiLevelCrossing, matching: find.byKey(BaliseRow.baliseIconKey));
+ expect(baliseIcon, findsOneWidget);
+ });
+
+ testWidgets('test whistle and tram area', (tester) async {
+ await prepareAndStartApp(tester);
+
+ // load train journey by filling out train selection page
+ await _loadTrainJourney(tester, trainNumber: 'T7');
+
+ final scrollableFinder = find.byType(ListView);
+ expect(scrollableFinder, findsOneWidget);
+
+ final whistleRow = findDASTableRowByText('39.6');
+ expect(whistleRow, findsOneWidget);
+
+ final whistleIcon = find.descendant(of: whistleRow, matching: find.byKey(WhistleRow.whistleIconKey));
+ expect(whistleIcon, findsOneWidget);
+
+ final tramAreaRow = findDASTableRowByText('km 37.8-36.8');
+ expect(tramAreaRow, findsOneWidget);
+
+ final tramAreaIcon = find.descendant(of: tramAreaRow, matching: find.byKey(TramAreaRow.tramAreaIconKey));
+ expect(tramAreaIcon, findsOneWidget);
+
+ final tramAreaDescription = find.descendant(of: tramAreaRow, matching: find.text('6 TS'));
+ expect(tramAreaDescription, findsOneWidget);
+ });
+
+ testWidgets('test balise and level crossing groups expand / collapse', (tester) async {
+ await prepareAndStartApp(tester);
+
+ // load train journey by filling out train selection page
+ await _loadTrainJourney(tester, trainNumber: 'T7');
+
+ final scrollableFinder = find.byType(ListView);
+ expect(scrollableFinder, findsOneWidget);
+
+ final groupOf5BaliseRow = findDASTableRowByText('41.6');
+ expect(groupOf5BaliseRow, findsOneWidget);
+
+ final countText = find.descendant(of: groupOf5BaliseRow, matching: find.text('5'));
+ expect(countText, findsOneWidget);
+
+ final levelCrossingText = find.descendant(of: groupOf5BaliseRow, matching: find.text(l10n.p_train_journey_table_level_crossing));
+ expect(levelCrossingText, findsOneWidget);
+
+ var detailRowBalise = findDASTableRowByText('41.552');
+ var detailRowLevelCrossing = findDASTableRowByText('41.492');
+
+ expect(detailRowLevelCrossing, findsNothing);
+ expect(detailRowBalise, findsNothing);
+
+ // expand group
+ await tapElement(tester, groupOf5BaliseRow);
+
+ detailRowBalise = findDASTableRowByText('41.552');
+ detailRowLevelCrossing = findDASTableRowByText('41.492');
+
+ expect(detailRowLevelCrossing, findsOneWidget);
+ expect(detailRowBalise, findsOneWidget);
+
+ expect(find.descendant(of: detailRowBalise, matching: find.byKey(BaliseRow.baliseIconKey)), findsOneWidget);
+ expect(find.descendant(of: detailRowLevelCrossing, matching: find.text(l10n.p_train_journey_table_level_crossing)), findsOneWidget);
+
+ // collapse group
+ await tapElement(tester, groupOf5BaliseRow);
+
+ detailRowBalise = findDASTableRowByText('41.552');
+ detailRowLevelCrossing = findDASTableRowByText('41.492');
+
+ expect(detailRowLevelCrossing, findsNothing);
+ expect(detailRowBalise, findsNothing);
+ });
+
testWidgets('test breaking series defaults to ??', (tester) async {
await prepareAndStartApp(tester);
diff --git a/das_client/l10n/strings_de.arb b/das_client/l10n/strings_de.arb
index 7bddbe1d..994e8246 100644
--- a/das_client/l10n/strings_de.arb
+++ b/das_client/l10n/strings_de.arb
@@ -17,6 +17,8 @@
"p_train_journey_table_curve_type_curve": "Kurve",
"p_train_journey_table_curve_type_station_exit_curve": "Kurve Ausfahrt",
"p_train_journey_table_curve_type_curve_after_halt": "Kurve nach Haltestelle",
+ "p_train_journey_table_level_crossing": "BUe",
+ "p_train_journey_table_tram_area": "TS",
"w_navigation_drawer_fahrtinfo_title": "Fahrtinfo",
"w_navigation_drawer_links_title": "Links",
"w_navigation_drawer_settings_title": "Einstellungen",
diff --git a/das_client/lib/app/bloc/train_journey_cubit.dart b/das_client/lib/app/bloc/train_journey_cubit.dart
index 7261e76c..965a34a0 100644
--- a/das_client/lib/app/bloc/train_journey_cubit.dart
+++ b/das_client/lib/app/bloc/train_journey_cubit.dart
@@ -117,6 +117,10 @@ class TrainJourneyCubit extends Cubit {
void updateBreakSeries(BreakSeries selectedBreakSeries) {
_settingsSubject.add(_settingsSubject.value.copyWith(selectedBreakSeries: selectedBreakSeries));
}
+
+ void updateExpandedGroups(List expandedGroups) {
+ _settingsSubject.add(_settingsSubject.value.copyWith(expandedGroups: expandedGroups));
+ }
}
extension ContextBlocExtension on BuildContext {
diff --git a/das_client/lib/app/model/train_journey_settings.dart b/das_client/lib/app/model/train_journey_settings.dart
index 0df6482f..ffbdc124 100644
--- a/das_client/lib/app/model/train_journey_settings.dart
+++ b/das_client/lib/app/model/train_journey_settings.dart
@@ -3,13 +3,16 @@ import 'package:das_client/model/journey/break_series.dart';
class TrainJourneySettings {
TrainJourneySettings({
this.selectedBreakSeries,
+ this.expandedGroups = const [],
});
final BreakSeries? selectedBreakSeries;
+ final List expandedGroups;
- TrainJourneySettings copyWith({BreakSeries? selectedBreakSeries}) {
+ TrainJourneySettings copyWith({BreakSeries? selectedBreakSeries, List? expandedGroups}) {
return TrainJourneySettings(
selectedBreakSeries: selectedBreakSeries ?? this.selectedBreakSeries,
+ expandedGroups: expandedGroups ?? this.expandedGroups,
);
}
}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/balise_level_crossing_group_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/balise_level_crossing_group_row.dart
new file mode 100644
index 00000000..f6a75c17
--- /dev/null
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/balise_level_crossing_group_row.dart
@@ -0,0 +1,68 @@
+import 'package:das_client/app/i18n/i18n.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/base_row_builder.dart';
+import 'package:das_client/app/widgets/assets.dart';
+import 'package:das_client/app/widgets/table/das_table_cell.dart';
+import 'package:das_client/model/journey/balise.dart';
+import 'package:das_client/model/journey/balise_level_crossing_group.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart';
+
+class BaliseLevelCrossingGroupRow extends BaseRowBuilder {
+ static const Key baliseIconKey = Key('balise_icon_key');
+
+ BaliseLevelCrossingGroupRow({
+ required super.metadata,
+ required super.data,
+ required super.settings,
+ super.trackEquipmentRenderData,
+ super.onTap,
+ });
+
+ @override
+ DASTableCell informationCell(BuildContext context) {
+ if (_baliseCount == 0) {
+ return DASTableCell(
+ child: Text('$_levelCrossingCount ${context.l10n.p_train_journey_table_level_crossing}'),
+ alignment: Alignment.centerLeft,
+ );
+ } else if (_baliseCount == 1 && _levelCrossingCount > 1) {
+ return DASTableCell(
+ child: Text('($_levelCrossingCount ${context.l10n.p_train_journey_table_level_crossing})'),
+ alignment: Alignment.centerRight,
+ );
+ } else {
+ return DASTableCell(
+ child: Row(
+ children: [
+ Text(_levelCrossingCount > 0 ? context.l10n.p_train_journey_table_level_crossing : ''),
+ Spacer(),
+ Text(_baliseCount.toString()),
+ ],
+ ),
+ alignment: Alignment.centerRight,
+ );
+ }
+ }
+
+ @override
+ DASTableCell iconsCell2(BuildContext context) {
+ if (_baliseCount > 0) {
+ return DASTableCell(
+ padding: EdgeInsets.all(sbbDefaultSpacing * 0.25),
+ child: SvgPicture.asset(
+ AppAssets.iconBalise,
+ key: baliseIconKey,
+ ),
+ alignment: Alignment.centerLeft,
+ );
+ } else {
+ return DASTableCell.empty();
+ }
+ }
+
+ int get _baliseCount => data.groupedElements.whereType().length;
+
+ int get _levelCrossingCount => data.groupedElements.whereType().length;
+}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/balise_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/balise_row.dart
new file mode 100644
index 00000000..3a129eea
--- /dev/null
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/balise_row.dart
@@ -0,0 +1,60 @@
+import 'package:das_client/app/i18n/i18n.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/base_row_builder.dart';
+import 'package:das_client/app/widgets/assets.dart';
+import 'package:das_client/app/widgets/table/das_table_cell.dart';
+import 'package:das_client/model/journey/balise.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart';
+
+class BaliseRow extends BaseRowBuilder {
+ static const Key baliseIconKey = Key('balise_icon_key');
+
+ BaliseRow({
+ required super.metadata,
+ required super.data,
+ required super.settings,
+ super.trackEquipmentRenderData,
+ super.isGrouped,
+ });
+
+ @override
+ DASTableCell kilometreCell(BuildContext context) {
+ return isGrouped ? DASTableCell.empty() : super.kilometreCell(context);
+ }
+
+ @override
+ DASTableCell timeCell(BuildContext context) {
+ if (!isGrouped) {
+ return DASTableCell.empty();
+ }
+
+ if (data.kilometre.isEmpty) {
+ return DASTableCell.empty(color: specialCellColor);
+ } else {
+ return DASTableCell(color: specialCellColor, child: Text(data.kilometre[0].toStringAsFixed(3)));
+ }
+ }
+
+ @override
+ DASTableCell informationCell(BuildContext context) {
+ return DASTableCell(
+ child: Text(data.amountLevelCrossings > 1
+ ? '(${data.amountLevelCrossings} ${context.l10n.p_train_journey_table_level_crossing})'
+ : ''),
+ alignment: Alignment.centerRight,
+ );
+ }
+
+ @override
+ DASTableCell iconsCell2(BuildContext context) {
+ return DASTableCell(
+ padding: EdgeInsets.all(sbbDefaultSpacing * 0.25),
+ child: SvgPicture.asset(
+ AppAssets.iconBalise,
+ key: baliseIconKey,
+ ),
+ alignment: Alignment.centerLeft,
+ );
+ }
+}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/base_row_builder.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/base_row_builder.dart
index 5f1d96fd..45f1793f 100644
--- a/das_client/lib/app/pages/journey/train_journey/widgets/table/base_row_builder.dart
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/base_row_builder.dart
@@ -21,6 +21,8 @@ class BaseRowBuilder extends DASTableRowBuilder {
this.trackEquipmentRenderData = const TrackEquipmentRenderData(),
this.defaultAlignment = Alignment.bottomCenter,
this.rowColor,
+ this.onTap,
+ this.isGrouped = false,
});
final Alignment defaultAlignment;
@@ -29,12 +31,15 @@ class BaseRowBuilder extends DASTableRowBuilder {
final T data;
final TrackEquipmentRenderData trackEquipmentRenderData;
final TrainJourneySettings settings;
+ final VoidCallback? onTap;
+ final bool isGrouped;
@override
DASTableRow build(BuildContext context) {
return DASTableRow(
height: height,
color: rowColor,
+ onTap: onTap,
cells: [
kilometreCell(context),
timeCell(context),
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data.dart
index 3f603d0a..d9d4fb29 100644
--- a/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data.dart
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data.dart
@@ -4,7 +4,7 @@ import 'package:das_client/app/pages/journey/train_journey/widgets/table/service
import 'package:das_client/model/journey/base_data.dart';
import 'package:das_client/model/journey/cab_signaling.dart';
import 'package:das_client/model/journey/datatype.dart';
-import 'package:das_client/model/journey/journey.dart';
+import 'package:das_client/model/journey/metadata.dart';
import 'package:das_client/model/journey/track_equipment.dart';
/// Data class to hold all the information to visualize the track equipment.
@@ -23,16 +23,16 @@ class TrackEquipmentRenderData {
final bool isConventionalExtendedSpeedBorder;
final TrackEquipmentType? trackEquipmentType;
- factory TrackEquipmentRenderData.from(Journey journey, int index) {
- final data = journey.data[index];
- final nonStandardTrackEquipmentSegments = journey.metadata.nonStandardTrackEquipmentSegments;
+ factory TrackEquipmentRenderData.from(List rowData, Metadata metadata, int index) {
+ final data = rowData[index];
+ final nonStandardTrackEquipmentSegments = metadata.nonStandardTrackEquipmentSegments;
final trackEquipment = nonStandardTrackEquipmentSegments.appliesToOrder(data.order).firstOrNull;
if (trackEquipment == null || !trackEquipment.isEtcsL2Segment) return TrackEquipmentRenderData();
return TrackEquipmentRenderData(
trackEquipmentType: trackEquipment.type,
- cumulativeHeight: _calculateTrackEquipmentCumulativeHeight(journey, trackEquipment, index),
- isConventionalExtendedSpeedBorder: _isConventionalExtendedSpeedBorder(journey, index),
+ cumulativeHeight: _calculateTrackEquipmentCumulativeHeight(rowData, metadata, trackEquipment, index),
+ isConventionalExtendedSpeedBorder: _isConventionalExtendedSpeedBorder(rowData, metadata, index),
isCABStart: data is CABSignaling ? data.isStart : false,
isCABEnd: data is CABSignaling ? data.isEnd : false,
);
@@ -40,13 +40,12 @@ class TrackEquipmentRenderData {
/// calculates the cumulative height of the track equipment "line" of previous rows with the same type as given [trackEquipment].
static double _calculateTrackEquipmentCumulativeHeight(
- Journey journey, NonStandardTrackEquipmentSegment trackEquipment, int index) {
+ List rowData, Metadata metadata, NonStandardTrackEquipmentSegment trackEquipment, int index) {
var cumulativeHeight = 0.0;
var searchIndex = index - 1;
while (searchIndex >= 0) {
- final data = journey.data[searchIndex];
- final testTrackEquipment =
- journey.metadata.nonStandardTrackEquipmentSegments.appliesToOrder(data.order).firstOrNull;
+ final data = rowData[searchIndex];
+ final testTrackEquipment = metadata.nonStandardTrackEquipmentSegments.appliesToOrder(data.order).firstOrNull;
if (testTrackEquipment == null || testTrackEquipment.type != trackEquipment.type) {
break;
@@ -55,7 +54,7 @@ class TrackEquipmentRenderData {
cumulativeHeight += _rowHeight(data);
// if is conventional extended speed border, reduce by it's height as it is not part of the dashed line.
- if (_isConventionalExtendedSpeedBorder(journey, searchIndex)) {
+ if (_isConventionalExtendedSpeedBorder(rowData, metadata, searchIndex)) {
cumulativeHeight -= TrackEquipmentCellBody.conventionalExtendedSpeedBorderSpace;
}
@@ -77,12 +76,12 @@ class TrackEquipmentRenderData {
}
/// checks if between current and previous track equipment is a border between extended and conventional speed.
- static bool _isConventionalExtendedSpeedBorder(Journey journey, int index) {
+ static bool _isConventionalExtendedSpeedBorder(List rowData, Metadata metadata, int index) {
if (index < 1) return false;
- final nonStandardTrackEquipmentSegments = journey.metadata.nonStandardTrackEquipmentSegments;
- final currentData = journey.data[index];
- final previousData = journey.data[index - 1];
+ final nonStandardTrackEquipmentSegments = metadata.nonStandardTrackEquipmentSegments;
+ final currentData = rowData[index];
+ final previousData = rowData[index - 1];
final trackEquipment = nonStandardTrackEquipmentSegments.appliesToOrder(currentData.order).firstOrNull;
final previousTrackEquipment = nonStandardTrackEquipmentSegments.appliesToOrder(previousData.order).firstOrNull;
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/level_crossing_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/level_crossing_row.dart
new file mode 100644
index 00000000..dbce46b6
--- /dev/null
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/level_crossing_row.dart
@@ -0,0 +1,41 @@
+import 'package:das_client/app/i18n/i18n.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/base_row_builder.dart';
+import 'package:das_client/app/widgets/table/das_table_cell.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
+import 'package:flutter/material.dart';
+
+class LevelCrossingRow extends BaseRowBuilder {
+ LevelCrossingRow({
+ required super.metadata,
+ required super.data,
+ required super.settings,
+ super.trackEquipmentRenderData,
+ super.isGrouped,
+ });
+
+ @override
+ DASTableCell kilometreCell(BuildContext context) {
+ return isGrouped ? DASTableCell.empty() : super.kilometreCell(context);
+ }
+
+ @override
+ DASTableCell timeCell(BuildContext context) {
+ if (!isGrouped) {
+ return DASTableCell.empty();
+ }
+
+ if (data.kilometre.isEmpty) {
+ return DASTableCell.empty(color: specialCellColor);
+ } else {
+ return DASTableCell(color: specialCellColor, child: Text(data.kilometre[0].toStringAsFixed(3)));
+ }
+ }
+
+ @override
+ DASTableCell informationCell(BuildContext context) {
+ return DASTableCell(
+ child: Text(context.l10n.p_train_journey_table_level_crossing),
+ alignment: Alignment.centerLeft,
+ );
+ }
+}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/speed_change_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/speed_change_row.dart
index 85e0eec7..a7dd616c 100644
--- a/das_client/lib/app/pages/journey/train_journey/widgets/table/speed_change_row.dart
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/speed_change_row.dart
@@ -1,9 +1,14 @@
import 'package:das_client/app/pages/journey/train_journey/widgets/table/base_row_builder.dart';
+import 'package:das_client/app/widgets/assets.dart';
import 'package:das_client/app/widgets/table/das_table_cell.dart';
import 'package:das_client/model/journey/speed_change.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart';
class SpeedChangeRow extends BaseRowBuilder {
+ static const Key kmIndicatorKey = Key('km_indicator_key');
+
SpeedChangeRow({
required super.metadata,
required super.data,
@@ -17,4 +22,16 @@ class SpeedChangeRow extends BaseRowBuilder {
child: Text(data.text ?? ''),
);
}
+
+ @override
+ DASTableCell iconsCell2(BuildContext context) {
+ return DASTableCell(
+ padding: EdgeInsets.all(sbbDefaultSpacing * 0.25),
+ child: SvgPicture.asset(
+ AppAssets.iconKmIndicator,
+ key: kmIndicatorKey,
+ ),
+ alignment: Alignment.centerLeft,
+ );
+ }
}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/tram_area_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/tram_area_row.dart
new file mode 100644
index 00000000..fa522188
--- /dev/null
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/tram_area_row.dart
@@ -0,0 +1,46 @@
+import 'package:das_client/app/i18n/i18n.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/base_row_builder.dart';
+import 'package:das_client/app/widgets/assets.dart';
+import 'package:das_client/app/widgets/table/das_table_cell.dart';
+import 'package:das_client/model/journey/tram_area.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart';
+
+class TramAreaRow extends BaseRowBuilder {
+ static const Key tramAreaIconKey = Key('tram_area_icon_key');
+
+ TramAreaRow({
+ required super.metadata,
+ required super.data,
+ required super.settings,
+ super.trackEquipmentRenderData,
+ });
+
+ @override
+ DASTableCell informationCell(BuildContext context) {
+ return DASTableCell(
+ child: Row(
+ children: [
+ Text(
+ '${context.l10n.p_train_journey_table_kilometre_label} ${data.kilometre[0].toStringAsFixed(1)}-${data.endKilometre.toStringAsFixed(1)}'),
+ Spacer(),
+ Text(
+ '${data.amountTramSignals > 1 ? data.amountTramSignals : ''} ${context.l10n.p_train_journey_table_tram_area}'),
+ ],
+ ),
+ );
+ }
+
+ @override
+ DASTableCell iconsCell2(BuildContext context) {
+ return DASTableCell(
+ padding: EdgeInsets.all(sbbDefaultSpacing * 0.25),
+ child: SvgPicture.asset(
+ AppAssets.iconTramArea,
+ key: tramAreaIconKey,
+ ),
+ alignment: Alignment.centerLeft,
+ );
+ }
+}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/whistle_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/whistle_row.dart
new file mode 100644
index 00000000..9230430b
--- /dev/null
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/whistle_row.dart
@@ -0,0 +1,30 @@
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/base_row_builder.dart';
+import 'package:das_client/app/widgets/assets.dart';
+import 'package:das_client/app/widgets/table/das_table_cell.dart';
+import 'package:das_client/model/journey/whistles.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart';
+
+class WhistleRow extends BaseRowBuilder {
+ static const Key whistleIconKey = Key('whistle_icon_key');
+
+ WhistleRow({
+ required super.metadata,
+ required super.data,
+ required super.settings,
+ super.trackEquipmentRenderData,
+ });
+
+ @override
+ DASTableCell iconsCell2(BuildContext context) {
+ return DASTableCell(
+ padding: EdgeInsets.all(sbbDefaultSpacing * 0.25),
+ child: SvgPicture.asset(
+ AppAssets.iconWhistle,
+ key: whistleIconKey,
+ ),
+ alignment: Alignment.centerLeft,
+ );
+ }
+}
diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/train_journey.dart b/das_client/lib/app/pages/journey/train_journey/widgets/train_journey.dart
index 29e7ed63..1c534dd9 100644
--- a/das_client/lib/app/pages/journey/train_journey/widgets/train_journey.dart
+++ b/das_client/lib/app/pages/journey/train_journey/widgets/train_journey.dart
@@ -3,28 +3,39 @@ import 'package:das_client/app/i18n/i18n.dart';
import 'package:das_client/app/model/train_journey_settings.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/break_series_selection.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/additional_speed_restriction_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/balise_level_crossing_group_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/balise_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/cab_signaling_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/connection_track_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/curve_point_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/level_crossing_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/protection_section_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/service_point_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/signal_row.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/speed_change_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/tram_area_row.dart';
+import 'package:das_client/app/pages/journey/train_journey/widgets/table/whistle_row.dart';
import 'package:das_client/app/widgets/table/das_table.dart';
import 'package:das_client/app/widgets/table/das_table_column.dart';
import 'package:das_client/app/widgets/table/das_table_row.dart';
import 'package:das_client/model/journey/additional_speed_restriction_data.dart';
+import 'package:das_client/model/journey/balise.dart';
+import 'package:das_client/model/journey/balise_level_crossing_group.dart';
+import 'package:das_client/model/journey/base_data_extension.dart';
import 'package:das_client/model/journey/break_series.dart';
import 'package:das_client/model/journey/cab_signaling.dart';
import 'package:das_client/model/journey/connection_track.dart';
import 'package:das_client/model/journey/curve_point.dart';
import 'package:das_client/model/journey/datatype.dart';
import 'package:das_client/model/journey/journey.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
import 'package:das_client/model/journey/protection_section.dart';
import 'package:das_client/model/journey/service_point.dart';
import 'package:das_client/model/journey/signal.dart';
import 'package:das_client/model/journey/speed_change.dart';
+import 'package:das_client/model/journey/tram_area.dart';
+import 'package:das_client/model/journey/whistles.dart';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart';
@@ -64,10 +75,15 @@ class TrainJourney extends StatelessWidget {
}
List _rows(BuildContext context, Journey journey, TrainJourneySettings settings) {
- return List.generate(journey.data.length, (index) {
- final rowData = journey.data[index];
+ final rows = journey.data.groupBaliseAndLeveLCrossings(settings);
- final renderData = TrackEquipmentRenderData.from(journey, index);
+ final groupedRows =
+ rows.whereType().map((it) => it.groupedElements).expand((it) => it).toList();
+
+ return List.generate(rows.length, (index) {
+ final rowData = rows[index];
+
+ final renderData = TrackEquipmentRenderData.from(rows, journey.metadata, index);
switch (rowData.type) {
case Datatype.servicePoint:
return ServicePointRow(
@@ -125,6 +141,44 @@ class TrainJourney extends StatelessWidget {
settings: settings,
trackEquipmentRenderData: renderData)
.build(context);
+ case Datatype.balise:
+ return BaliseRow(
+ metadata: journey.metadata,
+ data: rowData as Balise,
+ settings: settings,
+ trackEquipmentRenderData: renderData,
+ isGrouped: groupedRows.contains(rowData))
+ .build(context);
+ case Datatype.whistle:
+ return WhistleRow(
+ metadata: journey.metadata,
+ data: rowData as Whistle,
+ settings: settings,
+ trackEquipmentRenderData: renderData)
+ .build(context);
+ case Datatype.levelCrossing:
+ return LevelCrossingRow(
+ metadata: journey.metadata,
+ data: rowData as LevelCrossing,
+ settings: settings,
+ trackEquipmentRenderData: renderData,
+ isGrouped: groupedRows.contains(rowData))
+ .build(context);
+ case Datatype.tramArea:
+ return TramAreaRow(
+ metadata: journey.metadata,
+ data: rowData as TramArea,
+ settings: settings,
+ trackEquipmentRenderData: renderData)
+ .build(context);
+ case Datatype.baliseLevelCrossingGroup:
+ return BaliseLevelCrossingGroupRow(
+ metadata: journey.metadata,
+ data: rowData as BaliseLevelCrossingGroup,
+ settings: settings,
+ trackEquipmentRenderData: renderData,
+ onTap: () => _onBaliseLevelCrossingGroupTap(context, rowData, settings),
+ ).build(context);
}
});
}
@@ -166,6 +220,20 @@ class TrainJourney extends StatelessWidget {
];
}
+ void _onBaliseLevelCrossingGroupTap(
+ BuildContext context, BaliseLevelCrossingGroup group, TrainJourneySettings settings) {
+ final trainJourneyCubit = context.trainJourneyCubit;
+
+ final newList = List.from(settings.expandedGroups);
+ if (settings.expandedGroups.contains(group.order)) {
+ newList.remove(group.order);
+ } else {
+ newList.add(group.order);
+ }
+
+ trainJourneyCubit.updateExpandedGroups(newList);
+ }
+
void _onBreakSeriesTap(BuildContext context, Journey journey, TrainJourneySettings settings) {
final trainJourneyCubit = context.trainJourneyCubit;
diff --git a/das_client/lib/app/widgets/assets.dart b/das_client/lib/app/widgets/assets.dart
index 5f6020b1..c90d5a5c 100644
--- a/das_client/lib/app/widgets/assets.dart
+++ b/das_client/lib/app/widgets/assets.dart
@@ -16,4 +16,8 @@ class AppAssets {
static const iconCabStart = '$_iconsDir/icon_cab_start.svg';
static const iconCabEnd = '$_iconsDir/icon_cab_end.svg';
static const iconIndicatorChecked = '$_iconsDir/icon_indicator_checked.svg';
+ static const iconBalise = '$_iconsDir/icon_balise.svg';
+ static const iconKmIndicator = '$_iconsDir/icon_km_indicator.svg';
+ static const iconWhistle = '$_iconsDir/icon_whistle.svg';
+ static const iconTramArea = '$_iconsDir/icon_tram_area.svg';
}
diff --git a/das_client/lib/app/widgets/table/das_table.dart b/das_client/lib/app/widgets/table/das_table.dart
index 3655c7d6..735539c4 100644
--- a/das_client/lib/app/widgets/table/das_table.dart
+++ b/das_client/lib/app/widgets/table/das_table.dart
@@ -140,13 +140,16 @@ class DASTable extends StatelessWidget {
Widget _dataRow(DASTableRow row) {
final visibleColumns = columns.where((column) => column.isVisible).toList(growable: false);
final visibleCells = row.cells.whereIndexed((index, _) => columns[index].isVisible).toList(growable: false);
- return _FixedHeightRow(
- height: row.height,
- children: List.generate(visibleColumns.length, (index) {
- final cell = visibleCells[index];
- final column = visibleColumns[index];
- return _dataCell(cell, column, row, isLast: visibleColumns.length - 1 == index);
- }),
+ return InkWell(
+ onTap: row.onTap,
+ child: _FixedHeightRow(
+ height: row.height,
+ children: List.generate(visibleColumns.length, (index) {
+ final cell = visibleCells[index];
+ final column = visibleColumns[index];
+ return _dataCell(cell, column, row, isLast: visibleColumns.length - 1 == index);
+ }),
+ ),
);
}
diff --git a/das_client/lib/app/widgets/table/das_table_row.dart b/das_client/lib/app/widgets/table/das_table_row.dart
index 4509c879..dbe2be25 100644
--- a/das_client/lib/app/widgets/table/das_table_row.dart
+++ b/das_client/lib/app/widgets/table/das_table_row.dart
@@ -13,7 +13,7 @@ abstract class DASTableRowBuilder {
/// Represents a row in the [DASTable] containing cells.
@immutable
class DASTableRow {
- const DASTableRow({required this.cells, required this.height, this.color});
+ const DASTableRow({required this.cells, required this.height, this.color, this.onTap});
/// Height of the row
final double height;
@@ -22,4 +22,6 @@ class DASTableRow {
final Color? color;
final List cells;
+
+ final VoidCallback? onTap;
}
diff --git a/das_client/lib/model/journey/balise.dart b/das_client/lib/model/journey/balise.dart
new file mode 100644
index 00000000..a4da10d4
--- /dev/null
+++ b/das_client/lib/model/journey/balise.dart
@@ -0,0 +1,28 @@
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/datatype.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
+
+class Balise extends BaseData {
+ Balise({
+ required super.order,
+ required super.kilometre,
+ required this.amountLevelCrossings,
+ super.speedData,
+ }) : super(type: Datatype.balise);
+
+ final int amountLevelCrossings;
+
+ @override
+ bool get canGroup => true;
+
+ @override
+ bool canGroupWith(BaseData other) {
+ if (other is LevelCrossing) {
+ return true;
+ } else if (other is Balise) {
+ return amountLevelCrossings == 1 && other.amountLevelCrossings == 1;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/das_client/lib/model/journey/balise_level_crossing_group.dart b/das_client/lib/model/journey/balise_level_crossing_group.dart
new file mode 100644
index 00000000..0f452f71
--- /dev/null
+++ b/das_client/lib/model/journey/balise_level_crossing_group.dart
@@ -0,0 +1,13 @@
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/datatype.dart';
+
+class BaliseLevelCrossingGroup extends BaseData {
+ BaliseLevelCrossingGroup({
+ required super.order,
+ required super.kilometre,
+ required this.groupedElements,
+ super.speedData,
+ }) : super(type: Datatype.baliseLevelCrossingGroup);
+
+ final List groupedElements;
+}
diff --git a/das_client/lib/model/journey/base_data.dart b/das_client/lib/model/journey/base_data.dart
index 03f81fca..4cc013d4 100644
--- a/das_client/lib/model/journey/base_data.dart
+++ b/das_client/lib/model/journey/base_data.dart
@@ -1,3 +1,4 @@
+import 'package:das_client/model/journey/base_data_extension.dart';
import 'package:das_client/model/journey/datatype.dart';
import 'package:das_client/model/journey/speed_data.dart';
@@ -27,4 +28,16 @@ abstract class BaseData implements Comparable {
/// Used for comparing if [order] is equal.
/// If [orderPriority] is smaller, this is ordered before other, a bigger value is ordered after other.
int get orderPriority => 0;
+
+ /// Used to indicate that this element can be grouped together
+ /// [canGroup] and [canGroupWith] needs to be overridden for elements to be able to be grouped
+ /// Grouping is done in [BaseDataExtension]
+ bool get canGroup => false;
+
+ /// Used to check if the current element is allowed to be grouped with the other element
+ /// Only gets checked if [canGroup] is already true
+ /// Grouping is done in [BaseDataExtension]
+ bool canGroupWith(BaseData other) {
+ return false;
+ }
}
diff --git a/das_client/lib/model/journey/base_data_extension.dart b/das_client/lib/model/journey/base_data_extension.dart
new file mode 100644
index 00000000..b8a428a4
--- /dev/null
+++ b/das_client/lib/model/journey/base_data_extension.dart
@@ -0,0 +1,50 @@
+import 'package:das_client/app/model/train_journey_settings.dart';
+import 'package:das_client/model/journey/balise_level_crossing_group.dart';
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/datatype.dart';
+
+extension BaseDataExtension on List {
+ List groupBaliseAndLeveLCrossings(TrainJourneySettings settings) {
+ final List resultList = [];
+
+ for (int i = 0; i < length; i++) {
+ final currentElement = this[i];
+ if (!currentElement.canGroup) {
+ // Just add elements to the result that are unable to be grouped
+ resultList.add(currentElement);
+ continue;
+ }
+
+ final groupedElements = [currentElement];
+ // check the next elements if they can be grouped with the currentElement.
+ for (int j = i + 1; j < length; j++) {
+ final nextElement = this[j];
+ if (nextElement.canGroup && currentElement.canGroupWith(nextElement)) {
+ groupedElements.add(nextElement);
+ } else {
+ // Stop once we reach a element that is unable to be grouped
+ break;
+ }
+ }
+
+ if (groupedElements.length > 1 && [Datatype.balise, Datatype.levelCrossing].contains(currentElement.type)) {
+ // Add a group header if we have more then 1 element
+ final group = BaliseLevelCrossingGroup(
+ order: groupedElements[0].order, kilometre: groupedElements[0].kilometre, groupedElements: groupedElements);
+ resultList.add(group);
+
+ // Add all the elements if the group is currently expanded
+ if (settings.expandedGroups.contains(group.order)) {
+ resultList.addAll(groupedElements);
+ }
+
+ // skip already checked elements
+ i += groupedElements.length - 1;
+ } else {
+ resultList.add(currentElement);
+ }
+ }
+
+ return resultList;
+ }
+}
diff --git a/das_client/lib/model/journey/datatype.dart b/das_client/lib/model/journey/datatype.dart
index e5771a55..a68d676f 100644
--- a/das_client/lib/model/journey/datatype.dart
+++ b/das_client/lib/model/journey/datatype.dart
@@ -6,5 +6,10 @@ enum Datatype {
cabSignaling,
additionalSpeedRestriction,
connectionTrack,
- speedChange;
+ speedChange,
+ whistle,
+ levelCrossing,
+ tramArea,
+ balise,
+ baliseLevelCrossingGroup;
}
diff --git a/das_client/lib/model/journey/level_crossing.dart b/das_client/lib/model/journey/level_crossing.dart
new file mode 100644
index 00000000..856bf5ae
--- /dev/null
+++ b/das_client/lib/model/journey/level_crossing.dart
@@ -0,0 +1,18 @@
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/datatype.dart';
+
+class LevelCrossing extends BaseData {
+ LevelCrossing({
+ required super.order,
+ required super.kilometre,
+ super.speedData,
+ }) : super(type: Datatype.levelCrossing);
+
+ @override
+ bool get canGroup => true;
+
+ @override
+ bool canGroupWith(BaseData other) {
+ return [Datatype.balise, Datatype.levelCrossing].contains(other.type);
+ }
+}
diff --git a/das_client/lib/model/journey/tram_area.dart b/das_client/lib/model/journey/tram_area.dart
new file mode 100644
index 00000000..99de7395
--- /dev/null
+++ b/das_client/lib/model/journey/tram_area.dart
@@ -0,0 +1,15 @@
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/datatype.dart';
+
+class TramArea extends BaseData {
+ TramArea(
+ {required super.order,
+ required super.kilometre,
+ required this.endKilometre,
+ required this.amountTramSignals,
+ super.speedData})
+ : super(type: Datatype.tramArea);
+
+ final double endKilometre;
+ final int amountTramSignals;
+}
diff --git a/das_client/lib/model/journey/whistles.dart b/das_client/lib/model/journey/whistles.dart
new file mode 100644
index 00000000..18ce7d43
--- /dev/null
+++ b/das_client/lib/model/journey/whistles.dart
@@ -0,0 +1,6 @@
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/datatype.dart';
+
+class Whistle extends BaseData {
+ Whistle({required super.order, required super.kilometre, super.speedData}) : super(type: Datatype.whistle);
+}
diff --git a/das_client/lib/sfera/src/mapper/sfera_model_mapper.dart b/das_client/lib/sfera/src/mapper/sfera_model_mapper.dart
index 1bf9d776..f085b889 100644
--- a/das_client/lib/sfera/src/mapper/sfera_model_mapper.dart
+++ b/das_client/lib/sfera/src/mapper/sfera_model_mapper.dart
@@ -1,6 +1,7 @@
import 'package:collection/collection.dart';
import 'package:das_client/model/journey/additional_speed_restriction.dart';
import 'package:das_client/model/journey/additional_speed_restriction_data.dart';
+import 'package:das_client/model/journey/balise.dart' as journey_balise;
import 'package:das_client/model/journey/base_data.dart';
import 'package:das_client/model/journey/bracket_station.dart';
import 'package:das_client/model/journey/break_series.dart';
@@ -10,6 +11,7 @@ import 'package:das_client/model/journey/curve_point.dart';
import 'package:das_client/model/journey/datatype.dart';
import 'package:das_client/model/journey/graduated_station_speeds.dart';
import 'package:das_client/model/journey/journey.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
import 'package:das_client/model/journey/metadata.dart';
import 'package:das_client/model/journey/protection_section.dart';
import 'package:das_client/model/journey/service_point.dart';
@@ -19,7 +21,9 @@ import 'package:das_client/model/journey/speed_data.dart';
import 'package:das_client/model/journey/station_speed_data.dart';
import 'package:das_client/model/journey/track_equipment.dart';
import 'package:das_client/model/journey/train_series.dart';
+import 'package:das_client/model/journey/tram_area.dart';
import 'package:das_client/model/journey/velocity.dart';
+import 'package:das_client/model/journey/whistles.dart';
import 'package:das_client/model/localized_string.dart';
import 'package:das_client/sfera/src/mapper/track_equipment_mapper.dart';
import 'package:das_client/sfera/src/model/enums/length_type.dart';
@@ -88,6 +92,15 @@ class SferaModelMapper {
journeyData.addAll(connectionTracks);
journeyData.addAll(newLineSpeeds);
+ final balises = _parseBalise(segmentProfile, segmentIndex, kilometreMap);
+ journeyData.addAll(balises);
+
+ final whistles = _parseWhistle(segmentProfile, segmentIndex, kilometreMap);
+ journeyData.addAll(whistles);
+
+ final levelCrossings = _parseLevelCrossings(segmentProfile, segmentIndex, kilometreMap);
+ journeyData.addAll(levelCrossings);
+
final timingPoints = segmentProfile.points?.timingPoints.toList() ?? [];
for (final tpConstraint in segmentProfileList.timingPointsContraints) {
@@ -116,6 +129,9 @@ class SferaModelMapper {
_parseAndAddProtectionSections(journeyData, segmentIndex, segmentProfile, kilometreMap);
}
+ final tramAreas = _parseTramAreas(segmentProfiles);
+ journeyData.addAll(tramAreas);
+
final additionalSpeedRestrictions = _parseAdditionalSpeedRestrictions(journeyProfile, segmentProfiles);
for (final restriction in additionalSpeedRestrictions) {
journeyData.add(AdditionalSpeedRestrictionData(
@@ -440,4 +456,112 @@ class SferaModelMapper {
it.versionMajor == firstTrainRef.versionMajor &&
it.versionMinor == firstTrainRef.versionMinor);
}
+
+ static Iterable _parseBalise(
+ SegmentProfile segmentProfile, int segmentIndex, Map> kilometreMap) {
+ final balises = segmentProfile.points?.balise ?? [];
+ return balises.map((balise) {
+ return journey_balise.Balise(
+ order: calculateOrder(segmentIndex, balise.location),
+ kilometre: kilometreMap[balise.location] ?? [],
+ amountLevelCrossings: balise.amountLevelCrossings,
+ );
+ });
+ }
+
+ static Iterable _parseWhistle(
+ SegmentProfile segmentProfile, int segmentIndex, Map> kilometreMap) {
+ final whistleNsps = segmentProfile.points?.whistleNsp ?? [];
+ return whistleNsps.map((whistle) {
+ return Whistle(
+ order: calculateOrder(segmentIndex, whistle.location),
+ kilometre: kilometreMap[whistle.location] ?? [],
+ );
+ });
+ }
+
+ static Iterable _parseLevelCrossings(
+ SegmentProfile segmentProfile, int segmentIndex, Map> kilometreMap) {
+ final levelCrossings = segmentProfile.contextInformation?.levelCrossings ?? [];
+ return levelCrossings.map((levelCrossing) {
+ return LevelCrossing(
+ order: calculateOrder(segmentIndex, levelCrossing.startLocation),
+ kilometre: kilometreMap[levelCrossing.startLocation] ?? [],
+ );
+ });
+ }
+
+ static List _parseTramAreas(List segmentProfiles) {
+ final List result = [];
+
+ int? startSegmentIndex;
+ int? endSegmentIndex;
+ double? startLocation;
+ double? endLocation;
+ int? amountTramSignals;
+
+ for (int segmentIndex = 0; segmentIndex < segmentProfiles.length; segmentIndex++) {
+ final segmentProfile = segmentProfiles[segmentIndex];
+
+ if (segmentProfile.areas == null) continue;
+
+ for (final tramArea in segmentProfile.areas!.tramAreas) {
+ switch (tramArea.startEndQualifier) {
+ case StartEndQualifier.starts:
+ startLocation = tramArea.startLocation;
+ startSegmentIndex = segmentIndex;
+ amountTramSignals = tramArea.amountTramSignals?.amountTramSignals;
+ break;
+ case StartEndQualifier.startsEnds:
+ startLocation = tramArea.startLocation;
+ startSegmentIndex = segmentIndex;
+ amountTramSignals = tramArea.amountTramSignals?.amountTramSignals;
+ continue next;
+ next:
+ case StartEndQualifier.ends:
+ endLocation = tramArea.endLocation;
+ endSegmentIndex = segmentIndex;
+ break;
+ case StartEndQualifier.wholeSp:
+ break;
+ case null:
+ Fimber.w('Received tramArea with startEndQualifier=null');
+ break;
+ }
+
+ if (startSegmentIndex != null &&
+ endSegmentIndex != null &&
+ startLocation != null &&
+ endLocation != null &&
+ amountTramSignals != null) {
+ final startSegment = segmentProfiles[startSegmentIndex];
+ final endSegment = segmentProfiles[endSegmentIndex];
+
+ final startKilometreMap = parseKilometre(startSegment);
+ final endKilometreMap = parseKilometre(endSegment);
+
+ result.add(TramArea(
+ order: calculateOrder(startSegmentIndex, startLocation),
+ kilometre: startKilometreMap[startLocation]!,
+ endKilometre: endKilometreMap[endLocation]!.first,
+ amountTramSignals: amountTramSignals,
+ ));
+
+ startSegmentIndex = null;
+ endSegmentIndex = null;
+ startLocation = null;
+ endLocation = null;
+ amountTramSignals = null;
+ }
+ }
+ }
+
+ if (startSegmentIndex != null || endSegmentIndex != null || startLocation != null || endLocation != null) {
+ Fimber.w('Incomplete tram area found: '
+ 'startSegmentIndex: $startSegmentIndex, endSegmentIndex: $endSegmentIndex, '
+ 'startLocation: $startLocation, endLocation: $endLocation, amountTramSignals: $amountTramSignals');
+ }
+
+ return result;
+ }
}
diff --git a/das_client/lib/sfera/src/model/amount_tram_signals.dart b/das_client/lib/sfera/src/model/amount_tram_signals.dart
new file mode 100644
index 00000000..c25efad9
--- /dev/null
+++ b/das_client/lib/sfera/src/model/amount_tram_signals.dart
@@ -0,0 +1,14 @@
+import 'package:das_client/sfera/src/model/network_specific_parameter.dart';
+
+class AmountTramSignals extends NetworkSpecificParameter {
+ static const String elementName = 'amountTramSignals';
+
+ AmountTramSignals({super.type, super.attributes, super.children, super.value});
+
+ int get amountTramSignals => int.parse(attributes['value']!);
+
+ @override
+ bool validate() {
+ return validateHasAttributeInt('value') && super.validate();
+ }
+}
diff --git a/das_client/lib/sfera/src/model/balise.dart b/das_client/lib/sfera/src/model/balise.dart
new file mode 100644
index 00000000..6dec831a
--- /dev/null
+++ b/das_client/lib/sfera/src/model/balise.dart
@@ -0,0 +1,10 @@
+import 'package:das_client/sfera/src/model/sp_generic_point.dart';
+import 'package:das_client/util/util.dart';
+
+class Balise extends SpGenericPoint {
+ static const String elementType = 'Balise';
+
+ Balise({super.type = elementType, super.attributes, super.children, super.value});
+
+ int get amountLevelCrossings => Util.tryParseInt(attributes['amountLevelCrossings']) ?? 1;
+}
diff --git a/das_client/lib/sfera/src/model/level_crossing_area.dart b/das_client/lib/sfera/src/model/level_crossing_area.dart
new file mode 100644
index 00000000..38a2035a
--- /dev/null
+++ b/das_client/lib/sfera/src/model/level_crossing_area.dart
@@ -0,0 +1,22 @@
+import 'package:das_client/sfera/src/model/enums/start_end_qualifier.dart';
+import 'package:das_client/sfera/src/model/enums/xml_enum.dart';
+import 'package:das_client/sfera/src/model/sfera_xml_element.dart';
+import 'package:das_client/util/util.dart';
+
+class LevelCrossingArea extends SferaXmlElement {
+ static const String elementType = 'LevelCrossingArea';
+
+ LevelCrossingArea({super.type = elementType, super.attributes, super.children, super.value});
+
+ StartEndQualifier? get startEndQualifier =>
+ XmlEnum.valueOf(StartEndQualifier.values, attributes['startEndQualifier']);
+
+ double get startLocation => double.parse(attributes['startLocation']!);
+
+ double? get endLocation => Util.tryParseDouble(attributes['endLocation']);
+
+ @override
+ bool validate() {
+ return validateHasAttribute('startEndQualifier') && validateHasAttributeDouble('startLocation') && super.validate();
+ }
+}
diff --git a/das_client/lib/sfera/src/model/network_specific_area.dart b/das_client/lib/sfera/src/model/network_specific_area.dart
index f042c64e..d572c9df 100644
--- a/das_client/lib/sfera/src/model/network_specific_area.dart
+++ b/das_client/lib/sfera/src/model/network_specific_area.dart
@@ -1,8 +1,10 @@
+import 'package:das_client/sfera/src/model/amount_tram_signals.dart';
import 'package:das_client/sfera/src/model/enums/start_end_qualifier.dart';
import 'package:das_client/sfera/src/model/enums/xml_enum.dart';
import 'package:das_client/sfera/src/model/network_specific_parameter.dart';
import 'package:das_client/sfera/src/model/sfera_xml_element.dart';
import 'package:das_client/sfera/src/model/track_equipment_type_wrapper.dart';
+import 'package:das_client/util/util.dart';
class NetworkSpecificArea extends SferaXmlElement {
static const String elementType = 'NetworkSpecificArea';
@@ -14,17 +16,17 @@ class NetworkSpecificArea extends SferaXmlElement {
StartEndQualifier? get startEndQualifier =>
XmlEnum.valueOf(StartEndQualifier.values, attributes['startEndQualifier']);
- double? get startLocation => _parseOrNull(attributes['startLocation']);
+ double? get startLocation => Util.tryParseDouble(attributes['startLocation']);
- double? get endLocation => _parseOrNull(attributes['endLocation']);
+ double? get endLocation => Util.tryParseDouble(attributes['endLocation']);
Iterable get networkSpecificParameters => children.whereType();
- TrackEquipmentTypeWrapper? get trackEquipmentTypeWrapper => children.whereType().firstOrNull;
+ TrackEquipmentTypeWrapper? get trackEquipmentTypeWrapper =>
+ children.whereType().firstOrNull;
- double? _parseOrNull(String? source) {
- return source != null ? double.parse(source) : null;
- }
+ AmountTramSignals? get amountTramSignals =>
+ children.whereType().firstOrNull;
@override
bool validate() {
diff --git a/das_client/lib/sfera/src/model/network_specific_parameter.dart b/das_client/lib/sfera/src/model/network_specific_parameter.dart
index 0f6aa60b..76214435 100644
--- a/das_client/lib/sfera/src/model/network_specific_parameter.dart
+++ b/das_client/lib/sfera/src/model/network_specific_parameter.dart
@@ -1,3 +1,4 @@
+import 'package:das_client/sfera/src/model/amount_tram_signals.dart';
import 'package:das_client/sfera/src/model/sfera_xml_element.dart';
import 'package:das_client/sfera/src/model/track_equipment_type_wrapper.dart';
import 'package:das_client/sfera/src/model/xml_curve_speed.dart';
@@ -22,6 +23,8 @@ class NetworkSpecificParameter extends SferaXmlElement {
return XmlStationSpeed(attributes: attributes, children: children, value: value);
} else if (attributes?['name'] == XmlGraduatedSpeedInfo.elementName) {
return XmlGraduatedSpeedInfo(attributes: attributes, children: children, value: value);
+ } else if (attributes?['name'] == AmountTramSignals.elementName) {
+ return AmountTramSignals(attributes: attributes, children: children, value: value);
}
return NetworkSpecificParameter(attributes: attributes, children: children, value: value);
}
diff --git a/das_client/lib/sfera/src/model/network_specific_point.dart b/das_client/lib/sfera/src/model/network_specific_point.dart
index 8229ca3c..6c26427e 100644
--- a/das_client/lib/sfera/src/model/network_specific_point.dart
+++ b/das_client/lib/sfera/src/model/network_specific_point.dart
@@ -3,6 +3,7 @@ import 'package:das_client/sfera/src/model/network_specific_parameter.dart';
import 'package:das_client/sfera/src/model/new_line_speed_network_specific_point.dart';
import 'package:das_client/sfera/src/model/sfera_xml_element.dart';
import 'package:das_client/sfera/src/model/sp_generic_point.dart';
+import 'package:das_client/sfera/src/model/whistle_network_specific_point.dart';
class NetworkSpecificPoint extends SpGenericPoint {
static const String elementType = 'NetworkSpecificPoint';
@@ -14,6 +15,8 @@ class NetworkSpecificPoint extends SpGenericPoint {
return NewLineSpeedNetworkSpecificPoint(attributes: attributes, children: children, value: value);
} else if (attributes?['name'] == CurvePointNetworkSpecificPoint.elementName) {
return CurvePointNetworkSpecificPoint(attributes: attributes, children: children, value: value);
+ } else if (attributes?['name'] == WhistleNetworkSpecificPoint.elementName) {
+ return WhistleNetworkSpecificPoint(attributes: attributes, children: children, value: value);
}
return NetworkSpecificPoint(attributes: attributes, children: children, value: value);
}
diff --git a/das_client/lib/sfera/src/model/sp_areas.dart b/das_client/lib/sfera/src/model/sp_areas.dart
index 431a94d6..e6419d51 100644
--- a/das_client/lib/sfera/src/model/sp_areas.dart
+++ b/das_client/lib/sfera/src/model/sp_areas.dart
@@ -5,6 +5,7 @@ import 'package:das_client/sfera/src/model/taf_tap_location.dart';
class SpAreas extends SferaXmlElement {
static const String elementType = 'SP_Areas';
static const String _nonStandardTrackEquipmentName = 'nonStandardTrackEquipment';
+ static const String _tramAreaName = 'tramArea';
SpAreas({super.type = elementType, super.attributes, super.children, super.value});
@@ -12,4 +13,7 @@ class SpAreas extends SferaXmlElement {
Iterable get nonStandardTrackEquipments =>
children.whereType().where((it) => it.name == _nonStandardTrackEquipmentName);
+
+ Iterable get tramAreas =>
+ children.whereType().where((it) => it.name == _tramAreaName);
}
diff --git a/das_client/lib/sfera/src/model/sp_context_information.dart b/das_client/lib/sfera/src/model/sp_context_information.dart
index e018e3e9..80ef75e3 100644
--- a/das_client/lib/sfera/src/model/sp_context_information.dart
+++ b/das_client/lib/sfera/src/model/sp_context_information.dart
@@ -1,5 +1,6 @@
import 'package:das_client/sfera/src/model/connection_track.dart';
import 'package:das_client/sfera/src/model/kilometre_reference_point.dart';
+import 'package:das_client/sfera/src/model/level_crossing_area.dart';
import 'package:das_client/sfera/src/model/sfera_xml_element.dart';
class SpContextInformation extends SferaXmlElement {
@@ -10,4 +11,6 @@ class SpContextInformation extends SferaXmlElement {
Iterable get kilometreReferencePoints => children.whereType();
Iterable get connectionTracks => children.whereType();
+
+ Iterable get levelCrossings => children.whereType();
}
diff --git a/das_client/lib/sfera/src/model/sp_points.dart b/das_client/lib/sfera/src/model/sp_points.dart
index 67ba0f89..9f7b2c8b 100644
--- a/das_client/lib/sfera/src/model/sp_points.dart
+++ b/das_client/lib/sfera/src/model/sp_points.dart
@@ -1,3 +1,4 @@
+import 'package:das_client/sfera/src/model/balise.dart';
import 'package:das_client/sfera/src/model/curve_point_network_specific_point.dart';
import 'package:das_client/sfera/src/model/network_specific_point.dart';
import 'package:das_client/sfera/src/model/new_line_speed_network_specific_point.dart';
@@ -5,6 +6,7 @@ import 'package:das_client/sfera/src/model/sfera_xml_element.dart';
import 'package:das_client/sfera/src/model/signal.dart';
import 'package:das_client/sfera/src/model/timing_point.dart';
import 'package:das_client/sfera/src/model/virtual_balise.dart';
+import 'package:das_client/sfera/src/model/whistle_network_specific_point.dart';
class SpPoints extends SferaXmlElement {
static const String elementType = 'SP_Points';
@@ -16,7 +18,9 @@ class SpPoints extends SferaXmlElement {
Iterable get signals => children.whereType();
- Iterable get balise => children.whereType();
+ Iterable get virtualBalise => children.whereType();
+
+ Iterable get balise => children.whereType();
Iterable get protectionSectionNsp =>
children.whereType().where((it) => it.name == _protectionSectionNspName);
@@ -24,6 +28,7 @@ class SpPoints extends SferaXmlElement {
Iterable get newLineSpeedsNsp =>
children.whereType();
- Iterable get curvePointsNsp =>
- children.whereType();
+ Iterable get curvePointsNsp => children.whereType();
+
+ Iterable get whistleNsp => children.whereType();
}
diff --git a/das_client/lib/sfera/src/model/whistle_network_specific_point.dart b/das_client/lib/sfera/src/model/whistle_network_specific_point.dart
new file mode 100644
index 00000000..b1d66eaa
--- /dev/null
+++ b/das_client/lib/sfera/src/model/whistle_network_specific_point.dart
@@ -0,0 +1,7 @@
+import 'package:das_client/sfera/src/model/network_specific_point.dart';
+
+class WhistleNetworkSpecificPoint extends NetworkSpecificPoint {
+ static const String elementName = 'whistle';
+
+ WhistleNetworkSpecificPoint({super.type, super.attributes, super.children, super.value});
+}
diff --git a/das_client/lib/sfera/src/sfera_reply_parser.dart b/das_client/lib/sfera/src/sfera_reply_parser.dart
index 04c52b08..5f2c0f60 100644
--- a/das_client/lib/sfera/src/sfera_reply_parser.dart
+++ b/das_client/lib/sfera/src/sfera_reply_parser.dart
@@ -1,4 +1,5 @@
import 'package:das_client/sfera/src/model/additional_speed_restriction.dart';
+import 'package:das_client/sfera/src/model/balise.dart';
import 'package:das_client/sfera/src/model/connection_track.dart';
import 'package:das_client/sfera/src/model/current_limitation.dart';
import 'package:das_client/sfera/src/model/current_limitation_change.dart';
@@ -13,6 +14,7 @@ import 'package:das_client/sfera/src/model/handshake_reject.dart';
import 'package:das_client/sfera/src/model/journey_profile.dart';
import 'package:das_client/sfera/src/model/kilometre_reference_point.dart';
import 'package:das_client/sfera/src/model/km_reference.dart';
+import 'package:das_client/sfera/src/model/level_crossing_area.dart';
import 'package:das_client/sfera/src/model/line_speed.dart';
import 'package:das_client/sfera/src/model/location_ident.dart';
import 'package:das_client/sfera/src/model/message_header.dart';
@@ -206,6 +208,10 @@ class SferaReplyParser {
return GraduatedSpeedInfoEntity(type: type, attributes: attributes, children: children, value: value);
case GraduatedSpeedInfo.elementType:
return GraduatedSpeedInfo(type: type, attributes: attributes, children: children, value: value);
+ case Balise.elementType:
+ return Balise(type: type, attributes: attributes, children: children, value: value);
+ case LevelCrossingArea.elementType:
+ return LevelCrossingArea(type: type, attributes: attributes, children: children, value: value);
default:
return SferaXmlElement(type: type, attributes: attributes, children: children, value: value);
}
diff --git a/das_client/lib/util/util.dart b/das_client/lib/util/util.dart
index 33670724..fa1c30b4 100644
--- a/das_client/lib/util/util.dart
+++ b/das_client/lib/util/util.dart
@@ -2,4 +2,8 @@ class Util {
static int? tryParseInt(String? value) {
return value != null ? int.tryParse(value) : null;
}
+
+ static double? tryParseDouble(String? value) {
+ return value != null ? double.tryParse(value) : null;
+ }
}
diff --git a/das_client/test/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data_test.dart b/das_client/test/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data_test.dart
index d8c1d67d..98a39339 100644
--- a/das_client/test/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data_test.dart
+++ b/das_client/test/app/pages/journey/train_journey/widgets/table/cells/track_equipment_render_data_test.dart
@@ -29,9 +29,9 @@ void main() {
);
// WHEN
- final cabSignalingStart = TrackEquipmentRenderData.from(journey, 0);
- final signal = TrackEquipmentRenderData.from(journey, 1);
- final cabSignalingEnd = TrackEquipmentRenderData.from(journey, 2);
+ final cabSignalingStart = TrackEquipmentRenderData.from(journey.data, journey.metadata, 0);
+ final signal = TrackEquipmentRenderData.from(journey.data, journey.metadata, 1);
+ final cabSignalingEnd = TrackEquipmentRenderData.from(journey.data, journey.metadata, 2);
// THEN
expect(cabSignalingStart.isCABStart, isTrue);
@@ -59,11 +59,11 @@ void main() {
);
// WHEN
- final curvePoint = TrackEquipmentRenderData.from(journey, 0);
- final cabSignalingStart = TrackEquipmentRenderData.from(journey, 1);
- final servicePoint = TrackEquipmentRenderData.from(journey, 2);
- final cabSignalingEnd = TrackEquipmentRenderData.from(journey, 3);
- final signal = TrackEquipmentRenderData.from(journey, 4);
+ final curvePoint = TrackEquipmentRenderData.from(journey.data, journey.metadata, 0);
+ final cabSignalingStart = TrackEquipmentRenderData.from(journey.data, journey.metadata, 1);
+ final servicePoint = TrackEquipmentRenderData.from(journey.data, journey.metadata, 2);
+ final cabSignalingEnd = TrackEquipmentRenderData.from(journey.data, journey.metadata, 3);
+ final signal = TrackEquipmentRenderData.from(journey.data, journey.metadata, 4);
// THEN
var expectedHeight = 0.0;
@@ -92,11 +92,11 @@ void main() {
);
// WHEN
- final curvePoint = TrackEquipmentRenderData.from(journey, 0);
- final cabSignaling = TrackEquipmentRenderData.from(journey, 1);
- final servicePoint = TrackEquipmentRenderData.from(journey, 2);
- final signal = TrackEquipmentRenderData.from(journey, 3);
- final connectionTrack = TrackEquipmentRenderData.from(journey, 4);
+ final curvePoint = TrackEquipmentRenderData.from(journey.data, journey.metadata, 0);
+ final cabSignaling = TrackEquipmentRenderData.from(journey.data, journey.metadata, 1);
+ final servicePoint = TrackEquipmentRenderData.from(journey.data, journey.metadata, 2);
+ final signal = TrackEquipmentRenderData.from(journey.data, journey.metadata, 3);
+ final connectionTrack = TrackEquipmentRenderData.from(journey.data, journey.metadata, 4);
// THEN
expect(curvePoint.trackEquipmentType, isNull);
@@ -127,12 +127,12 @@ void main() {
);
// WHEN
- final curvePoint = TrackEquipmentRenderData.from(journey, 0);
- final cabSignaling = TrackEquipmentRenderData.from(journey, 1);
- final servicePoint = TrackEquipmentRenderData.from(journey, 2);
- final signal = TrackEquipmentRenderData.from(journey, 3);
- final connectionTrack = TrackEquipmentRenderData.from(journey, 4);
- final servicePoint2 = TrackEquipmentRenderData.from(journey, 5);
+ final curvePoint = TrackEquipmentRenderData.from(journey.data, journey.metadata, 0);
+ final cabSignaling = TrackEquipmentRenderData.from(journey.data, journey.metadata, 1);
+ final servicePoint = TrackEquipmentRenderData.from(journey.data, journey.metadata, 2);
+ final signal = TrackEquipmentRenderData.from(journey.data, journey.metadata, 3);
+ final connectionTrack = TrackEquipmentRenderData.from(journey.data, journey.metadata, 4);
+ final servicePoint2 = TrackEquipmentRenderData.from(journey.data, journey.metadata, 5);
// THEN
expect(curvePoint.isConventionalExtendedSpeedBorder, isFalse);
diff --git a/das_client/test/model/journey/base_data_extension_test.dart b/das_client/test/model/journey/base_data_extension_test.dart
new file mode 100644
index 00000000..3bacd009
--- /dev/null
+++ b/das_client/test/model/journey/base_data_extension_test.dart
@@ -0,0 +1,104 @@
+import 'package:das_client/app/model/train_journey_settings.dart';
+import 'package:das_client/model/journey/balise.dart';
+import 'package:das_client/model/journey/balise_level_crossing_group.dart';
+import 'package:das_client/model/journey/base_data.dart';
+import 'package:das_client/model/journey/base_data_extension.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
+import 'package:das_client/model/journey/whistles.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ test('Test balise and level crossing grouping', () {
+ final originalRows = [
+ Balise(order: 100, kilometre: [0.1], amountLevelCrossings: 1),
+ LevelCrossing(order: 101, kilometre: [0.11]),
+ Balise(order: 200, kilometre: [0.2], amountLevelCrossings: 1),
+ LevelCrossing(order: 202, kilometre: [0.22]),
+ ];
+
+ final notExpandedSettings = TrainJourneySettings();
+ final groupedRowsNotExpanded = originalRows.groupBaliseAndLeveLCrossings(notExpandedSettings);
+
+ expect(groupedRowsNotExpanded, hasLength(1));
+ expect(groupedRowsNotExpanded[0], isA());
+ expect((groupedRowsNotExpanded[0] as BaliseLevelCrossingGroup).groupedElements, hasLength(4));
+
+ final expandedSettings = TrainJourneySettings(expandedGroups: [100]);
+ final groupedRowsExpanded = originalRows.groupBaliseAndLeveLCrossings(expandedSettings);
+
+ expect(groupedRowsExpanded, hasLength(5));
+ expect(groupedRowsExpanded[0], isA());
+ expect((groupedRowsExpanded[0] as BaliseLevelCrossingGroup).groupedElements, hasLength(4));
+ expect(groupedRowsExpanded[1], isA());
+ expect(groupedRowsExpanded[2], isA());
+ expect(groupedRowsExpanded[3], isA());
+ expect(groupedRowsExpanded[4], isA());
+ });
+
+ test('Test balise and level crossing grouping with different amounts', () {
+ final originalRows = [
+ Balise(order: 100, kilometre: [0.1], amountLevelCrossings: 1),
+ LevelCrossing(order: 101, kilometre: [0.11]),
+ Balise(order: 200, kilometre: [0.2], amountLevelCrossings: 2),
+ LevelCrossing(order: 202, kilometre: [0.22]),
+ LevelCrossing(order: 203, kilometre: [0.23]),
+ ];
+
+ final notExpandedSettings = TrainJourneySettings();
+ final groupedRowsNotExpanded = originalRows.groupBaliseAndLeveLCrossings(notExpandedSettings);
+
+ expect(groupedRowsNotExpanded, hasLength(2));
+ expect(groupedRowsNotExpanded[0], isA());
+ expect((groupedRowsNotExpanded[0] as BaliseLevelCrossingGroup).groupedElements, hasLength(2));
+ expect(groupedRowsNotExpanded[1], isA());
+ expect((groupedRowsNotExpanded[1] as BaliseLevelCrossingGroup).groupedElements, hasLength(3));
+
+ final expandedSettings = TrainJourneySettings(expandedGroups: [200]);
+ final groupedRowsExpanded = originalRows.groupBaliseAndLeveLCrossings(expandedSettings);
+
+ expect(groupedRowsExpanded, hasLength(5));
+ expect(groupedRowsExpanded[0], isA());
+ expect((groupedRowsExpanded[0] as BaliseLevelCrossingGroup).groupedElements, hasLength(2));
+ expect(groupedRowsExpanded[1], isA());
+ expect((groupedRowsExpanded[1] as BaliseLevelCrossingGroup).groupedElements, hasLength(3));
+ expect(groupedRowsExpanded[2], isA());
+ expect(groupedRowsExpanded[3], isA());
+ expect(groupedRowsExpanded[4], isA());
+ });
+
+
+ test('Test balise and level crossing grouping with elements between', () {
+ final originalRows = [
+ Balise(order: 100, kilometre: [0.1], amountLevelCrossings: 1),
+ LevelCrossing(order: 101, kilometre: [0.11]),
+ Whistle(order: 155, kilometre: [0.22]),
+ Balise(order: 200, kilometre: [0.2], amountLevelCrossings: 1),
+ LevelCrossing(order: 202, kilometre: [0.22]),
+ ];
+
+ final notExpandedSettings = TrainJourneySettings();
+ final groupedRowsNotExpanded = originalRows.groupBaliseAndLeveLCrossings(notExpandedSettings);
+
+ expect(groupedRowsNotExpanded, hasLength(3));
+ expect(groupedRowsNotExpanded[0], isA());
+ expect((groupedRowsNotExpanded[0] as BaliseLevelCrossingGroup).groupedElements, hasLength(2));
+ expect(groupedRowsNotExpanded[1], isA());
+ expect(groupedRowsNotExpanded[2], isA());
+ expect((groupedRowsNotExpanded[2] as BaliseLevelCrossingGroup).groupedElements, hasLength(2));
+ });
+
+ test('Test level crossing grouping', () {
+ final originalRows = [
+ LevelCrossing(order: 101, kilometre: [0.11]),
+ LevelCrossing(order: 202, kilometre: [0.22]),
+ LevelCrossing(order: 303, kilometre: [0.33]),
+ ];
+
+ final notExpandedSettings = TrainJourneySettings();
+ final groupedRowsNotExpanded = originalRows.groupBaliseAndLeveLCrossings(notExpandedSettings);
+
+ expect(groupedRowsNotExpanded, hasLength(1));
+ expect(groupedRowsNotExpanded[0], isA());
+ expect((groupedRowsNotExpanded[0] as BaliseLevelCrossingGroup).groupedElements, hasLength(3));
+ });
+}
diff --git a/das_client/test/sfera/mapper/sfera_mapper_test.dart b/das_client/test/sfera/mapper/sfera_mapper_test.dart
index 49bfa48b..886e22f2 100644
--- a/das_client/test/sfera/mapper/sfera_mapper_test.dart
+++ b/das_client/test/sfera/mapper/sfera_mapper_test.dart
@@ -2,11 +2,13 @@ import 'dart:io';
import 'package:collection/collection.dart';
import 'package:das_client/model/journey/additional_speed_restriction_data.dart';
+import 'package:das_client/model/journey/balise.dart';
import 'package:das_client/model/journey/cab_signaling.dart';
import 'package:das_client/model/journey/connection_track.dart';
import 'package:das_client/model/journey/curve_point.dart';
import 'package:das_client/model/journey/datatype.dart';
import 'package:das_client/model/journey/journey.dart';
+import 'package:das_client/model/journey/level_crossing.dart';
import 'package:das_client/model/journey/protection_section.dart';
import 'package:das_client/model/journey/service_point.dart';
import 'package:das_client/model/journey/signal.dart';
@@ -14,6 +16,8 @@ import 'package:das_client/model/journey/speed.dart';
import 'package:das_client/model/journey/speed_change.dart';
import 'package:das_client/model/journey/track_equipment.dart';
import 'package:das_client/model/journey/train_series.dart';
+import 'package:das_client/model/journey/tram_area.dart';
+import 'package:das_client/model/journey/whistles.dart';
import 'package:das_client/sfera/sfera_component.dart';
import 'package:das_client/sfera/src/mapper/sfera_model_mapper.dart';
import 'package:das_client/sfera/src/model/journey_profile.dart';
@@ -582,6 +586,78 @@ void main() {
expect(journey.metadata.breakSeries!.breakSeries, 115);
});
+ test('Test tram area parsed correctly', () async {
+ final journey = getJourney('T7', 1, tcCount: 1);
+ expect(journey.valid, true);
+
+ final tramAreas = journey.data.where((it) => it.type == Datatype.tramArea).cast().toList();
+ expect(tramAreas, hasLength(1));
+ expect(tramAreas[0].order, 900);
+ expect(tramAreas[0].kilometre[0], 37.8);
+ expect(tramAreas[0].amountTramSignals, 6);
+ expect(tramAreas[0].endKilometre, 36.8);
+ });
+
+ test('Test whistle parsed correctly', () async {
+ final journey = getJourney('T7', 1, tcCount: 1);
+ expect(journey.valid, true);
+
+ final whistles = journey.data.where((it) => it.type == Datatype.whistle).cast().toList();
+ expect(whistles, hasLength(1));
+ expect(whistles[0].order, 610);
+ expect(whistles[0].kilometre[0], 39.600);
+ });
+
+ test('Test balise parsed correctly', () async {
+ final journey = getJourney('T7', 1, tcCount: 1);
+ expect(journey.valid, true);
+
+ final balises = journey.data.where((it) => it.type == Datatype.balise).cast().toList();
+ expect(balises, hasLength(8));
+ expect(balises[0].order, 600);
+ expect(balises[0].kilometre[0], 41.552);
+ expect(balises[0].amountLevelCrossings, 1);
+ expect(balises[1].order, 602);
+ expect(balises[1].kilometre[0], 41.190);
+ expect(balises[1].amountLevelCrossings, 1);
+
+ expect(balises[2].order, 604);
+ expect(balises[2].amountLevelCrossings, 1);
+ expect(balises[3].order, 606);
+ expect(balises[3].amountLevelCrossings, 1);
+ expect(balises[4].order, 608);
+ expect(balises[4].amountLevelCrossings, 1);
+
+ expect(balises[5].order, 611);
+ expect(balises[5].amountLevelCrossings, 1);
+ expect(balises[6].order, 613);
+ expect(balises[6].amountLevelCrossings, 2);
+ expect(balises[7].order, 616);
+ expect(balises[7].amountLevelCrossings, 1);
+ });
+
+ test('Test level crossing parsed correctly', () async {
+ final journey = getJourney('T7', 1, tcCount: 1);
+ expect(journey.valid, true);
+
+ final levelCrossings = journey.data.where((it) => it.type == Datatype.levelCrossing).cast().toList();
+ expect(levelCrossings, hasLength(12));
+ expect(levelCrossings[0].order, 601);
+ expect(levelCrossings[0].kilometre[0], 41.492);
+ expect(levelCrossings[1].order, 603);
+ expect(levelCrossings[1].kilometre[0], 41.155);
+ expect(levelCrossings[2].order, 605);
+ expect(levelCrossings[3].order, 607);
+ expect(levelCrossings[4].order, 609);
+ expect(levelCrossings[5].order, 612);
+ expect(levelCrossings[6].order, 614);
+ expect(levelCrossings[7].order, 615);
+ expect(levelCrossings[8].order, 617);
+ expect(levelCrossings[9].order, 1600);
+ expect(levelCrossings[10].order, 1601);
+ expect(levelCrossings[11].order, 1602);
+ });
+
test('Test graduated station speeds are parsed correctly', () async {
final journey = getJourney('T8', 1);
expect(journey.valid, true);
diff --git a/das_client/test/sfera/model/sfera_document_test.dart b/das_client/test/sfera/model/sfera_document_test.dart
index 30c6272e..f55beb47 100644
--- a/das_client/test/sfera/model/sfera_document_test.dart
+++ b/das_client/test/sfera/model/sfera_document_test.dart
@@ -67,10 +67,10 @@ void main() {
expect(spPoint.signals.first.id.physicalId, '102346');
expect(spPoint.signals.first.id.location, 843.0);
- expect(spPoint.balise, hasLength(3));
- expect(spPoint.balise.first.location, '0');
- expect(spPoint.balise.first.position.latitude, '51.48591');
- expect(spPoint.balise.first.position.longitude, '4.73459');
+ expect(spPoint.virtualBalise, hasLength(3));
+ expect(spPoint.virtualBalise.first.location, '0');
+ expect(spPoint.virtualBalise.first.position.latitude, '51.48591');
+ expect(spPoint.virtualBalise.first.position.longitude, '4.73459');
});
test('Test Sfera HandshakeRequest generation', () async {
diff --git a/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml b/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml
new file mode 100644
index 00000000..328dcad3
--- /dev/null
+++ b/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ 1085
+ T7
+ 2022-01-04
+
+
+
+
+ 0085
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1185
+
+
+
diff --git a/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml b/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml
new file mode 100644
index 00000000..5b668811
--- /dev/null
+++ b/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml
@@ -0,0 +1,232 @@
+
+
+
+ 0085
+
+
+
+
+
+ CH
+ 3002
+
+
+
+
+
+
+ CH
+ 3003
+
+
+
+
+
+
+ CH
+ 3004
+
+
+
+
+
+
+ CH
+ 3005
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CH
+ 3002
+
+
+
+
+
+
+ CH
+ 3003
+
+
+
+
+
+
+ CH
+ 3004
+
+
+
+
+
+
+ CH
+ 3005
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_TC_T7_1.xml b/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_TC_T7_1.xml
new file mode 100644
index 00000000..f01ae73d
--- /dev/null
+++ b/das_client/test_resources/T7_Balise_Whistle_TramArea/SFERA_TC_T7_1.xml
@@ -0,0 +1,8 @@
+
+
+ 1185
+
+
+
diff --git a/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml b/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml
index 328dcad3..fd79dde2 100644
--- a/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml
+++ b/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_JP_T7.xml
@@ -9,7 +9,7 @@
2022-01-04
-
+
0085
diff --git a/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml b/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml
index ce795229..51b2d81c 100644
--- a/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml
+++ b/sfera-mock/src/main/resources/static_sfera_resources/T7_Balise_Whistle_TramArea/SFERA_SP_T7_1.xml
@@ -1,7 +1,7 @@
+ SP_ID="T7_1" SP_VersionMajor="1" SP_VersionMinor="3" SP_Length="2000" SP_Status="Valid">
0085
@@ -183,11 +183,11 @@
-
+
-
+