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: base structure of train journey table (#79) #368

Merged
merged 5 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions das_client/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ linter:
rules:
always_use_package_imports: true
prefer_single_quotes: true
prefer_final_in_for_each: true
prefer_final_locals: true
prefer_final_fields: true

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
Expand Down
2 changes: 2 additions & 0 deletions das_client/integration_test/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'di.dart';
import 'test/train_journey_table_test.dart' as train_journey_table_tests;
import 'test/navigation_test.dart' as navigation_tests;
import 'test/train_journey_test.dart' as train_journey_tests;
import 'test/train_search_test.dart' as train_search_tests;
Expand All @@ -18,6 +19,7 @@ void main() {
Fimber.plantTree(DebugTree());

train_journey_tests.main();
train_journey_table_tests.main();
navigation_tests.main();
train_search_tests.main();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class MqttClientUserConnector implements MqttClientConnector {
}

try {
var mqttClientConnectionStatus =
final mqttClientConnectionStatus =
await client.connect(const String.fromEnvironment(mqttUsername), const String.fromEnvironment(mqttPassword));
Fimber.i('mqttClientConnectionStatus=$mqttClientConnectionStatus');

Expand Down
2 changes: 1 addition & 1 deletion das_client/integration_test/test/navigation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void main() {
await prepareAndStartApp(tester);

// check that there is a drawer
var scaffold = find.byWidgetPredicate((widget) => widget is Scaffold).first;
final scaffold = find.byWidgetPredicate((widget) => widget is Scaffold).first;
expect(tester.widget<Scaffold>(scaffold).drawer, isNotNull);

// check that drawer is not shown
Expand Down
69 changes: 69 additions & 0 deletions das_client/integration_test/test/train_journey_table_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import '../app_test.dart';
import '../util/test_utils.dart';

void main() {
group('train journey table test', () {
testWidgets('check if all table columns with header are present', (tester) async {
await prepareAndStartApp(tester);

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

// List of expected column headers
final List<String> expectedHeaders = [
l10n.p_train_journey_table_kilometre_label,
l10n.p_train_journey_table_journey_information_label,
l10n.p_train_journey_table_time_label,
l10n.p_train_journey_table_advised_speed_label,
l10n.p_train_journey_table_braked_weight_speed_label,
l10n.p_train_journey_table_graduated_speed_label,
];

// Check if each header is present in the widget tree
for (final header in expectedHeaders) {
expect(find.text(header), findsOneWidget);
}
});
testWidgets('test scrolling to last train station', (tester) async {
await prepareAndStartApp(tester);

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

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

// check first train station
expect(find.text('ZUE'), findsOneWidget);

// Scroll to last train station
await tester.dragUntilVisible(
find.text('AAR'),
find.byType(ListView),
const Offset(0, -300)
);
});
});
}

/// Verifies, that SBB is selected and loads train journey with [trainNumber]
Future<void> _loadTrainJourney(WidgetTester tester, {required String trainNumber}) async {
// verify we have ru SBB selected.
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

final trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
expect(trainNumberText, findsOneWidget);

await enterText(tester, trainNumberText, trainNumber);

// load train journey
final primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
await tester.tap(primaryButton);

// wait for train journey to load
await tester.pumpAndSettle();
}
2 changes: 1 addition & 1 deletion das_client/integration_test/test/train_journey_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void main() {
expect(find.text(l10n.c_ru_sbb_p), findsOneWidget);

// check that the primary button is enabled
var primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
final primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
expect(tester.widget<SBBPrimaryButton>(primaryButton).onPressed, isNotNull);

// press load Fahrordnung button
Expand Down
18 changes: 9 additions & 9 deletions das_client/integration_test/test/train_search_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ void main() {
// Verify that today is preselected
expect(find.text(Format.date(DateTime.now())), findsOneWidget);

var trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
final trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
expect(trainNumberText, findsOneWidget);

await enterText(tester, trainNumberText, '');

// check that the primary button is disabled
var primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
final primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
expect(tester.widget<SBBPrimaryButton>(primaryButton).onPressed, isNull);

});
Expand All @@ -69,8 +69,8 @@ void main() {
final today = DateTime.now();
final yesterday = today.add(Duration(days: -1));

var todayDateTextFinder = find.text(Format.date(today));
var yesterdayDateTextFinder = find.text(Format.date(yesterday));
final todayDateTextFinder = find.text(Format.date(today));
final yesterdayDateTextFinder = find.text(Format.date(yesterday));

// Verify that today is preselected
expect(todayDateTextFinder, findsOneWidget);
Expand Down Expand Up @@ -101,9 +101,9 @@ void main() {
final yesterday = today.add(Duration(days: -1));
final dayBeforeYesterday = today.add(Duration(days: -2));

var todayDateTextFinder = find.text(Format.date(today));
var yesterdayDateTextFinder = find.text(Format.date(yesterday));
var dayBeforeYesterdayDateTextFinder = find.text(Format.date(dayBeforeYesterday));
final todayDateTextFinder = find.text(Format.date(today));
final yesterdayDateTextFinder = find.text(Format.date(yesterday));
final dayBeforeYesterdayDateTextFinder = find.text(Format.date(dayBeforeYesterday));

// Verify that today is preselected
expect(todayDateTextFinder, findsOneWidget);
Expand Down Expand Up @@ -136,13 +136,13 @@ void main() {
// Verify that today is preselected
expect(find.text(Format.date(DateTime.now())), findsOneWidget);

var trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
final trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description);
expect(trainNumberText, findsOneWidget);

await enterText(tester, trainNumberText, '1234');

// check that the primary button is disabled
var primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
final primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first;
expect(tester.widget<SBBPrimaryButton>(primaryButton).onPressed, isNotNull);

await tapElement(tester, primaryButton);
Expand Down
2 changes: 1 addition & 1 deletion das_client/integration_test/util/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ Future<void> enterText(WidgetTester tester, FinderBase<Element> element, String
}

Finder findTextFieldByLabel(String label) {
var sbbTextField = find.byWidgetPredicate((widget) => widget is SBBTextField && widget.labelText == label);
final sbbTextField = find.byWidgetPredicate((widget) => widget is SBBTextField && widget.labelText == label);
return find.descendant(of: sbbTextField, matching: find.byType(TextField));
}
6 changes: 6 additions & 0 deletions das_client/l10n/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
"p_train_selection_choose_date": "Datum wählen",
"p_train_journey_header_button_dark_theme": "Nachtmodus",
"p_train_journey_header_button_pause": "Pause",
"p_train_journey_table_kilometre_label": "km",
"p_train_journey_table_time_label": "an/ab",
"p_train_journey_table_journey_information_label": "Streckeninformationen",
"p_train_journey_table_advised_speed_label": "FE",
"p_train_journey_table_graduated_speed_label": "OG",
"p_train_journey_table_braked_weight_speed_label": "R150",
"w_navigation_drawer_fahrtinfo_title": "Fahrtinfo",
"w_navigation_drawer_links_title": "Links",
"w_navigation_drawer_settings_title": "Einstellungen",
Expand Down
18 changes: 9 additions & 9 deletions das_client/lib/app/bloc/train_journey_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,34 @@ class TrainJourneyCubit extends Cubit<TrainJourneyState> {
final currentState = state;
if (currentState is SelectingTrainJourneyState) {
final date = currentState.date;
final evu = currentState.ru;
final ru = currentState.ru;
final trainNumber = currentState.trainNumber;
if (evu == null || trainNumber == null) {
if (ru == null || trainNumber == null) {
Fimber.i('company or trainNumber null');
return;
}

emit(ConnectingState(evu, trainNumber, currentState.date));
emit(ConnectingState(ru, trainNumber, currentState.date));
_stateSubscription?.cancel();
_stateSubscription = _sferaService.stateStream.listen((state) {
switch (state) {
case SferaServiceState.connected:
emit(TrainJourneyLoadedState(evu, trainNumber, date));
emit(TrainJourneyLoadedState(ru, trainNumber, date));
break;
case SferaServiceState.connecting:
case SferaServiceState.handshaking:
case SferaServiceState.loadingJourney:
case SferaServiceState.loadingSegments:
emit(ConnectingState(evu, trainNumber, date));
emit(ConnectingState(ru, trainNumber, date));
break;
case SferaServiceState.disconnected:
case SferaServiceState.offline:
emit(SelectingTrainJourneyState(
ru: evu, trainNumber: trainNumber, date: date, errorCode: _sferaService.lastErrorCode));
ru: ru, trainNumber: trainNumber, date: date, errorCode: _sferaService.lastErrorCode));
break;
}
});
_sferaService.connect(OtnId.create(evu.companyCode, trainNumber, date));
_sferaService.connect(OtnId.create(ru.companyCode, trainNumber, date));
}
}

Expand All @@ -68,11 +68,11 @@ class TrainJourneyCubit extends Cubit<TrainJourneyState> {
}
}

void updateCompany(Ru? evu) {
void updateCompany(Ru? ru) {
if (state is SelectingTrainJourneyState) {
emit(SelectingTrainJourneyState(
trainNumber: (state as SelectingTrainJourneyState).trainNumber,
ru: evu,
ru: ru,
date: (state as SelectingTrainJourneyState).date,
errorCode: (state as SelectingTrainJourneyState).errorCode));
}
Expand Down
2 changes: 1 addition & 1 deletion das_client/lib/app/bloc/train_journey_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ abstract class BaseTrainJourneyState extends TrainJourneyState {

@override
String toString() {
return '${runtimeType.toString()}(evu=$ru, trainNumber=$trainNumber, date=$date)';
return '${runtimeType.toString()}(ru=$ru, trainNumber=$trainNumber, date=$date)';
}
}

Expand Down
2 changes: 1 addition & 1 deletion das_client/lib/app/nav/das_navigation_drawer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class DASNavigationDrawer extends StatelessWidget {

Widget _navigationTile(BuildContext context,
{required IconData icon, required String title, required PageRouteInfo route}) {
bool isActiveRoute = context.router.isRouteActive(route.routeName);
final bool isActiveRoute = context.router.isRouteActive(route.routeName);

return ListTile(
leading: isActiveRoute ? _activeIcon(icon) : _inactiveIcon(icon),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:das_client/app/pages/journey/train_journey/widgets/header/adl_notification.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/header/header.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/train_journey.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

// TODO: handle extraLarge font sizes (diff to figma) globally.
Expand All @@ -15,7 +16,7 @@ class TrainJourneyOverview extends StatelessWidget {
Header(),
ADLNotification(
message: 'VMax fahren bis Wettingen',
margin: EdgeInsets.fromLTRB(8, 0, 8, 16),
margin: EdgeInsets.fromLTRB(sbbDefaultSpacing * 0.5, 0, sbbDefaultSpacing * 0.5, sbbDefaultSpacing),
),
Expanded(child: TrainJourney()),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@ class ADLNotification extends StatelessWidget {

@override
Widget build(BuildContext context) {
final isDarkTheme = SBBBaseStyle.of(context).brightness == Brightness.dark;
final fontColor = isDarkTheme ? SBBColors.charcoal : SBBColors.white;
return Container(
margin: margin,
decoration: BoxDecoration(
color: SBBColors.charcoal,
color: isDarkTheme ? SBBColors.cloud : SBBColors.charcoal,
borderRadius: BorderRadius.circular(sbbDefaultSpacing),
),
padding: const EdgeInsets.symmetric(vertical: 14.0)
.copyWith(left: sbbDefaultSpacing, right: 4.0),
padding: const EdgeInsets.symmetric(vertical: 14.0).copyWith(left: sbbDefaultSpacing, right: 4.0),
child: Row(
children: [
const Icon(SBBIcons.circle_information_small, color: SBBColors.white),
Icon(SBBIcons.circle_information_small, color: fontColor),
const SizedBox(width: sbbDefaultSpacing * 0.5),
Text(
'${context.l10n.w_adl_notification_title}: $message',
style: SBBTextStyles.mediumBold.copyWith(color: SBBColors.white),
style: SBBTextStyles.mediumBold.copyWith(color: fontColor),
),
],
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:das_client/app/i18n/i18n.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/header/departure_authorization.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/header/radio_channel.dart';
import 'package:das_client/app/widgets/widget_extensions.dart';
Expand Down Expand Up @@ -70,23 +71,27 @@ class MainContainer extends StatelessWidget {
}

Widget _buttonArea() {
return Row(
children: [
SBBTertiaryButtonLarge(
label: 'Nachtmodus',
icon: SBBIcons.moon_small,
onPressed: () {},
),
SBBTertiaryButtonLarge(
label: 'Pause',
icon: SBBIcons.pause_small,
onPressed: () {},
),
SBBIconButtonLarge(
icon: SBBIcons.context_menu_small,
onPressed: () {},
),
].withSpacing(width: sbbDefaultSpacing * 0.5),
return Builder(
builder: (context) {
return Row(
children: [
SBBTertiaryButtonLarge(
label: context.l10n.p_train_journey_header_button_dark_theme,
icon: SBBIcons.moon_small,
onPressed: () {},
),
SBBTertiaryButtonLarge(
label: context.l10n.p_train_journey_header_button_pause,
icon: SBBIcons.pause_small,
onPressed: () {},
),
SBBIconButtonLarge(
icon: SBBIcons.context_menu_small,
onPressed: () {},
),
].withSpacing(width: sbbDefaultSpacing * 0.5),
);
}
);
}
}
Loading