Skip to content

Commit

Permalink
feat: added basic service point row and improved DAS table code. (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
rawi-coding committed Nov 7, 2024
1 parent 847b492 commit ada2c39
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 40 deletions.
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_company_placeholder": "z.B. 0085",
"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 neu",
"p_train_journey_table_journey_information_label": "Streckeninformationen",
"p_train_journey_table_advised_speed_label": "FE",
"p_train_journey_table_og_label": "OG",
"p_train_journey_table_r150_label": "R150",
"w_navigation_drawer_fahrtinfo_title": "Fahrtinfo",
"w_navigation_drawer_links_title": "Links",
"w_navigation_drawer_settings_title": "Einstellungen",
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
@@ -0,0 +1,120 @@
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/sfera/sfera_component.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

// TODO: Extract real values from SFERA objects.
@immutable
class ServicePointRow extends DASTableRowBuilder {
const ServicePointRow({
this.timingPoint,
this.timingPointConstraints,
this.active = false,
super.height = 64.0,
});

final TimingPoint? timingPoint;
final TimingPointConstraints? timingPointConstraints;
final bool active;

final Alignment _defaultRowAlignment = Alignment.bottomCenter;

@override
DASTableRow build(BuildContext context) {
return DASTableRow(
height: height,
color: active ? SBBColors.royal.withOpacity(0.2) : null,
cells: [
_kilometre(),
_time(),
_route(),
_iconsPlaceholder(),
_journeyInformation(),
_iconsPlaceholder(),
_iconsPlaceholder(),
_og(),
_r150(),
_advisedSpeed(),
_actions(),
],
);
}

DASTableCell _kilometre() {
return DASTableCell(child: Text('10.2'), alignment: _defaultRowAlignment);
}

DASTableCell _time() {
return DASTableCell(child: Text('06:05:52'), alignment: _defaultRowAlignment);
}

DASTableCell _route() {
return DASTableCell(
padding: EdgeInsets.all(0.0),
alignment: null,
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
if (active)
Positioned(
bottom: sbbDefaultSpacing,
child: Container(
width: 14.0,
height: 14.0,
decoration: BoxDecoration(
color: SBBColors.black,
shape: BoxShape.circle,
),
),
),
Positioned(
top: -sbbDefaultSpacing,
bottom: -sbbDefaultSpacing,
right: 0,
left: 0,
child: VerticalDivider(thickness: 2.0, color: SBBColors.black),
),
],
),
);
}

// TODO: clarify use of different icon columns
DASTableCell _iconsPlaceholder() {
return DASTableCell.empty();
}

DASTableCell _journeyInformation() {
final servicePointName = timingPoint?.names.first.name ?? 'Unknown';
return DASTableCell(
alignment: _defaultRowAlignment,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: Text(servicePointName, style: SBBTextStyles.largeBold.copyWith(fontSize: 24.0))),
if (true) Text('B12'),
],
),
);
}

// TODO: clarify name
DASTableCell _og() {
return DASTableCell(child: Text('85'), alignment: _defaultRowAlignment);
}

DASTableCell _advisedSpeed() {
return DASTableCell(child: Text('100'), alignment: _defaultRowAlignment);
}

// TODO: clarify name
DASTableCell _r150() {
return DASTableCell(child: Text('95'), alignment: _defaultRowAlignment);
}

DASTableCell _actions() {
return DASTableCell.empty();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import 'package:das_client/app/bloc/train_journey_cubit.dart';
import 'package:das_client/app/i18n/i18n.dart';
import 'package:das_client/app/pages/journey/train_journey/widgets/table/service_point_row.dart';
import 'package:das_client/app/widgets/table/das_table.dart';
import 'package:das_client/app/widgets/table/das_table_column.dart';
import 'package:das_client/sfera/sfera_component.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';
Expand All @@ -12,19 +16,21 @@ class TrainJourney extends StatelessWidget {
final bloc = context.trainJourneyCubit;

return StreamBuilder<List<dynamic>>(
stream: CombineLatestStream.list([bloc.journeyStream, bloc.segmentStream]),
builder: (context, snapshot) {
JourneyProfile? journeyProfile = snapshot.data?[0];
List<SegmentProfile> segmentProfiles = snapshot.data?[1] ?? [];
if (journeyProfile == null) {
return Container();
}
stream: CombineLatestStream.list([bloc.journeyStream, bloc.segmentStream]),
builder: (context, snapshot) {
JourneyProfile? journeyProfile = snapshot.data?[0];
List<SegmentProfile> segmentProfiles = snapshot.data?[1] ?? [];
if (journeyProfile == null) {
return Container();
}

return _body(journeyProfile, segmentProfiles);
});
return _body(context, journeyProfile, segmentProfiles);
},
);
}

