Skip to content

Commit

Permalink
feat: base structure of train journey table (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
rawi-coding authored Nov 12, 2024
1 parent adf7fb9 commit c90a5be
Show file tree
Hide file tree
Showing 45 changed files with 996 additions and 213 deletions.
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

0 comments on commit c90a5be

Please sign in to comment.