Skip to content

Commit

Permalink
feat: basic fahrbild header with static data (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
rawi-coding committed Oct 24, 2024
1 parent fd87ada commit 9716686
Show file tree
Hide file tree
Showing 20 changed files with 289 additions and 31 deletions.
4 changes: 0 additions & 4 deletions das_client/.fvm/fvm_config.json

This file was deleted.

4 changes: 4 additions & 0 deletions das_client/.fvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"flutter": "3.24.3",
"flavors": {}
}
7 changes: 4 additions & 3 deletions das_client/integration_test/test/navigation_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:das_client/pages/fahrt/fahrt_page.dart';
import 'package:das_client/pages/links/links_page.dart';
import 'package:das_client/pages/profile/profile_page.dart';
import 'package:das_client/pages/settings/settings_page.dart';
import 'package:das_client/pages/train_selection/train_selection_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

Expand Down Expand Up @@ -93,6 +93,7 @@ void main() {
expect(find.byType(ProfilePage), findsOneWidget);
});

// TODO:
testWidgets('test navigate to fahrbild', (tester) async {
// Load app widget.
await prepareAndStartApp(tester);
Expand All @@ -118,8 +119,8 @@ void main() {

await tapElement(tester, find.text(l10n.w_navigation_drawer_fahrtinfo_title));

// Check on FahrtPage
expect(find.byType(FahrtPage), findsOneWidget);
// TODO: Handle TrainSelectionPage/FahrbildPage
expect(find.byType(TrainSelectionPage), findsOneWidget);
});
});
}
2 changes: 1 addition & 1 deletion das_client/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_appauth: 1ce438877bc111c5d8f42da47729909290624886
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
Expand Down
2 changes: 1 addition & 1 deletion das_client/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import UIKit
import Flutter