Widget _body(
BuildContext context,
JourneyProfile journeyProfile,
List<SegmentProfile> segmentProfiles,
) {
Expand All @@ -34,32 +40,53 @@ class TrainJourney extends StatelessWidget {

final points = segmentProfiles.expand((it) => it.points?.timingPoints.toList() ?? <TimingPoint>[]);

return SingleChildScrollView(
child: Column(
children: [
return Padding(
padding: const EdgeInsets.symmetric(horizontal: sbbDefaultSpacing * 0.5),
child: DASTable(
columns: _columns(context),
rows: [
...List.generate(timingPoints.length, (index) {
var timingPoint = timingPoints[index];
var tpId = timingPoint.timingPointReference.children.whereType<TpIdReference>().firstOrNull?.tpId;
var tp = points.where((point) => point.id == tpId).firstOrNull;
return Padding(
padding: const EdgeInsets.all(sbbDefaultSpacing * 0.5),
child: Row(
children: [
_arrivalTime(timingPoint),
const SizedBox(width: sbbDefaultSpacing),
_servicePointName(tp),
],
),
);

return ServicePointRow(
timingPoint: tp,
timingPointConstraints: timingPoint,
active: index == 1,
).build(context);
})
],
),
);
}

Widget _servicePointName(TimingPoint? tp) => Text(tp?.names.first.name ?? 'Unknown');

Widget _arrivalTime(TimingPointConstraints timingPoint) {
return Text(timingPoint.attributes['TP_PlannedLatestArrivalTime'] ?? '');
List<DASTableColumn> _columns(BuildContext context) {
return [
DASTableColumn(child: Text(context.l10n.p_train_journey_table_kilometre_label), width: 64.0),
DASTableColumn(child: Text(context.l10n.p_train_journey_table_time_label), width: 100.0),
DASTableColumn(width: 48.0), // route column
DASTableColumn(width: 64.0), // icons column
DASTableColumn(
child: Text(context.l10n.p_train_journey_table_journey_information_label),
expanded: true,
alignment: Alignment.centerLeft,
),
DASTableColumn(width: 68.0), // icons column
DASTableColumn(width: 48.0), // icons column
DASTableColumn(
// TODO: how is OG called generally
child: Text(context.l10n.p_train_journey_table_og_label),
width: 100.0,
border: BorderDirectional(
bottom: BorderSide(color: SBBColors.cloud, width: 1.0),
end: BorderSide(color: SBBColors.cloud, width: 2.0),
),
),
// TODO: how is R150 called generally
DASTableColumn(child: Text(context.l10n.p_train_journey_table_r150_label), width: 62.0),
DASTableColumn(child: Text(context.l10n.p_train_journey_table_advised_speed_label), width: 62.0),
DASTableColumn(width: 40.0), // actions
];
}
}
26 changes: 17 additions & 9 deletions das_client/lib/app/widgets/table/das_table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class DASTable extends StatelessWidget {
this.themeData = const DASTableThemeData(
backgroundColor: SBBColors.white,
headingTextStyle: SBBTextStyles.smallLight,
dataTextStyle: SBBTextStyles.largeLight,
headingRowBorder: Border(bottom: BorderSide(width: 2, color: SBBColors.cloud)),
tableBorder: TableBorder(
horizontalInside: BorderSide(width: 1, color: SBBColors.cloud),
Expand Down Expand Up @@ -95,14 +96,18 @@ class DASTable extends StatelessWidget {
width: column.width,
child: Container(
decoration: BoxDecoration(
border: column.border ?? tableThemeData?.headingRowBorder,
border: tableThemeData?.headingRowBorder ?? column.border,
color: column.color ?? tableThemeData?.headingRowColor,
),
padding: column.padding,
child: DefaultTextStyle(
style: DefaultTextStyle.of(context).style.merge(tableThemeData?.headingTextStyle),
child: column.child,
),
child: column.child == null
? SizedBox.shrink()
: DefaultTextStyle(
style: DefaultTextStyle.of(context).style.merge(tableThemeData?.headingTextStyle),
child: column.alignment != null
? Align(alignment: column.alignment!, child: column.child)
: column.child!,
),
),
);
});
Expand All @@ -112,14 +117,17 @@ class DASTable extends StatelessWidget {
return _FlexibleHeightRow(
fixedHeight: row.height,
children: List.generate(columns.length, (index) {
return _dataCell(row.cells[index], columns[index], isLast: columns.length - 1 == index);
final cell = row.cells[index];
final column = columns[index];
return _dataCell(cell, column, row, isLast: columns.length - 1 == index);
}),
);
}

Widget _dataCell(DASTableCell cell, DASTableColumn column, {isLast = false}) {
Widget _dataCell(DASTableCell cell, DASTableColumn column, DASTableRow row, {isLast = false}) {
return Builder(builder: (context) {
final tableThemeData = DASTableTheme.of(context)?.data;
final effectiveAlignment = cell.alignment ?? column.alignment;
return _TableCellWrapper(
expanded: column.expanded,
width: column.width,
Expand All @@ -128,13 +136,13 @@ class DASTable extends StatelessWidget {
child: Container(
decoration: BoxDecoration(
border: cell.border ?? column.border ?? tableThemeData?.tableBorder?.toBoxBorder(isLastCell: isLast),
color: cell.color ?? column.color ?? tableThemeData?.dataRowColor,
color: cell.color ?? row.color ?? column.color ?? tableThemeData?.dataRowColor,
),
padding: cell.padding ?? column.padding ?? EdgeInsets.all(sbbDefaultSpacing * 0.5),
clipBehavior: cell.clipBehaviour,
child: DefaultTextStyle(
style: DefaultTextStyle.of(context).style.merge(tableThemeData?.dataTextStyle),
child: cell.child,
child: effectiveAlignment != null ? Align(alignment: effectiveAlignment, child: cell.child) : cell.child,
),
),
),
Expand Down
7 changes: 7 additions & 0 deletions das_client/lib/app/widgets/table/das_table_cell.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:das_client/app/widgets/table/das_table_column.dart';
import 'package:das_client/app/widgets/table/das_table_row.dart';
import 'package:das_client/app/widgets/table/das_table_theme.dart';
import 'package:flutter/material.dart';
Expand All @@ -13,13 +14,19 @@ class DASTableCell {
this.border,
this.color,
this.padding,
this.alignment,
this.clipBehaviour = Clip.hardEdge,
});

const DASTableCell.empty() : this(child: const SizedBox.shrink());

final BoxBorder? border;
final Widget child;
final VoidCallback? onTap;
final Color? color;
final EdgeInsetsGeometry? padding;
final Clip clipBehaviour;

/// If provided, wraps child in Align widget. Can also be defined in [DASTableColumn]
final Alignment? alignment;
}
9 changes: 7 additions & 2 deletions das_client/lib/app/widgets/table/das_table_column.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:das_client/app/widgets/table/das_table_cell.dart';
import 'package:design_system_flutter/design_system_flutter.dart';
import 'package:flutter/material.dart';

Expand All @@ -8,16 +9,17 @@ import 'package:flutter/material.dart';
@immutable
class DASTableColumn {
const DASTableColumn({
required this.child,
this.child,
this.border,
this.color,
this.padding = const EdgeInsets.all(sbbDefaultSpacing * 0.5),
this.expanded = false,
this.width,
this.alignment = Alignment.center,
}) : assert((width != null && width > 0) || expanded);

/// The content of the column header as a widget.
final Widget child;
final Widget? child;

/// Border style for the heading and data cells
final BoxBorder? border;
Expand All @@ -32,4 +34,7 @@ class DASTableColumn {

/// The fixed width for the column. Must be specified if not expanded.
final double? width;

/// If provided, wraps child in Align widget. Can be overridden in [DASTableCell]
final Alignment? alignment;
}
Loading

0 comments on commit ada2c39

Please sign in to comment.