Skip to content

Commit

Permalink
feat: implement langsamfahrstellen (#87) (#413)
Browse files Browse the repository at this point in the history
Co-authored-by: u221638 <[email protected]>
  • Loading branch information
Grodien and rawi-coding authored Nov 28, 2024
1 parent c5603a0 commit 4fd494c
Show file tree
Hide file tree
Showing 52 changed files with 2,355 additions and 138 deletions.
5 changes: 5 additions & 0 deletions das_client/assets/icons/icon_additional_speed_restriction.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
133 changes: 102 additions & 31 deletions das_client/integration_test/test/train_journey_table_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
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/cells/bracket_station_body.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/cells/route_cell_body.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/protection_section_row.dart';
Expand All @@ -12,6 +13,63 @@ import '../util/test_utils.dart';

void main() {
group('train journey table test', () {
testWidgets('test additional speed restriction row is displayed correctly', (tester) async {
await prepareAndStartApp(tester);

// load train journey by filling out train selection page
await _loadTrainJourney(tester, trainNumber: '500');

final scrollableFinder = find.byType(ListView);
expect(scrollableFinder, findsOneWidget);

final asrRow = findDASTableRowByText('km 64.200 - km 47.200');
expect(asrRow, findsOneWidget);

final asrIcon = find.descendant(
of: asrRow, matching: find.byKey(AdditionalSpeedRestrictionRow.additionalSpeedRestrictionIconKey));
expect(asrIcon, findsOneWidget);

final asrSpeed = find.descendant(of: asrRow, matching: find.text('60'));
expect(asrSpeed, findsOneWidget);

// check all cells are colored
final coloredCells = find.descendant(
of: asrRow,
matching: find.byWidgetPredicate((it) =>
it is Container &&
it.decoration is BoxDecoration &&
(it.decoration as BoxDecoration).color == AdditionalSpeedRestrictionRow.additionalSpeedRestrictionColor));
expect(coloredCells, findsNWidgets(11));
});

testWidgets('test other rows are displayed correctly', (tester) async {
await prepareAndStartApp(tester);

// load train journey by filling out train selection page
await _loadTrainJourney(tester, trainNumber: '500');

final scrollableFinder = find.byType(ListView);
expect(scrollableFinder, findsOneWidget);

final testRows = ['Genève', 'km 32.2', 'Lengnau', 'WANZ'];

for (final rowText in testRows) {
await tester.dragUntilVisible(find.text(rowText), scrollableFinder, const Offset(0, -50));

final testRow = findDASTableRowByText(rowText);
expect(testRow, findsOneWidget);

// check first 3 cells are colored
final coloredCells = find.descendant(
of: testRow,
matching: find.byWidgetPredicate((it) =>
it is Container &&
it.decoration is BoxDecoration &&
(it.decoration as BoxDecoration).color == AdditionalSpeedRestrictionRow.additionalSpeedRestrictionColor));
expect(coloredCells, findsNWidgets(3));
}
});

testWidgets('check if all table columns with header are present', (tester) async {
await prepareAndStartApp(tester);

Expand All @@ -34,6 +92,38 @@ void main() {
}
});

testWidgets('test route is displayed correctly', (tester) async {
await prepareAndStartApp(tester);

// load train journey by filling out train selection page
await _loadTrainJourney(tester, trainNumber: '9999');

final scrollableFinder = find.byType(ListView);
expect(scrollableFinder, findsOneWidget);

final stopRouteRow = findDASTableRowByText('Bahnhof A');
final nonStoppingPassRouteRow = findDASTableRowByText('Haltestelle B');
expect(stopRouteRow, findsOneWidget);
expect(nonStoppingPassRouteRow, findsOneWidget);

// check stop circles
final stopRoute = find.descendant(of: stopRouteRow, matching: find.byKey(RouteCellBody.stopKey));
final nonStoppingPassRoute =
find.descendant(of: nonStoppingPassRouteRow, matching: find.byKey(RouteCellBody.stopKey));
expect(stopRoute, findsOneWidget);
expect(nonStoppingPassRoute, findsNothing);

// check route start
final routeStart = find.byKey(RouteCellBody.routeStartKey);
expect(routeStart, findsOneWidget);

await tester.dragUntilVisible(find.byKey(RouteCellBody.routeEndKey), scrollableFinder, const Offset(0, -50));

// check route end
final routeEnd = find.byKey(RouteCellBody.routeEndKey);
expect(routeEnd, findsOneWidget);
});

testWidgets('test protection secions are displayed correctly', (tester) async {
await prepareAndStartApp(tester);

Expand All @@ -54,7 +144,8 @@ void main() {
expect(find.descendant(of: protectionSectionRow, matching: find.text('FL')), findsOneWidget);
expect(find.descendant(of: protectionSectionRow, matching: find.text('32.2')), findsOneWidget);
// Verify icon is displayed
expect(find.descendant(of: protectionSectionRow, matching: find.byKey(ProtectionSectionRow.protectionSectionKey)), findsOneWidget);
expect(find.descendant(of: protectionSectionRow, matching: find.byKey(ProtectionSectionRow.protectionSectionKey)),
findsOneWidget);

// Scroll to next protection section
await tester.dragUntilVisible(find.text('Yverdon-les-Bains'), scrollableFinder, const Offset(0, -20));
Expand Down Expand Up @@ -157,6 +248,11 @@ void main() {
// load train journey by filling out train selection page
await _loadTrainJourney(tester, trainNumber: '9999');

final scrollableFinder = find.byType(ListView);
expect(scrollableFinder, findsOneWidget);

await tester.dragUntilVisible(find.text('Klammerbahnhof D1'), scrollableFinder, const Offset(0, -50));

final bracketStationD = findDASTableRowByText('Klammerbahnhof D');
final bracketStationD1 = findDASTableRowByText('Klammerbahnhof D1');
expect(bracketStationD, findsOneWidget);
Expand All @@ -181,6 +277,11 @@ void main() {
// load train journey by filling out train selection page
await _loadTrainJourney(tester, trainNumber: '9999');

final scrollableFinder = find.byType(ListView);
expect(scrollableFinder, findsOneWidget);

await tester.dragUntilVisible(find.text('Halt auf Verlangen C'), scrollableFinder, const Offset(0, -50));

final stopOnDemandRow = findDASTableRowByText('Halt auf Verlangen C');
expect(stopOnDemandRow, findsOneWidget);

Expand All @@ -195,34 +296,6 @@ void main() {
expect(stopRoute, findsNothing);
});

testWidgets('test route is displayed correctly', (tester) async {
await prepareAndStartApp(tester);

// load train journey by filling out train selection page
await _loadTrainJourney(tester, trainNumber: '9999');

final stopRouteRow = findDASTableRowByText('Bahnhof A');
final nonStoppingPassRouteRow = findDASTableRowByText('Haltestelle B');
expect(stopRouteRow, findsOneWidget);
expect(nonStoppingPassRouteRow, findsOneWidget);

// check stop circles
final stopRoute = find.descendant(of: stopRouteRow, matching: find.byKey(RouteCellBody.stopKey));
final nonStoppingPassRoute = find.descendant(of: nonStoppingPassRouteRow, matching: find.byKey(RouteCellBody.stopKey));
expect(stopRoute, findsOneWidget);
expect(nonStoppingPassRoute, findsNothing);

// check route start
final startStationRow = findDASTableRowByText('Bahnhof A');
final routeStart = find.descendant(of: startStationRow, matching: find.byKey(RouteCellBody.routeStartKey));
expect(routeStart, findsOneWidget);

// check route end
final endStationRow = findDASTableRowByText('Klammerbahnhof D1');
final routeEnd = find.descendant(of: endStationRow, matching: find.byKey(RouteCellBody.routeEndKey));
expect(routeEnd, findsOneWidget);
});

testWidgets('test halt is displayed italic', (tester) async {
await prepareAndStartApp(tester);

Expand All @@ -237,8 +310,6 @@ void main() {
.byWidgetPredicate((it) => it is Text && it.data == 'Schlieren' && it.style?.fontStyle != FontStyle.italic);
expect(schlierenText, findsOneWidget);
});


});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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/additional_speed_restriction_data.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

class AdditionalSpeedRestrictionRow extends BaseRowBuilder<AdditionalSpeedRestrictionData> {
static const Key additionalSpeedRestrictionIconKey = Key('addition_speed_restrction_icon_key');
static const Color additionalSpeedRestrictionColor = SBBColors.orange;

AdditionalSpeedRestrictionRow({
super.height = 44.0,
required super.metadata,
required super.data,
}) : super(rowColor: additionalSpeedRestrictionColor);

@override
DASTableCell informationCell(BuildContext context) {
return DASTableCell(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('${context.l10n.p_train_journey_table_kilometre_label} ${data.restriction.kmFrom.toStringAsFixed(3)} '
'- ${context.l10n.p_train_journey_table_kilometre_label} ${data.restriction.kmTo.toStringAsFixed(3)}'),
],
),
);
}

@override
DASTableCell iconsCell2(BuildContext context) {
return DASTableCell(
child: SvgPicture.asset(
AppAssets.iconAdditionalSpeedRestriction,
key: additionalSpeedRestrictionIconKey,
),
alignment: Alignment.center);
}

@override
DASTableCell graduatedSpeedCell(BuildContext context) {
return DASTableCell(
child: Text(data.restriction.speed.toString()),
alignment: Alignment.center,
);
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
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/cells/route_cell_body.dart';
import 'package:das_client/app/widgets/table/das_table_cell.dart';
import 'package:das_client/app/widgets/table/das_table_row.dart';
import 'package:das_client/model/journey/additional_speed_restriction.dart';
import 'package:das_client/model/journey/base_data.dart';
import 'package:das_client/model/journey/metadata.dart';
import 'package:flutter/material.dart';

abstract class BaseRowBuilder extends DASTableRowBuilder {
class BaseRowBuilder<T extends BaseData> extends DASTableRowBuilder {
const BaseRowBuilder({
super.height,
this.kilometre,
super.height = 44.0,
this.defaultAlignment = Alignment.bottomCenter,
this.rowColor,
this.isCurrentPosition = false,
required this.metadata,
required this.data,
});

final List<double>? kilometre;
final Alignment defaultAlignment;
final Color? rowColor;
final bool isCurrentPosition;
final Metadata metadata;
final T data;

@override
DASTableRow build(BuildContext context) {
Expand All @@ -39,31 +43,37 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
}

DASTableCell kilometreCell(BuildContext context) {
if (kilometre == null || kilometre!.isEmpty) {
if (data.kilometre.isEmpty) {
return DASTableCell.empty();
}

return DASTableCell(
color: getSpecialCellColor(),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(kilometre![0].toStringAsFixed(1)),
if (kilometre!.length > 1) Text(kilometre![1].toStringAsFixed(1))
Text(data.kilometre[0].toStringAsFixed(1)),
if (data.kilometre.length > 1) Text(data.kilometre[1].toStringAsFixed(1))
],
),
alignment: Alignment.centerLeft);
}

DASTableCell timeCell(BuildContext context) {
return DASTableCell(child: Text('06:05:52'), alignment: defaultAlignment);
return DASTableCell(color: getSpecialCellColor(), child: Text('06:05:52'), alignment: defaultAlignment);
}

DASTableCell routeCell(BuildContext context) {
return DASTableCell(
color: getSpecialCellColor(),
padding: EdgeInsets.all(0.0),
alignment: null,
child: RouteCellBody(isCurrentPosition: isCurrentPosition),
child: RouteCellBody(
isCurrentPosition: metadata.currentPosition == data,
isRouteStart: metadata.routeStart == data,
isRouteEnd: metadata.routeEnd == data,
),
);
}

Expand All @@ -72,15 +82,15 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
}

DASTableCell graduatedSpeedCell(BuildContext context) {
return DASTableCell(child: Text('85'), alignment: defaultAlignment);
return DASTableCell.empty();
}

DASTableCell advisedSpeedCell(BuildContext context) {
return DASTableCell(child: Text('100'), alignment: defaultAlignment);
return DASTableCell.empty();
}

DASTableCell brakedWeightSpeedCell(BuildContext context) {
return DASTableCell(child: Text('95'), alignment: defaultAlignment);
return DASTableCell.empty();
}

// TODO: clarify use of different icon cells and set appropriate name
Expand All @@ -101,4 +111,16 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
DASTableCell actionsCell(BuildContext context) {
return DASTableCell.empty();
}

Color? getSpecialCellColor() {
return getAdditionalSpeedRestriction() != null
? AdditionalSpeedRestrictionRow.additionalSpeedRestrictionColor
: null;
}

AdditionalSpeedRestriction? getAdditionalSpeedRestriction() {
return metadata.additionalSpeedRestrictions
.where((it) => it.orderFrom <= data.order && it.orderTo >= data.order)
.firstOrNull;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ class RouteCellBody extends StatelessWidget {
final isDarkTheme = SBBBaseStyle.of(context).brightness == Brightness.dark;
final lineColor = isDarkTheme ? SBBColors.white : SBBColors.black;
return Positioned(
key: isRouteStart ? routeStartKey : isRouteEnd ? routeEndKey : null,
key: isRouteStart
? routeStartKey
: isRouteEnd
? routeEndKey
: null,
top: isRouteStart ? height - sbbDefaultSpacing : -sbbDefaultSpacing,
bottom: isRouteEnd ? sbbDefaultSpacing : -sbbDefaultSpacing,
right: 0,
Expand Down
Loading

0 comments on commit 4fd494c

Please sign in to comment.