@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
Expand Down
9 changes: 5 additions & 4 deletions das_client/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ class App extends StatelessWidget {
return MaterialApp.router(
themeMode: ThemeMode.system,
theme: SBBTheme.light(
baseStyle: SBBBaseStyle(
primaryColor: SBBColors.royal,
primaryColorDark: SBBColors.royal125,
)),
baseStyle: SBBBaseStyle(
primaryColor: SBBColors.royal,
primaryColorDark: SBBColors.royal125,
),
),
//darkTheme: SBBTheme.dark(),
localizationsDelegates: localizationDelegates,
supportedLocales: supportedLocales,
Expand Down
24 changes: 19 additions & 5 deletions das_client/lib/nav/app_router.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:auto_route/auto_route.dart';
import 'package:das_client/pages/fahrt/fahrt_page.dart';
import 'package:das_client/pages/train_selection/train_selection_page.dart';
import 'package:das_client/pages/fahrbild/fahrbild_page.dart';
import 'package:das_client/pages/links/links_page.dart';
import 'package:das_client/pages/profile/profile_page.dart';
import 'package:das_client/pages/login/login_page.dart';
Expand All @@ -11,7 +12,15 @@ part 'app_router.gr.dart';
@AutoRouterConfig(replaceInRouteName: 'Page,Route')
class AppRouter extends RootStackRouter {
@override
List<AutoRoute> get routes => [_splash, _login, _fahrt, _links, _settings, _profile];
List<AutoRoute> get routes => [
_splash,
_login,
_trainSelection,
_fahrbild,
_links,
_settings,
_profile,
];

@override
get defaultRouteType => const RouteType.custom();
Expand All @@ -30,9 +39,14 @@ final _login = AutoRoute(
page: LoginRoute.page,
);

final _fahrt = AutoRoute(
path: '/fahrt',
page: FahrtRoute.page,
final _trainSelection = AutoRoute(
path: '/train_selection',
page: TrainSelectionRoute.page,
);

final _fahrbild = AutoRoute(
path: '/fahrbild',
page: FahrbildRoute.page,
);

final _links = AutoRoute(
Expand Down
2 changes: 1 addition & 1 deletion das_client/lib/nav/das_navigation_drawer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class DASNavigationDrawer extends StatelessWidget {
context,
icon: SBBIcons.route_circle_start_small,
title: context.l10n.w_navigation_drawer_fahrtinfo_title,
route: const FahrtRoute(),
route: const FahrbildRoute(),
),
_navigationTile(
context,
Expand Down
60 changes: 60 additions & 0 deletions das_client/lib/pages/fahrbild/fahrbild_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import 'package:auto_route/auto_route.dart';
import 'package:das_client/bloc/fahrbild_cubit.dart';
import 'package:das_client/nav/app_router.dart';
import 'package:das_client/nav/das_navigation_drawer.dart';
import 'package:das_client/pages/fahrbild/widgets/fahrbild.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// TODO: discuss general naming in DEV team
@RoutePage()
class FahrbildPage extends StatelessWidget {
const FahrbildPage({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(context),
body: _body(context),
drawer: const DASNavigationDrawer(),
);
}

SBBHeader _appBar(BuildContext context) {
return SBBHeader(
title: 'Fahrbild',
// TODO: Workaround as otherwise the SBB logo is shown
actions: const [SizedBox.shrink()],
leadingWidget: Builder(
builder: (context) => IconButton(
icon: const Icon(SBBIcons.hamburger_menu_small),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
);
}

Widget _body(BuildContext context) {
return Column(
children: [
Expanded(child: _content()),
],
);
}

Widget _content() {
return BlocBuilder<FahrbildCubit, FahrbildState>(
builder: (context, state) {
if (state is FahrbildLoadedState) {
return const Fahrbild();
} else if (state is FahrbildLoadedState) {
// TODO: unsexy, as Listener doesn't use initial state.
context.router.replace(const TrainSelectionRoute());
}

return const Center(child: CircularProgressIndicator());
},
);
}
}
17 changes: 17 additions & 0 deletions das_client/lib/pages/fahrbild/widgets/fahrbild.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:das_client/pages/fahrbild/widgets/header/header.dart';
import 'package:das_client/pages/fahrbild/widgets/train_journey.dart';
import 'package:flutter/material.dart';

class Fahrbild extends StatelessWidget {
const Fahrbild({super.key});

@override
Widget build(BuildContext context) {
return Column(
children: [
Header(),
Expanded(child: TrainJourney()),
],
);
}
}
25 changes: 25 additions & 0 deletions das_client/lib/pages/fahrbild/widgets/header/button_area.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

class ButtonArea extends StatelessWidget {
const ButtonArea({super.key});

@override
Widget build(BuildContext context) {
return Row(
children: [
SBBTertiaryButtonLarge(label: 'Button', onPressed: () {}),
SBBIconButtonLarge(icon: SBBIcons.tick_small, onPressed: () {}),
SBBIconButtonLarge(icon: SBBIcons.context_menu_small, onPressed: () {}),
].withSpacing(8.0),
);
}
}

// extensions

extension _Spacing on List<Widget> {
withSpacing(double width) {
return expand((x) => [SizedBox(width: width), x]).skip(1).toList();
}
}
78 changes: 78 additions & 0 deletions das_client/lib/pages/fahrbild/widgets/header/header.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'package:das_client/pages/fahrbild/widgets/header/button_area.dart';
import 'package:das_client/pages/fahrbild/widgets/header/next_stop.dart';
import 'package:das_client/pages/fahrbild/widgets/header/punctuality_display.dart';
import 'package:das_client/pages/fahrbild/widgets/header/radio_channel.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

class Header extends StatelessWidget {
const Header({super.key});

@override
Widget build(BuildContext context) {
return Stack(
children: [
_background(context),
_group(context),
],
);
}

Widget _background(BuildContext context) {
final primary = Theme.of(context).colorScheme.secondary;
return Container(
color: primary,
height: 16.0,
);
}

Widget _group(BuildContext context) {
return SBBGroup(
margin: const EdgeInsetsDirectional.fromSTEB(8, 0, 8, 16),
padding: const EdgeInsets.all(16).copyWith(bottom: 8.0),
useShadow: true,
child: SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_topHeaderRow(),
_divider(),
_bottomHeaderRow(),
],
),
),
);
}

Widget _bottomHeaderRow() {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 6.0),
child: Row(
children: [
RadioChannel(),
SizedBox(width: 48.0),
NextStop(),
],
),
);
}

Widget _divider() {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Divider(height: 1.0, color: SBBColors.cloud),
);
}

Widget _topHeaderRow() {
return const Row(
children: [
Expanded(
child: PunctualityDisplay(),
),
ButtonArea(),
],
);
}
}
17 changes: 17 additions & 0 deletions das_client/lib/pages/fahrbild/widgets/header/next_stop.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

class NextStop extends StatelessWidget {
const NextStop({super.key});

@override
Widget build(BuildContext context) {
return Row(
children: [
const Icon(SBBIcons.station_small),
const SizedBox(width: 8.0),
Text('Baden', style: SBBTextStyles.largeLight),
],
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

class PunctualityDisplay extends StatelessWidget {
const PunctualityDisplay({super.key});

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Text('05:43:00', style: SBBTextStyles.largeBold.copyWith(fontSize: 24.0)),
const SizedBox(width: 8.0),
Text('+00:01:30', style: SBBTextStyles.largeLight.copyWith(fontSize: 24.0)),
],
),
);
}
}
20 changes: 20 additions & 0 deletions das_client/lib/pages/fahrbild/widgets/header/radio_channel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

class RadioChannel extends StatelessWidget {
const RadioChannel({super.key});

@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: const BoxConstraints(minWidth: 240.0),
child: Row(
children: [
const Icon(SBBIcons.telephone_gsm_small),
const SizedBox(width: 8.0),
Text('1311', style: SBBTextStyles.largeLight),
],
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

class Fahrbild extends StatelessWidget {
const Fahrbild({super.key});
class TrainJourney extends StatelessWidget {
const TrainJourney({super.key});

@override
Widget build(BuildContext context) {
Expand Down
2 changes: 1 addition & 1 deletion das_client/lib/pages/login/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class _LoginPageState extends State<LoginPage> {
try {
await authenticator.login();
if (context.mounted) {
context.router.replace(const FahrtRoute());
context.router.replace(const TrainSelectionRoute());
}
} catch (e) {
Fimber.d('Login failed', ex: e);
Expand Down
2 changes: 1 addition & 1 deletion das_client/lib/pages/login/splash_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SplashPage extends StatelessWidget {
return BlocBuilder<AuthCubit, AuthState>(
builder: (context, state) {
if (state is Authenticated) {
context.router.replace(const FahrtRoute());
context.router.replace(const TrainSelectionRoute());
} else if (state is Unauthenticated) {
context.router.replace(const LoginRoute());
}
Expand Down
Loading

0 comments on commit 9716686

Please sign in to comment.