Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement langsamfahrstellen (#87) #413

Merged
merged 15 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 41 additions & 26 deletions das_client/integration_test/test/train_journey_table_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,37 @@ 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 Down Expand Up @@ -157,6 +188,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 +217,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,33 +236,7 @@ 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 Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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> {
rawi-coding marked this conversation as resolved.
Show resolved Hide resolved
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,
});

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

@override
DASTableCell iconsCell3(BuildContext context) {
return DASTableCell(child: const SizedBox.shrink(), color: additionalSpeedRestrictionColor);
}

@override
DASTableCell iconsCell1(BuildContext context) {
return DASTableCell(child: const SizedBox.shrink(), color: additionalSpeedRestrictionColor);
}

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

@override
DASTableCell graduatedSpeedCell(BuildContext context) {
return DASTableCell(
color: additionalSpeedRestrictionColor,
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 {
Grodien marked this conversation as resolved.
Show resolved Hide resolved
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,7 +43,7 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
}

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

Expand All @@ -48,8 +52,8 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
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);
Expand All @@ -63,7 +67,11 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
return DASTableCell(
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,
backgroundColor: getRouteCellColor()),
);
}

Expand All @@ -72,15 +80,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 +109,16 @@ abstract class BaseRowBuilder extends DASTableRowBuilder {
DASTableCell actionsCell(BuildContext context) {
return DASTableCell.empty();
}

Color? getRouteCellColor() {
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 @@ -19,6 +19,7 @@ class RouteCellBody extends StatelessWidget {
this.isCurrentPosition = false,
this.isRouteStart = false,
this.isRouteEnd = false,
this.backgroundColor,
rawi-coding marked this conversation as resolved.
Show resolved Hide resolved
});

final double chevronHeight;
Expand All @@ -32,6 +33,8 @@ class RouteCellBody extends StatelessWidget {
final bool isRouteStart;
final bool isRouteEnd;

final Color? backgroundColor;

@override
Widget build(BuildContext context) {
return LayoutBuilder(
Expand All @@ -41,6 +44,7 @@ class RouteCellBody extends StatelessWidget {
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
if (backgroundColor != null) _background(),
_routeLine(context, height),
if (isCurrentPosition) _chevron(context),
if (isStop) _circle(context),
Expand All @@ -50,11 +54,27 @@ class RouteCellBody extends StatelessWidget {
);
}

Widget _background() {
return Positioned(
top: -sbbDefaultSpacing,
bottom: -sbbDefaultSpacing,
right: 0,
left: 0,
child: Container(
color: backgroundColor,
),
);
}

Positioned _routeLine(BuildContext context, double height) {
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,29 @@ 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/metadata.dart';
import 'package:das_client/model/journey/protection_section.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

class ProtectionSectionRow extends BaseRowBuilder {
class ProtectionSectionRow extends BaseRowBuilder<ProtectionSection> {
static const Key protectionSectionKey = Key('protection_section_key');

ProtectionSectionRow({
super.height = 44.0,
required this.metadata,
required this.protectionSection,
}) : super(rowColor: SBBColors.peach, kilometre: protectionSection.kilometre);

final Metadata metadata;
final ProtectionSection protectionSection;
required super.metadata,
required super.data,
}) : super(rowColor: SBBColors.peach);

@override
DASTableCell informationCell(BuildContext context) {
return DASTableCell(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${context.l10n.p_train_journey_table_kilometre_label} ${protectionSection.kilometre[0].toStringAsFixed(1)}'),
Text('${context.l10n.p_train_journey_table_kilometre_label} ${data.kilometre[0].toStringAsFixed(1)}'),
Spacer(),
Text('${protectionSection.isOptional ? 'F' : ''}${protectionSection.isLong ? 'L' : ''}'),
Text('${data.isOptional ? 'F' : ''}${data.isLong ? 'L' : ''}'),
],
),
);
Expand Down
Loading