Add Fluent UI for Win, Linux
Also add split screen train view for landscape
This commit is contained in:
parent
da983871e2
commit
0e484bdc16
30 changed files with 3062 additions and 612 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
v2.7.9
|
||||||
|
Add Fluent UI for Windows and Linux.
|
||||||
|
Add split view in landscape when viewing a train.
|
||||||
|
Add error handling and auto refresh when viewing a station's arrivals/departures.
|
||||||
|
General code fixes and migration (freezed, riverpod).
|
||||||
|
|
||||||
v2.7.8
|
v2.7.8
|
||||||
Added cancelled trains in departures/arrivals board.
|
Added cancelled trains in departures/arrivals board.
|
||||||
Selecting train in departures/arrivels board chooses appropriate departure date.
|
Selecting train in departures/arrivels board chooses appropriate departure date.
|
||||||
|
|
59
lib/components/badge/badge.dart
Normal file
59
lib/components/badge/badge.dart
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge_fluent.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge_material.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class Badge extends ConsumerWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const Badge({
|
||||||
|
super.key,
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return MaterialBadge(
|
||||||
|
text: text,
|
||||||
|
caption: caption,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return CupertinoBadge(
|
||||||
|
text: text,
|
||||||
|
caption: caption,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return FluentBadge(
|
||||||
|
text: text,
|
||||||
|
caption: caption,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,84 +1,5 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
|
||||||
|
|
||||||
class MaterialBadge extends StatelessWidget {
|
|
||||||
final String text;
|
|
||||||
final String caption;
|
|
||||||
final bool isNotScheduled;
|
|
||||||
final bool isOnTime;
|
|
||||||
final bool isDelayed;
|
|
||||||
|
|
||||||
const MaterialBadge({
|
|
||||||
required this.text,
|
|
||||||
required this.caption,
|
|
||||||
this.isNotScheduled = false,
|
|
||||||
this.isOnTime = false,
|
|
||||||
this.isDelayed = false,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Color foregroundColor = Colors.white70;
|
|
||||||
Color? backgroundColor;
|
|
||||||
|
|
||||||
if (isNotScheduled) {
|
|
||||||
foregroundColor = Colors.orange.shade300;
|
|
||||||
backgroundColor = Colors.orange.shade900.withOpacity(0.3);
|
|
||||||
}
|
|
||||||
else if (isOnTime) {
|
|
||||||
foregroundColor = Colors.green.shade300;
|
|
||||||
backgroundColor = Colors.green.shade900.withOpacity(0.3);
|
|
||||||
}
|
|
||||||
else if (isDelayed) {
|
|
||||||
foregroundColor = Colors.red.shade300;
|
|
||||||
backgroundColor = Colors.red.shade900.withOpacity(0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
border: Border.all(
|
|
||||||
width: 2,
|
|
||||||
color: foregroundColor,
|
|
||||||
),
|
|
||||||
color: backgroundColor,
|
|
||||||
),
|
|
||||||
width: isSmallScreen(context) ? 42 : 48,
|
|
||||||
height: isSmallScreen(context) ? 42 : 48,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
text,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 16 : 20,
|
|
||||||
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
|
||||||
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
caption,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
fontSize: 10,
|
|
||||||
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CupertinoBadge extends StatelessWidget {
|
class CupertinoBadge extends StatelessWidget {
|
||||||
final String text;
|
final String text;
|
80
lib/components/badge/badge_fluent.dart
Normal file
80
lib/components/badge/badge_fluent.dart
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class FluentBadge extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const FluentBadge({
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color foregroundColor = FluentTheme.of(context).activeColor;
|
||||||
|
Color? backgroundColor;
|
||||||
|
|
||||||
|
if (isNotScheduled) {
|
||||||
|
foregroundColor = const Color.fromRGBO(225, 175, 30, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(80, 40, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isOnTime) {
|
||||||
|
foregroundColor = const Color.fromRGBO(130, 175, 65, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(40, 80, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isDelayed) {
|
||||||
|
foregroundColor = const Color.fromRGBO(225, 75, 30, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(80, 20, 10, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
width: 2,
|
||||||
|
color: foregroundColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
// color: CupertinoColors.activeOrange,
|
||||||
|
),
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: FluentTheme.of(context).typography.bodyLarge?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white : foregroundColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
caption,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
79
lib/components/badge/badge_material.dart
Normal file
79
lib/components/badge/badge_material.dart
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
||||||
|
|
||||||
|
class MaterialBadge extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const MaterialBadge({
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color foregroundColor = Colors.white70;
|
||||||
|
Color? backgroundColor;
|
||||||
|
|
||||||
|
if (isNotScheduled) {
|
||||||
|
foregroundColor = Colors.orange.shade300;
|
||||||
|
backgroundColor = Colors.orange.shade900.withOpacity(0.3);
|
||||||
|
}
|
||||||
|
else if (isOnTime) {
|
||||||
|
foregroundColor = Colors.green.shade300;
|
||||||
|
backgroundColor = Colors.green.shade900.withOpacity(0.3);
|
||||||
|
}
|
||||||
|
else if (isDelayed) {
|
||||||
|
foregroundColor = Colors.red.shade300;
|
||||||
|
backgroundColor = Colors.red.shade900.withOpacity(0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
width: 2,
|
||||||
|
color: foregroundColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
),
|
||||||
|
width: isSmallScreen(context) ? 42 : 48,
|
||||||
|
height: isSmallScreen(context) ? 42 : 48,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 16 : 20,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
caption,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/loading/loading_cupertino.dart';
|
import 'package:info_tren/components/loading/loading_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading_fluent.dart';
|
||||||
import 'package:info_tren/components/loading/loading_material.dart';
|
import 'package:info_tren/components/loading/loading_material.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/providers.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
@ -19,6 +20,8 @@ class Loading extends ConsumerWidget {
|
||||||
return LoadingMaterial(text: text ?? defaultText,);
|
return LoadingMaterial(text: text ?? defaultText,);
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return LoadingCupertino(text: text ?? defaultText,);
|
return LoadingCupertino(text: text ?? defaultText,);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return LoadingFluent(text: text ?? defaultText,);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
|
26
lib/components/loading/loading_fluent.dart
Normal file
26
lib/components/loading/loading_fluent.dart
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
|
||||||
|
class LoadingFluent extends LoadingCommon {
|
||||||
|
const LoadingFluent({required super.text, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: ProgressRing(),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(text),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_cupertino.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_fluent.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_material.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_material.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/providers.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
@ -31,6 +32,12 @@ class SelectTrainSuggestions extends ConsumerWidget {
|
||||||
onTrainSelected: onTrainSelected,
|
onTrainSelected: onTrainSelected,
|
||||||
currentInput: currentInput,
|
currentInput: currentInput,
|
||||||
);
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return SelectTrainSuggestionsFluent(
|
||||||
|
choices: choices,
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
currentInput: currentInput,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
@ -102,6 +109,12 @@ class OperatorAutocompleteSliver extends ConsumerWidget {
|
||||||
operatorName: operatorName,
|
operatorName: operatorName,
|
||||||
train: train,
|
train: train,
|
||||||
);
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return OperatorAutocompleteTileFluent(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestionsFluent extends SelectTrainSuggestionsShared {
|
||||||
|
const SelectTrainSuggestionsFluent({
|
||||||
|
super.key,
|
||||||
|
required super.choices,
|
||||||
|
required super.onTrainSelected,
|
||||||
|
super.currentInput,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Button(
|
||||||
|
child: Text(getUseCurrentInputWidgetText(currentInput)),
|
||||||
|
onPressed: () => onTrainSelected(currentInput),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorAutocompleteTileFluent extends OperatorAutocompleteTile {
|
||||||
|
const OperatorAutocompleteTileFluent({
|
||||||
|
Key? key,
|
||||||
|
required String operatorName,
|
||||||
|
required void Function(String) onTrainSelected,
|
||||||
|
required TrainsResult train
|
||||||
|
}): super(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
onTrainSelected(train.number);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 4, 16, 4),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
operatorName,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(fontSize: 10, fontWeight: FontWeight.w200),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${train.rank} ${train.number}",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:fluent_ui/fluent_ui.dart' as f;
|
||||||
|
import 'package:flutter/cupertino.dart' as c;
|
||||||
|
import 'package:flutter/material.dart' as m;
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/about/about_page.dart';
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
import 'package:info_tren/pages/main/main_page.dart';
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
|
@ -54,48 +59,59 @@ Map<String, WidgetBuilder> get routes => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
class StartPoint extends StatelessWidget {
|
class StartPoint extends ConsumerWidget {
|
||||||
final String appTitle = 'Info Tren';
|
final String appTitle = 'Info Tren';
|
||||||
|
|
||||||
const StartPoint({super.key});
|
const StartPoint({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
// if (Platform.isIOS || Platform.isMacOS) {
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
// return AnnotatedRegion(
|
if (uiDesign == UiDesign.CUPERTINO) {
|
||||||
// value: const SystemUiOverlayStyle(
|
return AnnotatedRegion(
|
||||||
// statusBarBrightness: Brightness.dark,
|
value: const SystemUiOverlayStyle(
|
||||||
// ),
|
statusBarBrightness: c.Brightness.dark,
|
||||||
// child: CupertinoApp(
|
),
|
||||||
// title: appTitle,
|
child: c.CupertinoApp(
|
||||||
// theme: CupertinoThemeData(
|
title: appTitle,
|
||||||
// primaryColor: Colors.blue.shade600,
|
theme: c.CupertinoThemeData(
|
||||||
// brightness: Brightness.dark,
|
primaryColor: m.Colors.blue.shade600,
|
||||||
// // textTheme: CupertinoTextThemeData(
|
brightness: c.Brightness.dark,
|
||||||
// // textStyle: TextStyle(
|
// textTheme: CupertinoTextThemeData(
|
||||||
// // fontFamily: 'Atkinson Hyperlegible',
|
// textStyle: TextStyle(
|
||||||
// // ),
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
// // ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// routes: routesByUiDesign(UiDesign.CUPERTINO),
|
),
|
||||||
// ),
|
routes: routes,
|
||||||
// );
|
),
|
||||||
// }
|
);
|
||||||
// else {
|
}
|
||||||
return MaterialApp(
|
else if (uiDesign == UiDesign.FLUENT) {
|
||||||
|
return f.FluentApp(
|
||||||
title: appTitle,
|
title: appTitle,
|
||||||
theme: ThemeData(
|
theme: f.ThemeData(
|
||||||
primarySwatch: Colors.blue,
|
brightness: f.Brightness.dark,
|
||||||
colorScheme: ColorScheme.fromSwatch(
|
accentColor: f.Colors.blue,
|
||||||
brightness: Brightness.dark,
|
),
|
||||||
primarySwatch: Colors.blue,
|
routes: routes,
|
||||||
accentColor: Colors.blue.shade700,
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return m.MaterialApp(
|
||||||
|
title: appTitle,
|
||||||
|
theme: m.ThemeData(
|
||||||
|
primarySwatch: m.Colors.blue,
|
||||||
|
colorScheme: m.ColorScheme.fromSwatch(
|
||||||
|
brightness: m.Brightness.dark,
|
||||||
|
primarySwatch: m.Colors.blue,
|
||||||
|
accentColor: m.Colors.blue.shade700,
|
||||||
),
|
),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
// fontFamily: 'Atkinson Hyperlegible',
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
),
|
),
|
||||||
routes: routes,
|
routes: routes,
|
||||||
);
|
);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
enum UiDesign {
|
enum UiDesign {
|
||||||
MATERIAL,
|
MATERIAL,
|
||||||
CUPERTINO
|
CUPERTINO,
|
||||||
|
FLUENT,
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnmatchedUiDesignException implements Exception {
|
class UnmatchedUiDesignException implements Exception {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/about/about_page.dart';
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
import 'package:info_tren/pages/main/main_page_cupertino.dart';
|
import 'package:info_tren/pages/main/main_page_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page_fluent.dart';
|
||||||
import 'package:info_tren/pages/main/main_page_material.dart';
|
import 'package:info_tren/pages/main/main_page_material.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
@ -20,6 +21,8 @@ class MainPage extends ConsumerWidget {
|
||||||
return const MainPageMaterial();
|
return const MainPageMaterial();
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return const MainPageCupertino();
|
return const MainPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const MainPageFluent();
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
|
73
lib/pages/main/main_page_fluent.dart
Normal file
73
lib/pages/main/main_page_fluent.dart
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
|
||||||
|
class MainPageFluent extends MainPageShared {
|
||||||
|
const MainPageFluent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
title: Text(pageTitle),
|
||||||
|
// centerTitle: true,
|
||||||
|
// actions: [
|
||||||
|
// PopupMenuButton<int>(
|
||||||
|
// icon: const Icon(Icons.more_vert),
|
||||||
|
// tooltip: moreOptionsText,
|
||||||
|
// itemBuilder: (_) => popupMenu.asMap().entries.map((e) => PopupMenuItem(
|
||||||
|
// value: e.key,
|
||||||
|
// child: Text(e.value.name),
|
||||||
|
// )).toList(),
|
||||||
|
// onSelected: (index) {
|
||||||
|
// popupMenu[index].action?.call(context);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
),
|
||||||
|
content: SafeArea(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: options.map((option) => HoverButton(
|
||||||
|
onPressed: option.action != null ? () => option.action!(context) : null,
|
||||||
|
builder: (context, states) {
|
||||||
|
return Card(
|
||||||
|
backgroundColor: option.action != null ? (states.isHovering ? FluentTheme.of(context).accentColor.dark : FluentTheme.of(context).accentColor) : null,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
option.name,
|
||||||
|
style: FluentTheme.of(context)
|
||||||
|
.typography
|
||||||
|
.bodyLarge
|
||||||
|
?.copyWith(
|
||||||
|
color:
|
||||||
|
FluentTheme.of(context).activeColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(option.description!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)).map((w) => Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: w,
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import 'package:flutter/widgets.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_cupertino.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_fluent.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_material.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_material.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
import 'package:info_tren/providers.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
@ -20,6 +21,8 @@ class SelectStationPage extends ConsumerWidget {
|
||||||
return const SelectStationPageMaterial();
|
return const SelectStationPageMaterial();
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return const SelectStationPageCupertino();
|
return const SelectStationPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const SelectStationPageFluent();
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
|
|
||||||
|
class SelectStationPageFluent extends SelectStationPageShared {
|
||||||
|
const SelectStationPageFluent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => SelectStationPageStateFluent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectStationPageStateFluent extends SelectStationPageState {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: const NavigationAppBar(
|
||||||
|
title: Text(SelectStationPageState.pageTitle),
|
||||||
|
// centerTitle: true,
|
||||||
|
),
|
||||||
|
content: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: TextBox(
|
||||||
|
controller: textEditingController,
|
||||||
|
autofocus: true,
|
||||||
|
placeholder: SelectStationPageState.textFieldLabel,
|
||||||
|
textInputAction: TextInputAction.search,
|
||||||
|
onChanged: onTextChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
// dense: true,
|
||||||
|
title: Text(filteredStations[index]),
|
||||||
|
onPressed: () => onSuggestionSelected(filteredStations[index]),
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
size: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: filteredStations.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_cupertino.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_fluent.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_material.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_material.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/providers.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
@ -31,6 +32,11 @@ class ViewStationPage extends HookConsumerWidget {
|
||||||
tab: tab.value,
|
tab: tab.value,
|
||||||
setTab: (newTab) => tab.value = newTab,
|
setTab: (newTab) => tab.value = newTab,
|
||||||
);
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return ViewStationPageFluent(
|
||||||
|
tab: tab.value,
|
||||||
|
setTab: (newTab) => tab.value = newTab,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,267 @@
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class ViewStationPageFluent extends ViewStationPageShared {
|
||||||
|
const ViewStationPageFluent({super.key, required super.tab, required super.setTab});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function()) _, RefreshFutureBuilderSnapshot<StationData> snapshot) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final stationName = ref.watch(viewStationArgumentsProvider.select((value) => value.stationName));
|
||||||
|
return Text(snapshot.hasData ? snapshot.data!.stationName : stationName);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: snapshot.state == RefreshFutureBuilderState.waiting || snapshot.state == RefreshFutureBuilderState.refreshError
|
||||||
|
? const Loading(text: ViewStationPageShared.loadingText,)
|
||||||
|
: snapshot.state == RefreshFutureBuilderState.error
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
FluentIcons.error,
|
||||||
|
size: 32,
|
||||||
|
color: Colors.red.normal,
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
ViewStationPageShared.errorText,
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontSize: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
snapshot.error.toString(),
|
||||||
|
style: FluentTheme.of(context).typography.subtitle,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Button(
|
||||||
|
onPressed: () {
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
child: const Text(ViewStationPageShared.retryText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
pane: snapshot.hasData ? NavigationPane(
|
||||||
|
onChanged: onTabChange,
|
||||||
|
selected: tab.index,
|
||||||
|
items: [
|
||||||
|
PaneItem(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(child: SafeArea(left: false, bottom: false, right: false,child: Container(),),),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]);
|
||||||
|
},
|
||||||
|
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
title: const Text(ViewStationPageShared.arrivals),
|
||||||
|
icon: const Icon(FluentIcons.arrow_down_right8),
|
||||||
|
),
|
||||||
|
PaneItem(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(child: SafeArea(left: false, bottom: false, right: false,child: Container(),),),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]);
|
||||||
|
},
|
||||||
|
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
title: const Text(ViewStationPageShared.departures),
|
||||||
|
icon: const Icon(FluentIcons.arrow_up_right8),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
) : null,
|
||||||
|
// bottomNavigationBar: snapshot.hasData ? BottomNavigationBar(
|
||||||
|
// items: const [
|
||||||
|
// BottomNavigationBarItem(
|
||||||
|
// icon: Icon(Icons.arrow_downward),
|
||||||
|
// label: ViewStationPageShared.arrivals,
|
||||||
|
// ),
|
||||||
|
// BottomNavigationBarItem(
|
||||||
|
// icon: Icon(Icons.arrow_upward),
|
||||||
|
// label: ViewStationPageShared.departures,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// currentIndex: tab.index,
|
||||||
|
// onTap: onTabChange,
|
||||||
|
// ) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildStationItem(BuildContext context, StationArrDep item, {required bool arrival}) {
|
||||||
|
return HoverButton(
|
||||||
|
onPressed: () => onTrainTapped(context, item.train),
|
||||||
|
builder: (context, states) {
|
||||||
|
return Container(
|
||||||
|
color: item.status.cancelled
|
||||||
|
? Colors.red.withAlpha(100)
|
||||||
|
: states.isPressing
|
||||||
|
? FluentTheme.of(context).scaffoldBackgroundColor
|
||||||
|
: states.isHovering
|
||||||
|
? FluentTheme.of(context).inactiveBackgroundColor
|
||||||
|
: null,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: const [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
decoration: item.status.cancelled || item.status.delay != 0 ? TextDecoration.lineThrough : null,
|
||||||
|
fontSize: item.status.delay != 0 ? 12 : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.delay != 0) Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final newTime = item.time.add(Duration(minutes: item.status.delay));
|
||||||
|
final delay = item.status.delay > 0;
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
'${newTime.toLocal().hour.toString().padLeft(2, '0')}:${newTime.toLocal().minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: const [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
color: delay ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: ListTile(
|
||||||
|
// isThreeLine: item.status.delay != 0,
|
||||||
|
title: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: item.train.rank,
|
||||||
|
style: TextStyle(
|
||||||
|
color: item.train.rank.startsWith('IR') ? const Color.fromARGB(255, 255, 0, 0) : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(text: item.train.number,),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: item.status.cancelled
|
||||||
|
? (arrival ? ViewStationPageShared.cancelledArrival : ViewStationPageShared.cancelledDeparture)
|
||||||
|
: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0
|
||||||
|
? (arrival ? ViewStationPageShared.arrivedFrom : ViewStationPageShared.departedTo)
|
||||||
|
: (arrival ? ViewStationPageShared.arrivesFrom : ViewStationPageShared.departsTo)
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(text: item.train.terminus),
|
||||||
|
if (item.status.delay != 0) ...[
|
||||||
|
const TextSpan(text: '\n'),
|
||||||
|
if (item.status.delay.abs() >= 60) ...[
|
||||||
|
TextSpan(text: (item.status.delay.abs() ~/ 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() >= 120 ? ' ore' : ' oră'),
|
||||||
|
if (item.status.delay.abs() % 60 != 0)
|
||||||
|
const TextSpan(text: ' și '),
|
||||||
|
],
|
||||||
|
TextSpan(text: (item.status.delay.abs() % 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() > 1 ? ' minute' : ' minut'),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
if (item.status.delay > 0)
|
||||||
|
TextSpan(
|
||||||
|
text: 'întârziere',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
TextSpan(
|
||||||
|
text: 'mai devreme',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.platform != null)
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: Badge(
|
||||||
|
text: item.status.platform!,
|
||||||
|
caption: 'Linia',
|
||||||
|
isOnTime: item.status.real && item.status.delay <= 0,
|
||||||
|
isDelayed: item.status.real && item.status.delay > 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||||
|
return buildStationItem(context, item, arrival: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||||
|
return buildStationItem(context, item, arrival: false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import 'dart:math';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/badge.dart';
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
|
@ -205,7 +205,7 @@ class ViewStationPageMaterial extends ViewStationPageShared {
|
||||||
IntrinsicHeight(
|
IntrinsicHeight(
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
child: MaterialBadge(
|
child: Badge(
|
||||||
text: item.status.platform!,
|
text: item.status.platform!,
|
||||||
caption: 'Linia',
|
caption: 'Linia',
|
||||||
isOnTime: item.status.real && item.status.delay <= 0,
|
isOnTime: item.status.real && item.status.delay <= 0,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train_cupertino.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/select_train/select_train_fluent.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train_material.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train_material.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/providers.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
@ -26,6 +27,8 @@ class SelectTrainPage extends ConsumerWidget {
|
||||||
return const SelectTrainPageMaterial();
|
return const SelectTrainPageMaterial();
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return const SelectTrainPageCupertino();
|
return const SelectTrainPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const SelectTrainPageFluent();
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +73,11 @@ abstract class SelectTrainPageState extends State<SelectTrainPageShared> {
|
||||||
return posInNum1.compareTo(posInNum2);
|
return posInNum1.compareTo(posInNum2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return t1.number.length.compareTo(t2.number.length);
|
if (t1.number.length != t2.number.length) {
|
||||||
|
return t1.number.length.compareTo(t2.number.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return t1.number.compareTo(t2.number);
|
||||||
});
|
});
|
||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
|
||||||
|
class SelectTrainPageFluent extends SelectTrainPageShared {
|
||||||
|
const SelectTrainPageFluent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SelectTrainPageShared> createState() => SelectTrainPageStateFluent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectTrainPageStateFluent extends SelectTrainPageState {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
),
|
||||||
|
content: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: TextBox(
|
||||||
|
controller: trainNoController,
|
||||||
|
autofocus: true,
|
||||||
|
placeholder: textFieldLabel,
|
||||||
|
textInputAction: TextInputAction.search,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: (_) => onTextChanged(),
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: suggestionsList,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/api/train_data.dart';
|
import 'package:info_tren/api/train_data.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info_cupertino.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_fluent.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
||||||
import 'package:info_tren/providers.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
@ -30,34 +29,35 @@ class TrainInfo extends ConsumerWidget {
|
||||||
replaceFutureBuilder(() => getTrain(trainNumber, date: DateTime.now().subtract(const Duration(days: 1))));
|
replaceFutureBuilder(() => getTrain(trainNumber, date: DateTime.now().subtract(const Duration(days: 1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([RefreshFutureBuilderState.none, RefreshFutureBuilderState.waiting].contains(snapshot.state)) {
|
||||||
|
return TrainInfoLoading(title: trainNumber.toString(), loadingText: "Se încarcă...",);
|
||||||
|
}
|
||||||
|
else if (snapshot.state == RefreshFutureBuilderState.error) {
|
||||||
|
return TrainInfoError(title: '$trainNumber - Error', error: snapshot.error!, refresh: refresh,);
|
||||||
|
}
|
||||||
|
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
if ([RefreshFutureBuilderState.none, RefreshFutureBuilderState.waiting].contains(snapshot.state)) {
|
|
||||||
return TrainInfoLoadingMaterial(title: trainNumber.toString(), loadingText: "Se încarcă...",);
|
|
||||||
}
|
|
||||||
else if (snapshot.state == RefreshFutureBuilderState.error) {
|
|
||||||
return TrainInfoErrorMaterial(title: '$trainNumber - Error', error: snapshot.error!, refresh: refresh,);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TrainInfoMaterial(
|
return TrainInfoMaterial(
|
||||||
trainData: snapshot.data!,
|
trainData: snapshot.data!,
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
|
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
|
||||||
onViewYesterdayTrain: onViewYesterdayTrain,
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
);
|
);
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
if ([RefreshFutureBuilderState.none, RefreshFutureBuilderState.waiting].contains(snapshot.state)) {
|
|
||||||
return TrainInfoLoadingCupertino(title: trainNumber.toString(), loadingText: "Se încarcă...",);
|
|
||||||
}
|
|
||||||
else if (snapshot.state == RefreshFutureBuilderState.error) {
|
|
||||||
return TrainInfoErrorCupertino(title: '$trainNumber - Error', error: snapshot.error!, refresh: refresh,);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TrainInfoCupertino(
|
return TrainInfoCupertino(
|
||||||
trainData: snapshot.data!,
|
trainData: snapshot.data!,
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
|
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
|
||||||
onViewYesterdayTrain: onViewYesterdayTrain,
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
);
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return TrainInfoFluent(
|
||||||
|
trainData: snapshot.data!,
|
||||||
|
refresh: refresh,
|
||||||
|
isRefreshing: snapshot.state == RefreshFutureBuilderState.refreshing,
|
||||||
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
@ -73,23 +73,176 @@ class TrainInfoArguments {
|
||||||
TrainInfoArguments({required this.trainNumber, this.date});
|
TrainInfoArguments({required this.trainNumber, this.date});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TrainInfoLoading extends StatelessWidget {
|
abstract class TrainInfoShared extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
final Future Function()? refresh;
|
||||||
|
final void Function()? onViewYesterdayTrain;
|
||||||
|
final bool? isRefreshing;
|
||||||
|
|
||||||
|
const TrainInfoShared({
|
||||||
|
super.key,
|
||||||
|
required this.trainData,
|
||||||
|
this.refresh,
|
||||||
|
this.onViewYesterdayTrain,
|
||||||
|
this.isRefreshing,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoLoading extends ConsumerWidget {
|
||||||
|
final String title;
|
||||||
|
final String? loadingText;
|
||||||
|
|
||||||
|
const TrainInfoLoading({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
this.loadingText,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return TrainInfoLoadingMaterial(
|
||||||
|
title: title,
|
||||||
|
loadingText: loadingText,
|
||||||
|
);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return TrainInfoLoadingCupertino(
|
||||||
|
title: title,
|
||||||
|
loadingText: loadingText,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return TrainInfoLoadingFluent(
|
||||||
|
title: title,
|
||||||
|
loadingText: loadingText,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TrainInfoLoadingShared extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final Widget loadingWidget;
|
final Widget loadingWidget;
|
||||||
|
|
||||||
TrainInfoLoading({
|
TrainInfoLoadingShared({
|
||||||
required this.title,
|
required this.title,
|
||||||
String? loadingText,
|
String? loadingText,
|
||||||
super.key,
|
super.key,
|
||||||
}) : loadingWidget = Loading(text: loadingText,);
|
}) : loadingWidget = Loading(text: loadingText,);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TrainInfoError extends StatelessWidget {
|
class TrainInfoError extends ConsumerWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final Object error;
|
final Object error;
|
||||||
final Future Function()? refresh;
|
final Future Function()? refresh;
|
||||||
|
|
||||||
const TrainInfoError({required this.title, required this.error, this.refresh, super.key,});
|
const TrainInfoError({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.error,
|
||||||
|
this.refresh,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return TrainInfoErrorMaterial(
|
||||||
|
title: title,
|
||||||
|
error: error,
|
||||||
|
refresh: refresh,
|
||||||
|
);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return TrainInfoErrorCupertino(
|
||||||
|
title: title,
|
||||||
|
error: error,
|
||||||
|
refresh: refresh,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return TrainInfoErrorFluent(
|
||||||
|
title: title,
|
||||||
|
error: error,
|
||||||
|
refresh: refresh,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TrainInfoErrorShared extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final Object error;
|
||||||
|
final Future Function()? refresh;
|
||||||
|
|
||||||
|
const TrainInfoErrorShared({required this.title, required this.error, this.refresh, super.key,});
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoBody extends ConsumerWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
final void Function()? onViewYesterdayTrain;
|
||||||
|
final Future Function()? refresh;
|
||||||
|
final bool? isRefreshing;
|
||||||
|
|
||||||
|
const TrainInfoBody({
|
||||||
|
required this.trainData,
|
||||||
|
this.onViewYesterdayTrain,
|
||||||
|
this.refresh,
|
||||||
|
this.isRefreshing,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return TrainInfoBodyMaterial(
|
||||||
|
trainData: trainData,
|
||||||
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
|
refresh: refresh,
|
||||||
|
isRefreshing: isRefreshing,
|
||||||
|
);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return TrainInfoBodyCupertino(
|
||||||
|
trainData: trainData,
|
||||||
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
|
refresh: refresh,
|
||||||
|
isRefreshing: isRefreshing,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return TrainInfoBodyFluent(
|
||||||
|
trainData: trainData,
|
||||||
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
|
refresh: refresh,
|
||||||
|
isRefreshing: isRefreshing,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TrainInfoBodyShared extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
final void Function()? onViewYesterdayTrain;
|
||||||
|
final Future Function()? refresh;
|
||||||
|
final bool? isRefreshing;
|
||||||
|
|
||||||
|
const TrainInfoBodyShared({
|
||||||
|
required this.trainData,
|
||||||
|
this.onViewYesterdayTrain,
|
||||||
|
this.refresh,
|
||||||
|
this.isRefreshing,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DisplayTrainYesterdayWarningCommon extends StatelessWidget {
|
abstract class DisplayTrainYesterdayWarningCommon extends StatelessWidget {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info_cupertino_DisplayTrainStation.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_cupertino_DisplayTrainStation.dart';
|
||||||
import 'package:info_tren/utils/state_to_string.dart';
|
import 'package:info_tren/utils/state_to_string.dart';
|
||||||
|
|
||||||
class TrainInfoLoadingCupertino extends TrainInfoLoading {
|
class TrainInfoLoadingCupertino extends TrainInfoLoadingShared {
|
||||||
TrainInfoLoadingCupertino({required super.title, super.loadingText, super.key,});
|
TrainInfoLoadingCupertino({required super.title, super.loadingText, super.key,});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -26,17 +26,13 @@ class TrainInfoLoadingCupertino extends TrainInfoLoading {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrainInfoErrorCupertino extends TrainInfoError {
|
class TrainInfoErrorCupertino extends TrainInfoErrorShared {
|
||||||
const TrainInfoErrorCupertino({
|
const TrainInfoErrorCupertino({
|
||||||
required Object error,
|
required super.error,
|
||||||
required String title,
|
required super.title,
|
||||||
Future Function()? refresh,
|
super.refresh,
|
||||||
super.key,
|
super.key,
|
||||||
}) : super(
|
});
|
||||||
error: error,
|
|
||||||
title: title,
|
|
||||||
refresh: refresh,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -64,17 +60,12 @@ class TrainInfoErrorCupertino extends TrainInfoError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrainInfoCupertino extends StatelessWidget {
|
class TrainInfoCupertino extends TrainInfoShared {
|
||||||
final TrainData trainData;
|
|
||||||
final Future Function()? refresh;
|
|
||||||
final bool? isRefreshing;
|
|
||||||
final void Function()? onViewYesterdayTrain;
|
|
||||||
|
|
||||||
const TrainInfoCupertino({
|
const TrainInfoCupertino({
|
||||||
required this.trainData,
|
required super.trainData,
|
||||||
this.refresh,
|
super.refresh,
|
||||||
this.isRefreshing,
|
super.isRefreshing,
|
||||||
this.onViewYesterdayTrain,
|
super.onViewYesterdayTrain,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,195 +84,10 @@ class TrainInfoCupertino extends StatelessWidget {
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
top: false,
|
top: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Builder(builder: (context) {
|
child: TrainInfoBody(
|
||||||
final topPadding = MediaQuery.of(context).padding.top;
|
trainData: trainData,
|
||||||
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
return NestedScrollView(
|
),
|
||||||
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
|
||||||
return [
|
|
||||||
// SliverPadding(
|
|
||||||
// padding: EdgeInsets.only(
|
|
||||||
// top: topPadding,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
SliverPersistentHeaderPadding(
|
|
||||||
maxHeight: topPadding,
|
|
||||||
)
|
|
||||||
];
|
|
||||||
},
|
|
||||||
body: Builder(builder: (context) {
|
|
||||||
return CustomScrollView(
|
|
||||||
slivers: <Widget>[
|
|
||||||
if (refresh != null)
|
|
||||||
CupertinoSliverRefreshControl(
|
|
||||||
builder: (context, mode, pulledExtent,
|
|
||||||
refreshTriggerPullDistance, refreshIndicatorExtent) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: pulledExtent,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: min(
|
|
||||||
refreshIndicatorExtent, pulledExtent),
|
|
||||||
child: Center(
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
if (mode ==
|
|
||||||
RefreshIndicatorMode.inactive) {
|
|
||||||
return Container();
|
|
||||||
} else if (mode ==
|
|
||||||
RefreshIndicatorMode.done) {
|
|
||||||
return const Text('Refreshed!');
|
|
||||||
} else if (mode ==
|
|
||||||
RefreshIndicatorMode.drag) {
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: const [
|
|
||||||
CupertinoActivityIndicator(
|
|
||||||
animating: false,
|
|
||||||
),
|
|
||||||
Text('Pull to refresh...'),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else if (mode ==
|
|
||||||
RefreshIndicatorMode.armed) {
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: const [
|
|
||||||
CupertinoActivityIndicator(
|
|
||||||
animating: false,
|
|
||||||
),
|
|
||||||
Text('Release to refresh...'),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: const [
|
|
||||||
CupertinoActivityIndicator(),
|
|
||||||
Text('Refreshing'),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onRefresh: refresh,
|
|
||||||
),
|
|
||||||
DisplayTrainID(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
DisplayTrainOperator(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
DisplayTrainRoute(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
DisplayTrainDeparture(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
const SliverToBoxAdapter(
|
|
||||||
child: CupertinoDivider(
|
|
||||||
color: foregroundWhite,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DisplayTrainLastInfo(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
const SliverToBoxAdapter(
|
|
||||||
child: CupertinoDivider(),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
// Expanded(
|
|
||||||
// child: DisplayTrainNextStop(trainData: trainData,),
|
|
||||||
// ),
|
|
||||||
Expanded(
|
|
||||||
child: DisplayTrainRouteDuration(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Expanded(
|
|
||||||
// child: DisplayTrainDestination(trainData: trainData,),
|
|
||||||
// ),
|
|
||||||
const SizedBox(
|
|
||||||
height: double.infinity,
|
|
||||||
child: CupertinoVerticalDivider(),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: DisplayTrainRouteDistance(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// SliverToBoxAdapter(
|
|
||||||
// child: CupertinoDivider(),
|
|
||||||
// ),
|
|
||||||
// SliverToBoxAdapter(
|
|
||||||
// child: IntrinsicHeight(
|
|
||||||
// child: Row(
|
|
||||||
// children: <Widget>[
|
|
||||||
// // Expanded(
|
|
||||||
// // child: DisplayTrainRouteDuration(trainData: trainData,),
|
|
||||||
// // ),
|
|
||||||
// Expanded(child: Container(),),
|
|
||||||
// SizedBox(
|
|
||||||
// height: double.infinity,
|
|
||||||
// child: CupertinoVerticalDivider(),
|
|
||||||
// ),
|
|
||||||
// Expanded(
|
|
||||||
// child: DisplayTrainRouteDistance(trainData: trainData,),
|
|
||||||
// )
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
const SliverToBoxAdapter(
|
|
||||||
child: CupertinoDivider(
|
|
||||||
color: foregroundWhite,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (onViewYesterdayTrain != null && trainData.stations.first.departure!.scheduleTime.compareTo(DateTime.now()) > 0) ...[
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainYesterdayWarningCupertino(onViewYesterdayTrain!),
|
|
||||||
),
|
|
||||||
const SliverToBoxAdapter(
|
|
||||||
child: CupertinoDivider(
|
|
||||||
color: foregroundWhite,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
DisplayTrainStations(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
height: MediaQuery.of(context).viewPadding.bottom,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -390,31 +196,382 @@ class TrainInfoCupertino extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TrainInfoBodyCupertino extends TrainInfoBodyShared {
|
||||||
|
const TrainInfoBodyCupertino({
|
||||||
|
super.key,
|
||||||
|
required super.trainData,
|
||||||
|
super.onViewYesterdayTrain,
|
||||||
|
super.isRefreshing,
|
||||||
|
super.refresh,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mq = MediaQuery.of(context);
|
||||||
|
final topPadding = mq.padding.top;
|
||||||
|
|
||||||
|
if (mq.orientation == Orientation.landscape && mq.size.width >= 1000) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 400,
|
||||||
|
maxWidth: 400,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
DisplayTrainID(trainData: trainData),
|
||||||
|
DisplayTrainOperator(trainData: trainData),
|
||||||
|
DisplayTrainRoute(trainData: trainData),
|
||||||
|
DisplayTrainDeparture(trainData: trainData),
|
||||||
|
const CupertinoDivider(
|
||||||
|
color: foregroundWhite,
|
||||||
|
),
|
||||||
|
DisplayTrainLastInfo(trainData: trainData),
|
||||||
|
const CupertinoDivider(),
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainNextStop(trainData: trainData,),
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDuration(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainDestination(trainData: trainData,),
|
||||||
|
// ),
|
||||||
|
const SizedBox(
|
||||||
|
height: double.infinity,
|
||||||
|
child: CupertinoVerticalDivider(),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDistance(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const CupertinoDivider(
|
||||||
|
color: foregroundWhite,
|
||||||
|
),
|
||||||
|
if (onViewYesterdayTrain != null && trainData.stations.first.departure!.scheduleTime.compareTo(DateTime.now()) > 0) ...[
|
||||||
|
DisplayTrainYesterdayWarningCupertino(onViewYesterdayTrain!),
|
||||||
|
const CupertinoDivider(
|
||||||
|
color: foregroundWhite,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: NestedScrollView(
|
||||||
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||||
|
return [
|
||||||
|
// SliverPadding(
|
||||||
|
// padding: EdgeInsets.only(
|
||||||
|
// top: topPadding,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverPersistentHeaderPadding(
|
||||||
|
maxHeight: topPadding,
|
||||||
|
)
|
||||||
|
];
|
||||||
|
},
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
if (refresh != null)
|
||||||
|
CupertinoSliverRefreshControl(
|
||||||
|
builder: (context, mode, pulledExtent,
|
||||||
|
refreshTriggerPullDistance, refreshIndicatorExtent) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: pulledExtent,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: min(
|
||||||
|
refreshIndicatorExtent, pulledExtent),
|
||||||
|
child: Center(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
if (mode ==
|
||||||
|
RefreshIndicatorMode.inactive) {
|
||||||
|
return Container();
|
||||||
|
} else if (mode ==
|
||||||
|
RefreshIndicatorMode.done) {
|
||||||
|
return const Text('Refreshed!');
|
||||||
|
} else if (mode ==
|
||||||
|
RefreshIndicatorMode.drag) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: const [
|
||||||
|
CupertinoActivityIndicator(
|
||||||
|
animating: false,
|
||||||
|
),
|
||||||
|
Text('Pull to refresh...'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else if (mode ==
|
||||||
|
RefreshIndicatorMode.armed) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: const [
|
||||||
|
CupertinoActivityIndicator(
|
||||||
|
animating: false,
|
||||||
|
),
|
||||||
|
Text('Release to refresh...'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: const [
|
||||||
|
CupertinoActivityIndicator(),
|
||||||
|
Text('Refreshing'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onRefresh: refresh,
|
||||||
|
),
|
||||||
|
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery.of(context).viewPadding.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NestedScrollView(
|
||||||
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||||
|
return [
|
||||||
|
// SliverPadding(
|
||||||
|
// padding: EdgeInsets.only(
|
||||||
|
// top: topPadding,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverPersistentHeaderPadding(
|
||||||
|
maxHeight: topPadding,
|
||||||
|
)
|
||||||
|
];
|
||||||
|
},
|
||||||
|
body: Builder(builder: (context) {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
if (refresh != null)
|
||||||
|
CupertinoSliverRefreshControl(
|
||||||
|
builder: (context, mode, pulledExtent,
|
||||||
|
refreshTriggerPullDistance, refreshIndicatorExtent) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: pulledExtent,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: min(
|
||||||
|
refreshIndicatorExtent, pulledExtent),
|
||||||
|
child: Center(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
if (mode ==
|
||||||
|
RefreshIndicatorMode.inactive) {
|
||||||
|
return Container();
|
||||||
|
} else if (mode ==
|
||||||
|
RefreshIndicatorMode.done) {
|
||||||
|
return const Text('Refreshed!');
|
||||||
|
} else if (mode ==
|
||||||
|
RefreshIndicatorMode.drag) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: const [
|
||||||
|
CupertinoActivityIndicator(
|
||||||
|
animating: false,
|
||||||
|
),
|
||||||
|
Text('Pull to refresh...'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else if (mode ==
|
||||||
|
RefreshIndicatorMode.armed) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: const [
|
||||||
|
CupertinoActivityIndicator(
|
||||||
|
animating: false,
|
||||||
|
),
|
||||||
|
Text('Release to refresh...'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: const [
|
||||||
|
CupertinoActivityIndicator(),
|
||||||
|
Text('Refreshing'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onRefresh: refresh,
|
||||||
|
),
|
||||||
|
...[
|
||||||
|
DisplayTrainID(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
DisplayTrainOperator(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
DisplayTrainRoute(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
DisplayTrainDeparture(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
const CupertinoDivider(
|
||||||
|
color: foregroundWhite,
|
||||||
|
),
|
||||||
|
DisplayTrainLastInfo(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
const CupertinoDivider(),
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainNextStop(trainData: trainData,),
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDuration(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainDestination(trainData: trainData,),
|
||||||
|
// ),
|
||||||
|
const SizedBox(
|
||||||
|
height: double.infinity,
|
||||||
|
child: CupertinoVerticalDivider(),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDistance(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const CupertinoDivider(
|
||||||
|
color: foregroundWhite,
|
||||||
|
),
|
||||||
|
if (onViewYesterdayTrain != null && trainData.stations.first.departure!.scheduleTime.compareTo(DateTime.now()) > 0) ...[
|
||||||
|
DisplayTrainYesterdayWarningCupertino(onViewYesterdayTrain!),
|
||||||
|
const CupertinoDivider(
|
||||||
|
color: foregroundWhite,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
].map((e) => SliverToBoxAdapter(child: e)),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: CupertinoDivider(),
|
||||||
|
// ),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: IntrinsicHeight(
|
||||||
|
// child: Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// // Expanded(
|
||||||
|
// // child: DisplayTrainRouteDuration(trainData: trainData,),
|
||||||
|
// // ),
|
||||||
|
// Expanded(child: Container(),),
|
||||||
|
// SizedBox(
|
||||||
|
// height: double.infinity,
|
||||||
|
// child: CupertinoVerticalDivider(),
|
||||||
|
// ),
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainRouteDistance(trainData: trainData,),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery.of(context).viewPadding.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DisplayTrainID extends StatelessWidget {
|
class DisplayTrainID extends StatelessWidget {
|
||||||
final TrainData trainData;
|
final TrainData trainData;
|
||||||
const DisplayTrainID({required this.trainData, super.key,});
|
const DisplayTrainID({required this.trainData, super.key,});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverToBoxAdapter(
|
return Center(
|
||||||
child: Center(
|
child: Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.all(8.0),
|
||||||
padding: const EdgeInsets.all(8.0),
|
child: Text.rich(
|
||||||
child: Text.rich(
|
TextSpan(
|
||||||
TextSpan(
|
children: [
|
||||||
children: [
|
TextSpan(
|
||||||
TextSpan(
|
text: trainData.rank,
|
||||||
text: trainData.rank,
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: trainData.rank.startsWith('IR') ? const Color.fromARGB(255, 255, 0, 0) : null,
|
||||||
color: trainData.rank.startsWith('IR') ? const Color.fromARGB(255, 255, 0, 0) : null,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const TextSpan(text: ' '),
|
),
|
||||||
TextSpan(text: trainData.number,),
|
const TextSpan(text: ' '),
|
||||||
],
|
TextSpan(text: trainData.number,),
|
||||||
),
|
],
|
||||||
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
|
),
|
||||||
),
|
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -428,41 +585,39 @@ class DisplayTrainRoute extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverToBoxAdapter(
|
return Row(
|
||||||
child: Row(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
Expanded(
|
||||||
Expanded(
|
child: Center(
|
||||||
child: Center(
|
child: Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.all(4),
|
||||||
padding: const EdgeInsets.all(4),
|
child: Text(
|
||||||
child: Text(
|
trainData.route.from,
|
||||||
trainData.route.from,
|
style:
|
||||||
style:
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
fontSize: 16,
|
||||||
fontSize: 16,
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Center(child: Text("-")),
|
),
|
||||||
Expanded(
|
const Center(child: Text("-")),
|
||||||
child: Center(
|
Expanded(
|
||||||
child: Padding(
|
child: Center(
|
||||||
padding: const EdgeInsets.all(4),
|
child: Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.all(4),
|
||||||
trainData.route.to,
|
child: Text(
|
||||||
style:
|
trainData.route.to,
|
||||||
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
style:
|
||||||
fontSize: 16,
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
),
|
fontSize: 16,
|
||||||
textAlign: TextAlign.right,
|
),
|
||||||
),
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,15 +629,13 @@ class DisplayTrainOperator extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverToBoxAdapter(
|
return Center(
|
||||||
child: Center(
|
child: Text(
|
||||||
child: Text(
|
trainData.operator,
|
||||||
trainData.operator,
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
fontSize: 14,
|
||||||
fontSize: 14,
|
fontStyle: FontStyle.italic,
|
||||||
fontStyle: FontStyle.italic,
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -495,18 +648,16 @@ class DisplayTrainDeparture extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverToBoxAdapter(
|
return Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.all(2),
|
||||||
padding: const EdgeInsets.all(2),
|
child: Text(
|
||||||
child: Text(
|
// "Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}",
|
||||||
// "Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}",
|
"Plecare în ${trainData.date}",
|
||||||
"Plecare în ${trainData.date}",
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
fontStyle: FontStyle.italic,
|
||||||
fontStyle: FontStyle.italic,
|
fontWeight: FontWeight.w200,
|
||||||
fontWeight: FontWeight.w200,
|
),
|
||||||
),
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -520,90 +671,86 @@ class DisplayTrainLastInfo extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (trainData.status == null) {
|
if (trainData.status == null) {
|
||||||
return SliverToBoxAdapter(
|
return Container();
|
||||||
child: Container(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SliverToBoxAdapter(
|
return Column(
|
||||||
child: Column(
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisSize: MainAxisSize.min,
|
children: <Widget>[
|
||||||
children: <Widget>[
|
Center(
|
||||||
Center(
|
child: Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.all(2),
|
||||||
padding: const EdgeInsets.all(2),
|
child: Text(
|
||||||
child: Text(
|
"Ultima informație",
|
||||||
"Ultima informație",
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
fontSize: 20,
|
||||||
fontSize: 20,
|
fontWeight: FontWeight.bold,
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Row(
|
),
|
||||||
children: <Widget>[
|
Row(
|
||||||
Padding(
|
children: <Widget>[
|
||||||
padding: const EdgeInsets.all(4),
|
Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.all(4),
|
||||||
trainData.status!.station,
|
child: Text(
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
trainData.status!.station,
|
||||||
textAlign: TextAlign.left,
|
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||||
),
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
child: Container(),
|
Expanded(
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
stateToString(trainData.status!.state),
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||||
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.all(4),
|
],
|
||||||
child: Text(
|
),
|
||||||
stateToString(trainData.status!.state),
|
// FutureDisplay<DateTime>(
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
// future: trainData.lastInfo.dateAndTime,
|
||||||
textAlign: TextAlign.right,
|
// builder: (context, dt) {
|
||||||
),
|
// return Text(
|
||||||
),
|
// "Raportat în ${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year.toString().padLeft(4, '0')}, la ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}",
|
||||||
],
|
// textAlign: TextAlign.center,
|
||||||
),
|
// );
|
||||||
// FutureDisplay<DateTime>(
|
// },
|
||||||
// future: trainData.lastInfo.dateAndTime,
|
// ),
|
||||||
// builder: (context, dt) {
|
Builder(
|
||||||
// return Text(
|
builder: (context) {
|
||||||
// "Raportat în ${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year.toString().padLeft(4, '0')}, la ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}",
|
final data = trainData.status!.delay;
|
||||||
// textAlign: TextAlign.center,
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final data = trainData.status!.delay;
|
|
||||||
|
|
||||||
if (data == 0) {
|
if (data == 0) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data > 0) {
|
if (data > 0) {
|
||||||
return Text(
|
return Text(
|
||||||
"$data ${data == 1 ? 'minut' : 'minute'} întârziere",
|
"$data ${data == 1 ? 'minut' : 'minute'} întârziere",
|
||||||
style:
|
style:
|
||||||
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: CupertinoColors.destructiveRed,
|
color: CupertinoColors.destructiveRed,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Text(
|
return Text(
|
||||||
"${-data} ${data == -1 ? 'minut' : 'minute'} mai devreme",
|
"${-data} ${data == -1 ? 'minut' : 'minute'} mai devreme",
|
||||||
style:
|
style:
|
||||||
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: CupertinoColors.systemGreen,
|
color: CupertinoColors.systemGreen,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:info_tren/components/badge.dart';
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
class DisplayTrainStation extends StatelessWidget {
|
class DisplayTrainStation extends StatelessWidget {
|
||||||
|
@ -47,7 +47,7 @@ class DisplayTrainStation extends StatelessWidget {
|
||||||
final isOnTime = delay <= 0 && real == true;
|
final isOnTime = delay <= 0 && real == true;
|
||||||
const isNotScheduled = false;
|
const isNotScheduled = false;
|
||||||
|
|
||||||
return CupertinoBadge(
|
return Badge(
|
||||||
text: station.km.toString(),
|
text: station.km.toString(),
|
||||||
caption: 'km',
|
caption: 'km',
|
||||||
isNotScheduled: isNotScheduled,
|
isNotScheduled: isNotScheduled,
|
||||||
|
@ -65,7 +65,7 @@ class DisplayTrainStation extends StatelessWidget {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: station.platform == null ? Container() : CupertinoBadge(text: station.platform!, caption: 'linia'),
|
child: station.platform == null ? Container() : Badge(text: station.platform!, caption: 'linia'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
807
lib/pages/train_info_page/view_train/train_info_fluent.dart
Normal file
807
lib/pages/train_info_page/view_train/train_info_fluent.dart
Normal file
|
@ -0,0 +1,807 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_fluent_DisplayTrainStation.dart';
|
||||||
|
import 'package:info_tren/utils/state_to_string.dart';
|
||||||
|
|
||||||
|
class TrainInfoLoadingFluent extends TrainInfoLoadingShared {
|
||||||
|
TrainInfoLoadingFluent({required super.title, super.loadingText, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Text(title),
|
||||||
|
),
|
||||||
|
content: Center(
|
||||||
|
child: loadingWidget,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoErrorFluent extends TrainInfoErrorShared {
|
||||||
|
const TrainInfoErrorFluent({
|
||||||
|
required super.error,
|
||||||
|
required super.title,
|
||||||
|
super.refresh,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Text(title),
|
||||||
|
),
|
||||||
|
content: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(error.toString()),
|
||||||
|
if (refresh != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Button(
|
||||||
|
child: const Text('Retry'),
|
||||||
|
onPressed: () => refresh!(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoFluent extends TrainInfoShared {
|
||||||
|
const TrainInfoFluent({
|
||||||
|
super.key,
|
||||||
|
required super.trainData,
|
||||||
|
super.isRefreshing,
|
||||||
|
super.refresh,
|
||||||
|
super.onViewYesterdayTrain,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Text(
|
||||||
|
"Informații despre ${trainData.rank} ${trainData.number}",
|
||||||
|
),
|
||||||
|
actions: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (refresh != null) ...[
|
||||||
|
Center(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
child: IconButton(
|
||||||
|
icon: isRefreshing == true ? const ProgressRing() : const Icon(
|
||||||
|
FluentIcons.refresh,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
onPressed: isRefreshing == true ? null : () {
|
||||||
|
refresh!();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: TrainInfoBody(
|
||||||
|
trainData: trainData,
|
||||||
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoBodyFluent extends TrainInfoBodyShared {
|
||||||
|
const TrainInfoBodyFluent({
|
||||||
|
super.key,
|
||||||
|
required super.trainData,
|
||||||
|
super.onViewYesterdayTrain,
|
||||||
|
super.refresh,
|
||||||
|
super.isRefreshing,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mq = MediaQuery.of(context);
|
||||||
|
|
||||||
|
if (mq.orientation == Orientation.landscape && mq.size.width >= 1000) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 400,
|
||||||
|
maxWidth: 400,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
DisplayTrainID(trainData: trainData),
|
||||||
|
DisplayTrainOperator(trainData: trainData),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 2.0),
|
||||||
|
child: DisplayTrainRoute(trainData: trainData),
|
||||||
|
),
|
||||||
|
DisplayTrainDeparture(trainData: trainData),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: DisplayTrainLastInfo(trainData: trainData),
|
||||||
|
),
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: DisplayTrainRouteDuration(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: DisplayTrainRouteDistance(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
if (onViewYesterdayTrain != null &&
|
||||||
|
trainData.stations.first.departure!.scheduleTime
|
||||||
|
.compareTo(DateTime.now()) >
|
||||||
|
0)
|
||||||
|
...[
|
||||||
|
DisplayTrainYesterdayWarningFluent(
|
||||||
|
onViewYesterdayTrain!,
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.viewPadding
|
||||||
|
.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainID(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainOperator(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(left: 2, right: 2),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainRoute(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainDeparture(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainLastInfo(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: DisplayTrainRouteDuration(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: DisplayTrainRouteDistance(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SliverToBoxAdapter(
|
||||||
|
child: Divider(),
|
||||||
|
),
|
||||||
|
if (onViewYesterdayTrain != null &&
|
||||||
|
trainData.stations.first.departure!.scheduleTime
|
||||||
|
.compareTo(DateTime.now()) >
|
||||||
|
0) ...[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainYesterdayWarningFluent(
|
||||||
|
onViewYesterdayTrain!),
|
||||||
|
),
|
||||||
|
const SliverToBoxAdapter(
|
||||||
|
child: Divider(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.viewPadding
|
||||||
|
.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainID extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainID({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: trainData.rank,
|
||||||
|
style: TextStyle(
|
||||||
|
color: trainData.rank.startsWith('IR')
|
||||||
|
? const Color.fromARGB(255, 255, 0, 0)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text: trainData.number,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: FluentTheme.of(context).typography.title?.copyWith(
|
||||||
|
color: FluentTheme.of(context).typography.body?.color,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainOperator extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainOperator({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
trainData.operator,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRoute extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainRoute({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.route.from,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Center(child: Text("-")),
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.route.to,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainDeparture extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainDeparture({required this.trainData, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
// "Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}",
|
||||||
|
"Plecare în ${trainData.date}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainLastInfo extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainLastInfo({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (trainData.status == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
"Ultima informație",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.status!.station,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
stateToString(trainData.status!.state),
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final data = trainData.status!.delay;
|
||||||
|
if (data == 0) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data > 0) {
|
||||||
|
return Text(
|
||||||
|
"$data ${data == 1 ? 'minut' : 'minute'} întârziere",
|
||||||
|
style:
|
||||||
|
FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.red.lighter,
|
||||||
|
// color: Colors.red.shade300,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Text(
|
||||||
|
"${-data} ${data == -1 ? 'minut' : 'minute'} mai devreme",
|
||||||
|
style:
|
||||||
|
FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.green.lighter,
|
||||||
|
// color: Colors.green.shade300,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainDestination extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainDestination({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final destination = trainData.stations.last;
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
"Destinația",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
||||||
|
child: Text(
|
||||||
|
destination.name,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final arrival = destination.arrival!.scheduleTime.toLocal();
|
||||||
|
final delay =
|
||||||
|
trainData.stations.last.arrival!.status?.delay ?? 0;
|
||||||
|
final arrivalWithDelay =
|
||||||
|
arrival.add(Duration(minutes: delay));
|
||||||
|
final arrivalWithDelayString =
|
||||||
|
'${arrivalWithDelay.hour}:${arrivalWithDelay.minute.toString().padLeft(2, "0")}';
|
||||||
|
// const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 12 : 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: 'la',
|
||||||
|
children: [
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
'${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}',
|
||||||
|
style: delay == 0
|
||||||
|
? null
|
||||||
|
: const TextStyle(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (delay != 0) ...[
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text: arrivalWithDelayString,
|
||||||
|
style: TextStyle(
|
||||||
|
color: delay > 0
|
||||||
|
? Colors.red.lighter
|
||||||
|
: Colors.green.lighter,
|
||||||
|
// color: delay > 0
|
||||||
|
// ? Colors.red.shade300
|
||||||
|
// : Colors.green.shade300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRouteDistance extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainRouteDistance({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"Distanța rutei",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${trainData.stations.last.km} km",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRouteDuration extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
const DisplayTrainRouteDuration({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"Durata rutei",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
var duration = trainData.stations.last.arrival!.scheduleTime
|
||||||
|
.difference(
|
||||||
|
trainData.stations.first.departure!.scheduleTime);
|
||||||
|
var durationString = StringBuffer();
|
||||||
|
|
||||||
|
bool firstWritten = false;
|
||||||
|
|
||||||
|
if (duration.inDays > 0) {
|
||||||
|
firstWritten = true;
|
||||||
|
if (duration.inDays == 1) {
|
||||||
|
durationString.write("1 zi");
|
||||||
|
} else {
|
||||||
|
durationString.write("${duration.inDays} zile");
|
||||||
|
}
|
||||||
|
duration -= Duration(days: duration.inDays);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration.inHours > 0) {
|
||||||
|
if (firstWritten) {
|
||||||
|
durationString.write(", ");
|
||||||
|
}
|
||||||
|
firstWritten = true;
|
||||||
|
if (duration.inHours == 1) {
|
||||||
|
durationString.write("1 oră");
|
||||||
|
} else {
|
||||||
|
durationString.write("${duration.inHours} ore");
|
||||||
|
}
|
||||||
|
duration -= Duration(hours: duration.inHours);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration.inMinutes > 0) {
|
||||||
|
if (firstWritten) {
|
||||||
|
durationString.write(", ");
|
||||||
|
}
|
||||||
|
firstWritten = true;
|
||||||
|
if (duration.inMinutes == 1) {
|
||||||
|
durationString.write("1 minut");
|
||||||
|
} else {
|
||||||
|
durationString.write("${duration.inMinutes} minute");
|
||||||
|
}
|
||||||
|
duration -= Duration(minutes: duration.inMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
durationString.toString(),
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainYesterdayWarningFluent
|
||||||
|
extends DisplayTrainYesterdayWarningCommon {
|
||||||
|
const DisplayTrainYesterdayWarningFluent(super.onViewYesterdayTrain, {super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: DisplayTrainYesterdayWarningCommon.trainDidNotDepart,
|
||||||
|
),
|
||||||
|
const TextSpan(text: '\n'),
|
||||||
|
TextSpan(
|
||||||
|
text: DisplayTrainYesterdayWarningCommon.seeYesterdayTrain,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
recognizer: TapGestureRecognizer()
|
||||||
|
..onTap = onViewYesterdayTrain,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainStations extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
const DisplayTrainStations({required this.trainData, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return IndexedSemantics(
|
||||||
|
index: index,
|
||||||
|
child: DisplayTrainStation(
|
||||||
|
station: trainData.stations[index],
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).pushNamed(
|
||||||
|
ViewStationPage.routeName,
|
||||||
|
arguments: ViewStationArguments(stationName: trainData.stations[index].name),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
childCount: trainData.stations.length,
|
||||||
|
addSemanticIndexes: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,447 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
class DisplayTrainStation extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final void Function()? onTap;
|
||||||
|
|
||||||
|
const DisplayTrainStation({required this.station, this.onTap, super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: HoverButton(
|
||||||
|
onPressed: onTap,
|
||||||
|
builder: (context, states) {
|
||||||
|
return Card(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final departureStatus = station.departure?.status;
|
||||||
|
final arrivalStatus = station.arrival?.status;
|
||||||
|
int delay;
|
||||||
|
bool real;
|
||||||
|
if (departureStatus == null) {
|
||||||
|
delay = arrivalStatus?.delay ?? 0;
|
||||||
|
real = arrivalStatus?.real ?? false;
|
||||||
|
}
|
||||||
|
else if (arrivalStatus == null) {
|
||||||
|
delay = departureStatus.delay;
|
||||||
|
real = departureStatus.real;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delay = departureStatus.delay;
|
||||||
|
real = departureStatus.real;
|
||||||
|
if (!real && arrivalStatus.real) {
|
||||||
|
delay = arrivalStatus.delay;
|
||||||
|
real = arrivalStatus.real;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final isDelayed = delay > 0 && real == true;
|
||||||
|
final isOnTime = delay <= 0 && real == true;
|
||||||
|
const isNotScheduled = false;
|
||||||
|
|
||||||
|
return Badge(
|
||||||
|
text: station.km.toString(),
|
||||||
|
caption: 'km',
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Title(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: (station.platform == null)
|
||||||
|
? Container()
|
||||||
|
: Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: Badge(text: station.platform!, caption: 'linia',),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Time(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
Delay(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Title extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
const Title({
|
||||||
|
required this.station,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
station.name,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w500 : FontWeight.w300,
|
||||||
|
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Time extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
const Time({
|
||||||
|
required this.station,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival == null) {
|
||||||
|
// Plecare
|
||||||
|
return DepartureTime(
|
||||||
|
station: station,
|
||||||
|
firstStation: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (station.departure == null) {
|
||||||
|
// Sosire
|
||||||
|
return ArrivalTime(
|
||||||
|
station: station,
|
||||||
|
finalStation: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 2,),
|
||||||
|
ArrivalTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
StopTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
DepartureTime(station: station,),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArrivalTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool finalStation;
|
||||||
|
|
||||||
|
const ArrivalTime({
|
||||||
|
required this.station,
|
||||||
|
this.finalStation = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
if (finalStation) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 2,),
|
||||||
|
const Text("sosire la "),
|
||||||
|
ArrivalTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final delay = station.arrival!.status?.delay ?? 0;
|
||||||
|
final time = station.arrival!.scheduleTime.toLocal();
|
||||||
|
|
||||||
|
if (delay == 0) {
|
||||||
|
return Text("${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
|
||||||
|
}
|
||||||
|
else if (delay > 0) {
|
||||||
|
final oldDate = time;
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
// color: Colors.red.shade300,
|
||||||
|
color: Colors.red.lighter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final oldDate = time;
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
// color: Colors.green.shade300,
|
||||||
|
color: Colors.green.lighter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StopTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
const StopTime({
|
||||||
|
required this.station,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
const Text(
|
||||||
|
"staționează pentru",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
int stopsForInt = station.stoppingTime!;
|
||||||
|
bool minutes = false;
|
||||||
|
if (stopsForInt >= 60) {
|
||||||
|
stopsForInt ~/= 60;
|
||||||
|
minutes = true;
|
||||||
|
}
|
||||||
|
if (stopsForInt == 1) {
|
||||||
|
return Text(
|
||||||
|
"1 ${minutes ? 'minut' : 'secundă'}",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (stopsForInt < 20) {
|
||||||
|
return Text(
|
||||||
|
"$stopsForInt ${minutes ? 'minute' : 'secunde'}",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Text(
|
||||||
|
"$stopsForInt de ${minutes ? 'minute' : 'secunde'}",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DepartureTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool firstStation;
|
||||||
|
|
||||||
|
const DepartureTime({
|
||||||
|
required this.station,
|
||||||
|
this.firstStation = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.departure == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
if (firstStation) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
const Text("plecare la "),
|
||||||
|
DepartureTime(station: station,),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final delay = station.departure!.status?.delay ?? 0;
|
||||||
|
final time = station.departure!.scheduleTime.toLocal();
|
||||||
|
|
||||||
|
if (delay == 0) {
|
||||||
|
return Text("${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}");
|
||||||
|
}
|
||||||
|
else if (delay > 0) {
|
||||||
|
final oldDate = time;
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
// color: Colors.red.shade300,
|
||||||
|
color: Colors.red.lighter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final oldDate = time;
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
// color: Colors.green.shade300,
|
||||||
|
color: Colors.green.lighter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Delay extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
const Delay({
|
||||||
|
required this.station,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival?.status == null && station.departure?.status == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
var delay = station.arrival?.status?.delay;
|
||||||
|
if (station.departure?.status?.real == true) {
|
||||||
|
delay = station.departure?.status?.delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay == 0 || delay == null) {
|
||||||
|
return Container();
|
||||||
|
} else if (delay > 0) {
|
||||||
|
return Text(
|
||||||
|
"$delay ${delay == 1 ? 'minut' : 'minute'} întârziere",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
// color: Colors.red.shade300,
|
||||||
|
color: Colors.red.lighter,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (delay < 0) {
|
||||||
|
return Text(
|
||||||
|
"${-delay} ${delay == -1 ? 'minut' : 'minute'} mai devreme",
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
// color: Colors.green.shade300,
|
||||||
|
color: Colors.green.lighter,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info_material_DisplayTrainStation.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material_DisplayTrainStation.dart';
|
||||||
import 'package:info_tren/utils/state_to_string.dart';
|
import 'package:info_tren/utils/state_to_string.dart';
|
||||||
|
|
||||||
class TrainInfoLoadingMaterial extends TrainInfoLoading {
|
class TrainInfoLoadingMaterial extends TrainInfoLoadingShared {
|
||||||
TrainInfoLoadingMaterial({required super.title, super.loadingText, super.key,});
|
TrainInfoLoadingMaterial({required super.title, super.loadingText, super.key,});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -24,7 +24,7 @@ class TrainInfoLoadingMaterial extends TrainInfoLoading {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrainInfoErrorMaterial extends TrainInfoError {
|
class TrainInfoErrorMaterial extends TrainInfoErrorShared {
|
||||||
const TrainInfoErrorMaterial({
|
const TrainInfoErrorMaterial({
|
||||||
required super.error,
|
required super.error,
|
||||||
required super.title,
|
required super.title,
|
||||||
|
@ -61,15 +61,12 @@ class TrainInfoErrorMaterial extends TrainInfoError {
|
||||||
bool isSmallScreen(BuildContext context) =>
|
bool isSmallScreen(BuildContext context) =>
|
||||||
MediaQuery.of(context).size.height <= 425;
|
MediaQuery.of(context).size.height <= 425;
|
||||||
|
|
||||||
class TrainInfoMaterial extends StatelessWidget {
|
class TrainInfoMaterial extends TrainInfoShared {
|
||||||
final TrainData trainData;
|
|
||||||
final Future Function()? refresh;
|
|
||||||
final void Function()? onViewYesterdayTrain;
|
|
||||||
|
|
||||||
const TrainInfoMaterial({
|
const TrainInfoMaterial({
|
||||||
required this.trainData,
|
required super.trainData,
|
||||||
this.refresh,
|
super.refresh,
|
||||||
this.onViewYesterdayTrain,
|
super.onViewYesterdayTrain,
|
||||||
|
super.isRefreshing,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,12 +76,13 @@ class TrainInfoMaterial extends StatelessWidget {
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: isSmallScreen(context)
|
appBar: isSmallScreen(context)
|
||||||
? null
|
? null
|
||||||
: AppBar(
|
: AppBar(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
"Informații despre ${trainData.rank} ${trainData.number}"),
|
"Informații despre ${trainData.rank} ${trainData.number}",
|
||||||
),
|
),
|
||||||
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (isSmallScreen(context))
|
if (isSmallScreen(context))
|
||||||
|
@ -93,8 +91,8 @@ class TrainInfoMaterial extends StatelessWidget {
|
||||||
left: false,
|
left: false,
|
||||||
right: false,
|
right: false,
|
||||||
child: SlimAppBar(
|
child: SlimAppBar(
|
||||||
title:
|
title: 'INFO TREN - ${trainData.rank} ${trainData.number}',
|
||||||
'INFO TREN - ${trainData.rank} ${trainData.number}'),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
|
@ -102,102 +100,9 @@ class TrainInfoMaterial extends StatelessWidget {
|
||||||
top: isSmallScreen(context) ? false : true,
|
top: isSmallScreen(context) ? false : true,
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
onRefresh: refresh ?? () async {},
|
onRefresh: refresh ?? () async {},
|
||||||
child: CustomScrollView(
|
child: TrainInfoBody(
|
||||||
slivers: <Widget>[
|
trainData: trainData,
|
||||||
SliverToBoxAdapter(
|
onViewYesterdayTrain: onViewYesterdayTrain,
|
||||||
child: DisplayTrainID(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainOperator(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverPadding(
|
|
||||||
padding: const EdgeInsets.only(left: 2, right: 2),
|
|
||||||
sliver: SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainRoute(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainDeparture(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// SliverToBoxAdapter(
|
|
||||||
// child: Divider(
|
|
||||||
// color: Colors.white70,
|
|
||||||
// height: isSmallScreen(context) ? 8 : 16,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainLastInfo(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
// Expanded(child: DisplayTrainNextStop(trainData: trainData,)),
|
|
||||||
// Expanded(child: DisplayTrainDestination(trainData: trainData,)),
|
|
||||||
Expanded(
|
|
||||||
child: DisplayTrainRouteDuration(
|
|
||||||
trainData: trainData,
|
|
||||||
)),
|
|
||||||
Expanded(
|
|
||||||
child: DisplayTrainRouteDistance(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// SliverToBoxAdapter(
|
|
||||||
// child: IntrinsicHeight(
|
|
||||||
// child: Row(
|
|
||||||
// children: <Widget>[
|
|
||||||
// // Expanded(child: DisplayTrainRouteDuration(trainData: trainData,)),
|
|
||||||
// Expanded(child: Container(),),
|
|
||||||
// Expanded(child: DisplayTrainRouteDistance(trainData: trainData,)),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Divider(
|
|
||||||
color: Colors.white70,
|
|
||||||
height: isSmallScreen(context) ? 8 : 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (onViewYesterdayTrain != null &&
|
|
||||||
trainData.stations.first.departure!.scheduleTime
|
|
||||||
.compareTo(DateTime.now()) >
|
|
||||||
0) ...[
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainYesterdayWarningMaterial(
|
|
||||||
onViewYesterdayTrain!),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Divider(
|
|
||||||
color: Colors.white70,
|
|
||||||
height: isSmallScreen(context) ? 8 : 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
DisplayTrainStations(
|
|
||||||
trainData: trainData,
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
height: MediaQuery.of(context).viewPadding.bottom,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -210,6 +115,201 @@ class TrainInfoMaterial extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TrainInfoBodyMaterial extends TrainInfoBodyShared {
|
||||||
|
const TrainInfoBodyMaterial({
|
||||||
|
super.key,
|
||||||
|
required super.trainData,
|
||||||
|
super.onViewYesterdayTrain,
|
||||||
|
super.isRefreshing,
|
||||||
|
super.refresh,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mq = MediaQuery.of(context);
|
||||||
|
|
||||||
|
if (mq.orientation == Orientation.landscape && mq.size.width >= 1000) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 400,
|
||||||
|
maxWidth: 400,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
DisplayTrainID(trainData: trainData),
|
||||||
|
DisplayTrainOperator(trainData: trainData),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 2.0),
|
||||||
|
child: DisplayTrainRoute(trainData: trainData),
|
||||||
|
),
|
||||||
|
DisplayTrainDeparture(trainData: trainData),
|
||||||
|
DisplayTrainLastInfo(trainData: trainData),
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDuration(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDistance(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
color: Colors.white70,
|
||||||
|
height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
),
|
||||||
|
if (onViewYesterdayTrain != null &&
|
||||||
|
trainData.stations.first.departure!.scheduleTime
|
||||||
|
.compareTo(DateTime.now()) >
|
||||||
|
0)
|
||||||
|
...[
|
||||||
|
DisplayTrainYesterdayWarningMaterial(
|
||||||
|
onViewYesterdayTrain!,
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
color: Colors.white70,
|
||||||
|
height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.viewPadding
|
||||||
|
.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainID(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainOperator(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(left: 2, right: 2),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainRoute(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainDeparture(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: Divider(
|
||||||
|
// color: Colors.white70,
|
||||||
|
// height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainLastInfo(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
// Expanded(child: DisplayTrainNextStop(trainData: trainData,)),
|
||||||
|
// Expanded(child: DisplayTrainDestination(trainData: trainData,)),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDuration(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainRouteDistance(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: IntrinsicHeight(
|
||||||
|
// child: Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// // Expanded(child: DisplayTrainRouteDuration(trainData: trainData,)),
|
||||||
|
// Expanded(child: Container(),),
|
||||||
|
// Expanded(child: DisplayTrainRouteDistance(trainData: trainData,)),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Divider(
|
||||||
|
color: Colors.white70,
|
||||||
|
height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (onViewYesterdayTrain != null &&
|
||||||
|
trainData.stations.first.departure!.scheduleTime
|
||||||
|
.compareTo(DateTime.now()) >
|
||||||
|
0) ...[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainYesterdayWarningMaterial(
|
||||||
|
onViewYesterdayTrain!),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Divider(
|
||||||
|
color: Colors.white70,
|
||||||
|
height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.viewPadding
|
||||||
|
.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DisplayTrainID extends StatelessWidget {
|
class DisplayTrainID extends StatelessWidget {
|
||||||
final TrainData trainData;
|
final TrainData trainData;
|
||||||
|
|
||||||
|
@ -798,7 +898,7 @@ class DisplayTrainStations extends StatelessWidget {
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pushNamed(
|
Navigator.of(context).pushNamed(
|
||||||
ViewStationPage.routeName,
|
ViewStationPage.routeName,
|
||||||
arguments: trainData.stations[index].name,
|
arguments: ViewStationArguments(stationName: trainData.stations[index].name),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:info_tren/models.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/components/badge.dart';
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
||||||
|
|
||||||
class DisplayTrainStation extends StatelessWidget {
|
class DisplayTrainStation extends StatelessWidget {
|
||||||
|
@ -54,7 +54,7 @@ class DisplayTrainStation extends StatelessWidget {
|
||||||
final isOnTime = delay <= 0 && real == true;
|
final isOnTime = delay <= 0 && real == true;
|
||||||
const isNotScheduled = false;
|
const isNotScheduled = false;
|
||||||
|
|
||||||
return MaterialBadge(
|
return Badge(
|
||||||
text: station.km.toString(),
|
text: station.km.toString(),
|
||||||
caption: 'km',
|
caption: 'km',
|
||||||
isNotScheduled: isNotScheduled,
|
isNotScheduled: isNotScheduled,
|
||||||
|
@ -74,7 +74,7 @@ class DisplayTrainStation extends StatelessWidget {
|
||||||
? Container()
|
? Container()
|
||||||
: Align(
|
: Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: MaterialBadge(text: station.platform!, caption: 'linia',),
|
child: Badge(text: station.platform!, caption: 'linia',),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -6,6 +6,9 @@ UiDesign get defaultUiDesign {
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
return UiDesign.CUPERTINO;
|
return UiDesign.CUPERTINO;
|
||||||
}
|
}
|
||||||
|
else if (Platform.isLinux || Platform.isWindows) {
|
||||||
|
return UiDesign.FLUENT;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return UiDesign.MATERIAL;
|
return UiDesign.MATERIAL;
|
||||||
}
|
}
|
||||||
|
|
44
pubspec.lock
44
pubspec.lock
|
@ -99,6 +99,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
clock:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: clock
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
code_builder:
|
code_builder:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -162,6 +169,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
fluent_ui:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fluent_ui
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.3+1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -181,6 +195,11 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
flutter_localizations:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -256,6 +275,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
intl:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.17.0"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -311,7 +337,7 @@ packages:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.1.5"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -424,6 +450,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
recase:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: recase
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -431,6 +464,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
|
scroll_pos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: scroll_pos
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -659,7 +699,7 @@ packages:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.2"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -11,7 +11,7 @@ description: O aplicație de vizualizare a datelor puse la dispoziție de Inform
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 2.7.8
|
version: 2.7.9
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.0 <3.0.0"
|
sdk: ">=2.17.0 <3.0.0"
|
||||||
|
@ -33,6 +33,7 @@ dependencies:
|
||||||
freezed_annotation: ^2.2.0
|
freezed_annotation: ^2.2.0
|
||||||
json_annotation: ^4.7.0
|
json_annotation: ^4.7.0
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
|
fluent_ui: ^4.0.3+1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
# flutter_test:
|
# flutter_test:
|
||||||
|
|
Loading…
Add table
Reference in a new issue