diff --git a/das_client/.gitignore b/das_client/.gitignore index 306a60d4..417046a6 100644 --- a/das_client/.gitignore +++ b/das_client/.gitignore @@ -7,9 +7,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/das_client/integration_test/app_test.dart b/das_client/integration_test/app_test.dart index eb9c831b..e5d4fbcd 100644 --- a/das_client/integration_test/app_test.dart +++ b/das_client/integration_test/app_test.dart @@ -9,7 +9,6 @@ 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; AppLocalizations l10n = AppLocalizationsDe(); @@ -18,7 +17,6 @@ void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); Fimber.plantTree(DebugTree()); - train_journey_tests.main(); train_journey_table_tests.main(); navigation_tests.main(); train_search_tests.main(); diff --git a/das_client/integration_test/test/train_journey_test.dart b/das_client/integration_test/test/train_journey_test.dart deleted file mode 100644 index 42750308..00000000 --- a/das_client/integration_test/test/train_journey_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:das_client/app/pages/journey/train_journey/widgets/header/header.dart'; -import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../app_test.dart'; -import '../util/test_utils.dart'; - -void main() { - group('home screen test', () { - testWidgets('load train journey company=1085, train=T9999', (tester) async { - // Load app widget. - await prepareAndStartApp(tester); - - // Verify we have train number with T9999. - expect(find.text('T9999'), findsOneWidget); - - // Verify we have ru SBB. - expect(find.text(l10n.c_ru_sbb_p), findsOneWidget); - - // check that the primary button is enabled - final primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first; - expect(tester.widget(primaryButton).onPressed, isNotNull); - - // press load train journey button - await tester.tap(primaryButton); - - // wait for train journey to load - await tester.pumpAndSettle(); - - // check if station is present - expect(find.text('Bahnhof A'), findsOneWidget); - - await tester.pumpAndSettle(); - }); - - testWidgets('show the correct next stop', (tester) async { - // Load app widget. - await prepareAndStartApp(tester); - - // - final trainNumberText = findTextFieldByLabel(l10n.p_train_selection_trainnumber_description); - expect(trainNumberText, findsOneWidget); - - await enterText(tester, trainNumberText, 'T6'); - - final primaryButton = find.byWidgetPredicate((widget) => widget is SBBPrimaryButton).first; - await tester.tap(primaryButton); - - // wait for train journey to load - await tester.pumpAndSettle(); - - //find the header and check if it is existent - final headerFinder = find.byType(Header); - expect(headerFinder, findsOneWidget); - - //Find the text in the header - expect(find.descendant(of: headerFinder, matching: find.text('Hardbrücke')), findsOneWidget); - - await tester.pumpAndSettle(); - }); - }); -} diff --git a/das_client/integration_test/test/train_search_test.dart b/das_client/integration_test/test/train_search_test.dart index acb52828..37bf7f7a 100644 --- a/das_client/integration_test/test/train_search_test.dart +++ b/das_client/integration_test/test/train_search_test.dart @@ -70,7 +70,7 @@ void main() { final yesterday = today.add(Duration(days: -1)); final todayDateTextFinder = find.text(Format.date(today)); - final yesterdayDateTextFinder = find.text('${Format.date(yesterday)} ${l10n.p_train_selection_date_not_today_warning}'); + final yesterdayDateTextFinder = find.text(Format.date(yesterday)); // Verify that today is preselected expect(todayDateTextFinder, findsOneWidget); @@ -90,6 +90,8 @@ void main() { expect(todayDateTextFinder, findsNothing); expect(yesterdayDateTextFinder, findsOneWidget); + final warningMessage = find.text(l10n.p_train_selection_date_not_today_warning); + expect(warningMessage, findsOneWidget); }); @@ -102,7 +104,7 @@ void main() { final dayBeforeYesterday = today.add(Duration(days: -2)); final todayDateTextFinder = find.text(Format.date(today)); - final yesterdayDateTextFinder = find.text('${Format.date(yesterday)} ${l10n.p_train_selection_date_not_today_warning}'); + final yesterdayDateTextFinder = find.text(Format.date(yesterday)); final dayBeforeYesterdayDateTextFinder = find.text(Format.date(dayBeforeYesterday)); // Verify that today is preselected @@ -123,6 +125,8 @@ void main() { expect(todayDateTextFinder, findsNothing); expect(yesterdayDateTextFinder, findsOneWidget); + final warningMessage = find.text(l10n.p_train_selection_date_not_today_warning); + expect(warningMessage, findsOneWidget); expect(dayBeforeYesterdayDateTextFinder, findsNothing); }); @@ -147,7 +151,8 @@ void main() { await tapElement(tester, primaryButton); - expect(find.text('${ErrorCode.sferaJpUnavailable.code}: ${l10n.c_error_sfera_jp_unavailable}'), findsOneWidget); + expect(find.text('${l10n.c_error_code}: ${ErrorCode.sferaJpUnavailable.code}'), findsOneWidget); + expect(find.text(l10n.c_error_sfera_jp_unavailable), findsOneWidget); }); }); diff --git a/das_client/ios/Podfile.lock b/das_client/ios/Podfile.lock index 2e39e64c..1318dfb1 100644 --- a/das_client/ios/Podfile.lock +++ b/das_client/ios/Podfile.lock @@ -57,13 +57,13 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa - device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d + device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_appauth: aef998cfbcc307dff7f2fbe1f59a50323748dc25 flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 - package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 PODFILE CHECKSUM: d9dad56c0cd0b4fd8b4fe3034a53fd42a0b990f6 diff --git a/das_client/l10n/strings_de.arb b/das_client/l10n/strings_de.arb index d4f8ae78..7bddbe1d 100644 --- a/das_client/l10n/strings_de.arb +++ b/das_client/l10n/strings_de.arb @@ -4,7 +4,7 @@ "p_train_selection_ru_description": "EVU", "p_train_selection_date_description": "Datum", "p_train_selection_choose_date": "Datum wählen", - "p_train_selection_date_not_today_warning": "(⚠\uFE0Fentspricht nicht dem aktuellen Datum)", + "p_train_selection_date_not_today_warning": "Das gewählte Datum entspricht nicht dem aktuellen Datum.", "p_train_journey_header_button_dark_theme": "Nachtmodus", "p_train_journey_header_button_pause": "Pause", "p_train_journey_table_kilometre_label": "km", @@ -32,12 +32,15 @@ "c_ru_bls_c": "BLS Cargo", "c_ru_sob": "SOB", "c_unknown": "Unbekannt", + "c_train_number": "Zugnummer", "c_main_signal_function_entry": "Einfahrsignal", "c_main_signal_function_exit": "Ausfahrsignal", "c_main_signal_function_intermediate": "Abschnittsignal", "c_main_signal_function_block": "Block", "c_main_signal_function_protection": "Deckungssignal", "c_main_signal_function_laneChange": "Spurwechsel", + "c_error_code": "Fehlercode", + "c_something_went_wrong": "Da ist was schiefgegangen.", "c_error_connection_failed": "Verbindung fehlgeschlagen", "c_error_sfera_validation_failed": "Validierung der Daten fehlgeschlagen", "c_error_sfera_handshake_rejected": "Server hat die Verbindung abgelehnt", diff --git a/das_client/lib/app/nav/das_navigation_drawer.dart b/das_client/lib/app/nav/das_navigation_drawer.dart index 96ee9fbd..feba07a1 100644 --- a/das_client/lib/app/nav/das_navigation_drawer.dart +++ b/das_client/lib/app/nav/das_navigation_drawer.dart @@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:das_client/app/i18n/i18n.dart'; import 'package:das_client/app/nav/app_router.dart'; import 'package:das_client/app/widgets/app_version_text.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/app/widgets/device_id_text.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -55,7 +56,7 @@ class DASNavigationDrawer extends StatelessWidget { return ListTile( leading: isActiveRoute ? _activeIcon(icon) : _inactiveIcon(icon), - title: Text(title, style: isActiveRoute ? SBBTextStyles.mediumBold : SBBTextStyles.mediumLight), + title: Text(title, style: isActiveRoute ? DASTextStyles.mediumBold : DASTextStyles.mediumLight), onTap: () { Navigator.pop(context); context.router.replace(route); diff --git a/das_client/lib/app/pages/journey/journey_page.dart b/das_client/lib/app/pages/journey/journey_page.dart index f5550acb..d0721d89 100644 --- a/das_client/lib/app/pages/journey/journey_page.dart +++ b/das_client/lib/app/pages/journey/journey_page.dart @@ -1,15 +1,17 @@ import 'package:auto_route/auto_route.dart'; import 'package:das_client/app/bloc/train_journey_cubit.dart'; import 'package:das_client/app/i18n/i18n.dart'; +import 'package:das_client/app/model/ru.dart'; import 'package:das_client/app/nav/app_router.dart'; import 'package:das_client/app/nav/das_navigation_drawer.dart'; import 'package:das_client/app/pages/journey/train_journey/train_journey_overview.dart'; import 'package:das_client/app/pages/journey/train_selection/train_selection.dart'; import 'package:das_client/auth/authentication_component.dart'; import 'package:das_client/di.dart'; -import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; +import 'package:das_client/util/format.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; @RoutePage() class JourneyPage extends StatelessWidget { @@ -36,22 +38,20 @@ class JourneyPageContent extends StatelessWidget { ); } - SBBHeader _appBar(BuildContext context) { - return SBBHeader( - title: context.l10n.c_app_name, - actions: [ - IconButton( - icon: const Icon(SBBIcons.exit_small), - onPressed: () { - if (context.trainJourneyCubit.state is SelectingTrainJourneyState) { - context.authCubit.logout(); - context.router.replace(const LoginRoute()); - } else { - context.trainJourneyCubit.reset(); - } - }, - ) - ], + PreferredSizeWidget _appBar(BuildContext context) { + return PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight), + child: BlocBuilder( + builder: (context, state) { + return SBBHeader( + title: _headerTitle(context, state), + actions: [ + if (state is SelectingTrainJourneyState) _logoutButton(context), + if (state is! SelectingTrainJourneyState) _trainSelectionButton(context) + ], + ); + }, + ), ); } @@ -76,4 +76,31 @@ class JourneyPageContent extends StatelessWidget { }, ); } + + IconButton _logoutButton(BuildContext context) { + return IconButton( + icon: const Icon(SBBIcons.exit_small), + onPressed: () { + context.authCubit.logout(); + context.router.replace(const LoginRoute()); + }, + ); + } + + IconButton _trainSelectionButton(BuildContext context) { + return IconButton( + icon: const Icon(SBBIcons.train_small), + onPressed: () => context.trainJourneyCubit.reset(), + ); + } + + String _headerTitle(BuildContext context, TrainJourneyState state) { + if (state is TrainJourneyLoadedState) { + final trainNumber = '${context.l10n.c_train_number} ${state.trainNumber}'; + final ru = state.ru.displayText(context); + final date = Format.dateWithAbbreviatedDay(state.date); + return '$trainNumber - $ru - $date'; + } + return context.l10n.c_app_name; + } } diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection.dart b/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection.dart index aff897ce..78f871c3 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection.dart @@ -1,6 +1,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:das_client/app/i18n/i18n.dart'; import 'package:das_client/app/pages/journey/train_journey/widgets/break_series_selection_button.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/model/journey/break_series.dart'; import 'package:das_client/model/journey/train_series.dart'; import 'package:flutter/material.dart'; @@ -86,7 +87,7 @@ class _BreakSeriesSelectionState extends State { padding: const EdgeInsets.fromLTRB(0, sbbDefaultSpacing, 0, sbbDefaultSpacing), child: Text( trainSeries.name, - style: SBBTextStyles.mediumBold, + style: DASTextStyles.mediumBold, ), ), Padding( diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection_button.dart b/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection_button.dart index 45425ba2..2ee553c8 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection_button.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/break_series_selection_button.dart @@ -1,4 +1,5 @@ import 'package:das_client/app/widgets/assets.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; @@ -28,7 +29,7 @@ class BreakSeriesSelectionButton extends StatelessWidget { child: Center( child: Text( label, - style: SBBTextStyles.mediumBold.copyWith(color: currentlySelected ? SBBColors.white : SBBColors.black), + style: DASTextStyles.mediumBold.copyWith(color: currentlySelected ? SBBColors.white : SBBColors.black), ), ), ), diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/header/adl_notification.dart b/das_client/lib/app/pages/journey/train_journey/widgets/header/adl_notification.dart index df382bac..39223d86 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/header/adl_notification.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/header/adl_notification.dart @@ -1,4 +1,5 @@ import 'package:das_client/app/i18n/i18n.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -25,7 +26,7 @@ class ADLNotification extends StatelessWidget { const SizedBox(width: sbbDefaultSpacing * 0.5), Text( '${context.l10n.w_adl_notification_title}: $message', - style: SBBTextStyles.mediumBold.copyWith(color: fontColor), + style: DASTextStyles.mediumBold.copyWith(color: fontColor), ), ], ), diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/header/departure_authorization.dart b/das_client/lib/app/pages/journey/train_journey/widgets/header/departure_authorization.dart index e5eafbd0..8b8ed55a 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/header/departure_authorization.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/header/departure_authorization.dart @@ -1,3 +1,4 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -10,7 +11,7 @@ class DepartureAuthorization extends StatelessWidget { children: [ const Icon(SBBIcons.circle_tick_small), const SizedBox(width: sbbDefaultSpacing * 0.5), - Text('SMS', style: SBBTextStyles.largeLight.copyWith(fontSize: 24.0)), + Text('SMS', style: DASTextStyles.largeRoman), ], ); } diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/header/main_container.dart b/das_client/lib/app/pages/journey/train_journey/widgets/header/main_container.dart index 1390e46a..012f561a 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/header/main_container.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/header/main_container.dart @@ -3,6 +3,7 @@ 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/assets.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/app/widgets/widget_extensions.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -77,8 +78,10 @@ class MainContainer extends StatelessWidget { Expanded( child: Padding( padding: const EdgeInsets.only(left: sbbDefaultSpacing * 0.5), - child: Text(journey.metadata.nextStop?.name.localized ?? context.l10n.c_unknown, - style: SBBTextStyles.largeLight.copyWith(fontSize: 24.0)), + child: Text( + journey.metadata.nextStop?.name.localized ?? context.l10n.c_unknown, + style: DASTextStyles.xLargeLight, + ), ), ), _buttonArea(), diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/header/radio_channel.dart b/das_client/lib/app/pages/journey/train_journey/widgets/header/radio_channel.dart index 89f00d47..43825480 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/header/radio_channel.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/header/radio_channel.dart @@ -1,3 +1,4 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -12,7 +13,7 @@ class RadioChannel extends StatelessWidget { children: [ const Icon(SBBIcons.telephone_gsm_small), const SizedBox(width: sbbDefaultSpacing * 0.5), - Text('1311', style: SBBTextStyles.largeLight.copyWith(fontSize: 24.0)), + Text('1311', style: DASTextStyles.largeRoman), ], ), ); diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/header/time_container.dart b/das_client/lib/app/pages/journey/train_journey/widgets/header/time_container.dart index 20c2caaf..396d2283 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/header/time_container.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/header/time_container.dart @@ -1,3 +1,4 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -22,15 +23,9 @@ class TimeContainer extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - '05:43:00', - style: SBBTextStyles.largeBold.copyWith(fontSize: 24.0), - ), + Text('05:43:00', style: DASTextStyles.xLargeBold), _divider(), - Text( - '+00:01:30', - style: SBBTextStyles.largeLight.copyWith(fontSize: 24.0), - ), + Text('+00:01:30', style: DASTextStyles.xLargeLight), ], ), ), diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/bracket_station_cell_body.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/bracket_station_cell_body.dart index 00c27293..de47b70c 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/bracket_station_cell_body.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/cells/bracket_station_cell_body.dart @@ -1,3 +1,4 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/model/journey/bracket_station.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; @@ -33,7 +34,7 @@ class BracketStationCellBody extends StatelessWidget { quarterTurns: -1, child: Text( bracketStation.mainStationAbbreviation ?? '', - style: SBBTextStyles.extraSmallBold.copyWith( + style: DASTextStyles.extraSmallBold.copyWith( color: SBBColors.white, fontSize: _bracketStationFontSize, height: _bracketStationWidth / _bracketStationFontSize, diff --git a/das_client/lib/app/pages/journey/train_journey/widgets/table/service_point_row.dart b/das_client/lib/app/pages/journey/train_journey/widgets/table/service_point_row.dart index 19dad2dd..3ce47053 100644 --- a/das_client/lib/app/pages/journey/train_journey/widgets/table/service_point_row.dart +++ b/das_client/lib/app/pages/journey/train_journey/widgets/table/service_point_row.dart @@ -3,6 +3,7 @@ import 'package:das_client/app/pages/journey/train_journey/widgets/table/cells/b 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/cells/track_equipment_cell_body.dart'; import 'package:das_client/app/widgets/assets.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/app/widgets/table/das_table_cell.dart'; import 'package:das_client/model/journey/service_point.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; @@ -25,9 +26,8 @@ class ServicePointRow extends BaseRowBuilder { @override DASTableCell informationCell(BuildContext context) { final servicePointName = data.name.localized; - final textStyle = data.isStation - ? SBBTextStyles.largeBold.copyWith(fontSize: 24.0) - : SBBTextStyles.largeLight.copyWith(fontSize: 24.0, fontStyle: FontStyle.italic); + final textStyle = + data.isStation ? DASTextStyles.xLargeBold : DASTextStyles.xLargeLight.copyWith(fontStyle: FontStyle.italic); return DASTableCell( alignment: defaultAlignment, child: Row( diff --git a/das_client/lib/app/pages/journey/train_selection/train_selection.dart b/das_client/lib/app/pages/journey/train_selection/train_selection.dart index ed01fc07..fb57dcc7 100644 --- a/das_client/lib/app/pages/journey/train_selection/train_selection.dart +++ b/das_client/lib/app/pages/journey/train_selection/train_selection.dart @@ -22,7 +22,7 @@ class _TrainSelectionState extends State { @override void initState() { super.initState(); - _trainNumberController = TextEditingController(text: 'T9999'); + _trainNumberController = TextEditingController(); _dateController = TextEditingController(); context.trainJourneyCubit.updateTrainNumber(_trainNumberController.text); @@ -35,9 +35,9 @@ class _TrainSelectionState extends State { if (state is SelectingTrainJourneyState) { return Column( children: [ - Header(child: _headerWidgets(context, state)), + _header(context, state), Spacer(), - _errorWidget(context, state), + _errorMessage(context, state), Spacer(), _loadButton(context, state) ], @@ -49,17 +49,22 @@ class _TrainSelectionState extends State { ); } - Widget _headerWidgets(BuildContext context, SelectingTrainJourneyState state) { - return Column( - children: [ - _trainNumberWidget(), - _dateDisplayWidget(state), - _ruSelectionWidget(context, state), - ], + Widget _header(BuildContext context, SelectingTrainJourneyState state) { + return Header( + information: !DateUtils.isSameDay(state.date, DateTime.now()) + ? context.l10n.p_train_selection_date_not_today_warning + : null, + child: Column( + children: [ + _trainNumberInput(), + _dateInput(state), + _ruSelection(context, state), + ], + ), ); } - Widget _trainNumberWidget() { + Widget _trainNumberInput() { return Padding( padding: const EdgeInsets.fromLTRB(sbbDefaultSpacing, sbbDefaultSpacing, 0, sbbDefaultSpacing / 2), child: SBBTextField( @@ -71,12 +76,8 @@ class _TrainSelectionState extends State { ); } - Widget _dateDisplayWidget(SelectingTrainJourneyState state) { - if (DateUtils.isSameDay(state.date, DateTime.now())) { - _dateController.text = Format.date(state.date); - } else { - _dateController.text = '${Format.date(state.date)} ${context.l10n.p_train_selection_date_not_today_warning}'; - } + Widget _dateInput(SelectingTrainJourneyState state) { + _dateController.text = Format.date(state.date); return Padding( padding: const EdgeInsets.fromLTRB(sbbDefaultSpacing, 0, 0, sbbDefaultSpacing / 2), @@ -91,7 +92,7 @@ class _TrainSelectionState extends State { ); } - Widget _ruSelectionWidget(BuildContext context, SelectingTrainJourneyState state) { + Widget _ruSelection(BuildContext context, SelectingTrainJourneyState state) { return Padding( padding: const EdgeInsets.fromLTRB(sbbDefaultSpacing, 0, 0, sbbDefaultSpacing), child: SBBSelect( @@ -104,9 +105,14 @@ class _TrainSelectionState extends State { ); } - Widget _errorWidget(BuildContext context, SelectingTrainJourneyState state) { + Widget _errorMessage(BuildContext context, SelectingTrainJourneyState state) { if (state.errorCode != null) { - return Text(state.errorCode!.displayTextWithErrorCode(context), style: SBBTextStyles.mediumBold); + return SBBMessage( + illustration: MessageIllustration.Display, + title: context.l10n.c_something_went_wrong, + description: state.errorCode!.displayText(context), + messageCode: '${context.l10n.c_error_code}: ${state.errorCode!.code.toString()}', + ); } return Container(); } diff --git a/das_client/lib/app/widgets/app_version_text.dart b/das_client/lib/app/widgets/app_version_text.dart index 139670f1..cb81b6b8 100644 --- a/das_client/lib/app/widgets/app_version_text.dart +++ b/das_client/lib/app/widgets/app_version_text.dart @@ -1,3 +1,4 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -23,8 +24,7 @@ class AppVersionText extends StatelessWidget { const SizedBox( width: sbbDefaultSpacing / 2, ), - Text(info.version, - style: SBBTextStyles.smallLight.copyWith(color: color)), + Text(info.version, style: DASTextStyles.smallLight.copyWith(color: color)), ], ); } else { diff --git a/das_client/lib/app/widgets/das_text_styles.dart b/das_client/lib/app/widgets/das_text_styles.dart new file mode 100644 index 00000000..8883e574 --- /dev/null +++ b/das_client/lib/app/widgets/das_text_styles.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; + +const String sbbWebFont = 'packages/sbb_design_system_mobile/SBBWeb'; + +class DASTextStyles { + DASTextStyles._(); + + static const double xLargeFontSize = 24.0; + static const double xLargeFontHeight = 32.0 / xLargeFontSize; + + static const TextStyle xLargeBold = TextStyle( + fontSize: xLargeFontSize, + height: xLargeFontHeight, + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w700, + fontFamily: sbbWebFont, + ); + + static const TextStyle xLargeRoman = TextStyle( + fontSize: xLargeFontSize, + height: xLargeFontHeight, + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w400, + fontFamily: sbbWebFont, + ); + + static const TextStyle xLargeLight = TextStyle( + fontSize: xLargeFontSize, + height: xLargeFontHeight, + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w300, + fontFamily: sbbWebFont, + ); + + static const TextStyle largeBold = SBBTextStyles.largeBold; + + static const TextStyle largeRoman = TextStyle( + fontSize: SBBTextStyles.largeFontSize, + height: SBBTextStyles.largeFontHeight, + fontStyle: FontStyle.normal, + fontWeight: FontWeight.w400, + fontFamily: sbbWebFont, + ); + + static const TextStyle largeLight = SBBTextStyles.largeLight; + + static const TextStyle mediumBold = SBBTextStyles.mediumBold; + + static const TextStyle mediumLight = SBBTextStyles.mediumLight; + + static const TextStyle smallLight = SBBTextStyles.smallLight; + + static const TextStyle extraSmallBold = SBBTextStyles.extraSmallBold; + +} \ No newline at end of file diff --git a/das_client/lib/app/widgets/device_id_text.dart b/das_client/lib/app/widgets/device_id_text.dart index 8b417bb3..cc7c4c3e 100644 --- a/das_client/lib/app/widgets/device_id_text.dart +++ b/das_client/lib/app/widgets/device_id_text.dart @@ -1,5 +1,5 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/util/device_id_info.dart'; -import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; class DeviceIdText extends StatelessWidget { @@ -14,7 +14,7 @@ class DeviceIdText extends StatelessWidget { builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { final deviceId = snapshot.data as String? ?? ''; - return Text(deviceId, style: SBBTextStyles.smallLight.copyWith(color: color)); + return Text(deviceId, style: DASTextStyles.smallLight.copyWith(color: color)); } else { return const SizedBox.shrink(); } diff --git a/das_client/lib/app/widgets/header.dart b/das_client/lib/app/widgets/header.dart index b4f4dbc8..ce7ce16e 100644 --- a/das_client/lib/app/widgets/header.dart +++ b/das_client/lib/app/widgets/header.dart @@ -1,11 +1,15 @@ +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:sbb_design_system_mobile/sbb_design_system_mobile.dart'; import 'package:flutter/material.dart'; class Header extends StatelessWidget { - const Header({required this.child, super.key}); + const Header({required this.child, super.key, this.information}); final Widget child; + /// information text is shown below header card if given. + final String? information; + @override Widget build(BuildContext context) { return Stack( @@ -25,15 +29,39 @@ class Header extends StatelessWidget { } Widget _container(BuildContext context) { - return SBBGroup( + return Container( margin: const EdgeInsetsDirectional.fromSTEB( sbbDefaultSpacing * 0.5, 0, sbbDefaultSpacing * 0.5, sbbDefaultSpacing, ), - useShadow: false, - child: child, + decoration: BoxDecoration( + color: SBBColors.cloud, + borderRadius: BorderRadius.all(Radius.circular(sbbDefaultSpacing)), + ), + child: Column( + children: [ + SBBGroup( + useShadow: false, + child: child, + ), + if (information != null) _information(), + ], + ), + ); + } + + Widget _information() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: sbbDefaultSpacing, vertical: sbbDefaultSpacing * 0.5), + child: Row( + spacing: sbbDefaultSpacing * 0.5, + children: [ + Icon(SBBIcons.circle_information_small, size: 20.0), + Text(information!, style: DASTextStyles.smallLight), + ], + ), ); } } diff --git a/das_client/lib/app/widgets/table/das_table.dart b/das_client/lib/app/widgets/table/das_table.dart index 0388bfd2..3655c7d6 100644 --- a/das_client/lib/app/widgets/table/das_table.dart +++ b/das_client/lib/app/widgets/table/das_table.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:collection/collection.dart'; +import 'package:das_client/app/widgets/das_text_styles.dart'; import 'package:das_client/app/widgets/table/das_table_cell.dart'; import 'package:das_client/app/widgets/table/das_table_column.dart'; import 'package:das_client/app/widgets/table/das_table_row.dart'; @@ -84,8 +85,8 @@ class DASTable extends StatelessWidget { final borderColor = isDarkTheme ? SBBColors.iron : SBBColors.cloud; return DASTableThemeData( backgroundColor: isDarkTheme ? SBBColors.charcoal : SBBColors.white, - headingTextStyle: SBBTextStyles.smallLight, - dataTextStyle: SBBTextStyles.largeLight, + headingTextStyle: DASTextStyles.smallLight, + dataTextStyle: DASTextStyles.largeRoman, headingRowBorder: Border(bottom: BorderSide(width: 2, color: borderColor)), tableBorder: TableBorder( horizontalInside: BorderSide(width: 1, color: borderColor), diff --git a/das_client/lib/util/format.dart b/das_client/lib/util/format.dart index 192caf1c..04b5f7c6 100644 --- a/das_client/lib/util/format.dart +++ b/das_client/lib/util/format.dart @@ -28,6 +28,12 @@ class Format { return dateFormat.format(localDate); } + static String dateWithAbbreviatedDay(DateTime date) { + final localDate = date.toLocal(); + final dateFormat = DateFormat('E. dd.MM.yyyy'); + return dateFormat.format(localDate); + } + static String time(DateTime date, {bool showSeconds = true}) { final localDate = date.toLocal(); final format = showSeconds ? DateFormat.HOUR24_MINUTE_SECOND : DateFormat.HOUR24_MINUTE;