Skip to content

Commit

Permalink
Merge branch 'main' into 82-graduated-station-speeds
Browse files Browse the repository at this point in the history
# Conflicts:
#	das_client/lib/sfera/src/mapper/sfera_model_mapper.dart
#	das_client/lib/sfera/src/model/network_specific_parameter.dart
#	das_client/lib/sfera/src/sfera_reply_parser.dart
#	das_client/test/sfera/mapper/sfera_mapper_test.dart
  • Loading branch information
rawi-coding committed Jan 15, 2025
2 parents 68ffd4a + 27379a2 commit 59f0a0d
Show file tree
Hide file tree
Showing 50 changed files with 1,339 additions and 64 deletions.
5 changes: 5 additions & 0 deletions das_client/assets/icons/icon_balise.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions das_client/assets/icons/icon_km_indicator.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions das_client/assets/icons/icon_tram_area.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions das_client/assets/icons/icon_whistle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 91 additions & 0 deletions das_client/integration_test/test/train_journey_table_test.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand All @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions das_client/l10n/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 4 additions & 0 deletions das_client/lib/app/bloc/train_journey_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class TrainJourneyCubit extends Cubit<TrainJourneyState> {
void updateBreakSeries(BreakSeries selectedBreakSeries) {
_settingsSubject.add(_settingsSubject.value.copyWith(selectedBreakSeries: selectedBreakSeries));
}

void updateExpandedGroups(List<int> expandedGroups) {
_settingsSubject.add(_settingsSubject.value.copyWith(expandedGroups: expandedGroups));
}
}

extension ContextBlocExtension on BuildContext {
Expand Down
5 changes: 4 additions & 1 deletion das_client/lib/app/model/train_journey_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<int> expandedGroups;

TrainJourneySettings copyWith({BreakSeries? selectedBreakSeries}) {
TrainJourneySettings copyWith({BreakSeries? selectedBreakSeries, List<int>? expandedGroups}) {
return TrainJourneySettings(
selectedBreakSeries: selectedBreakSeries ?? this.selectedBreakSeries,
expandedGroups: expandedGroups ?? this.expandedGroups,
);
}
}
Original file line number Diff line number Diff line change
@@ -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<BaliseLevelCrossingGroup> {
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<Balise>().length;

int get _levelCrossingCount => data.groupedElements.whereType<LevelCrossing>().length;
}
Original file line number Diff line number Diff line change
@@ -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<Balise> {
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,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class BaseRowBuilder<T extends BaseData> extends DASTableRowBuilder {
this.trackEquipmentRenderData = const TrackEquipmentRenderData(),
this.defaultAlignment = Alignment.bottomCenter,
this.rowColor,
this.onTap,
this.isGrouped = false,
});

final Alignment defaultAlignment;
Expand All @@ -29,12 +31,15 @@ class BaseRowBuilder<T extends BaseData> 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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -23,30 +23,29 @@ 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<BaseData> 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,
);
}

/// 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<BaseData> 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;
Expand All @@ -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;
}

Expand All @@ -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<BaseData> 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;
Expand Down
Loading

0 comments on commit 59f0a0d

Please sign in to comment.