Skip to content

Commit

Permalink
feat(no-forecasts): add the edge case when all forecasts has passed (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vareversat authored Nov 9, 2023
1 parent 0287d4d commit ce59836
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 19 deletions.
23 changes: 17 additions & 6 deletions lib/bloc/forecast/forecast_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ForecastBloc extends Bloc<ForecastEvent, ForecastState> {
return [];
}

AbstractForecast _getCurrentStatus(
AbstractForecast? _getCurrentStatus(
List<AbstractForecast> forecast,
) {
int middle = forecast.length ~/ 2;
Expand All @@ -94,10 +94,16 @@ class ForecastBloc extends Bloc<ForecastEvent, ForecastState> {
return forecast[middle];
}
if (forecast.length == 2) {
return forecast[1].circulationClosingDate.isAfter(DateTime.now()) &&
forecast[0].circulationReOpeningDate.isBefore(DateTime.now())
? forecast[1]
: forecast[0];
if (forecast[1].circulationClosingDate.isAfter(DateTime.now()) &&
forecast[0].circulationReOpeningDate.isBefore(DateTime.now())) {
return forecast[1];
} else {
if (!forecast[0].circulationReOpeningDate.isBefore(DateTime.now())) {
return forecast[0];
} else {
return null;
}
}
} else if (forecast[middle]
.circulationClosingDate
.isAfter(DateTime.now())) {
Expand All @@ -109,8 +115,11 @@ class ForecastBloc extends Bloc<ForecastEvent, ForecastState> {

AbstractForecast? _getPreviousStatus(
List<AbstractForecast> forecasts,
AbstractForecast currentStatus,
AbstractForecast? currentStatus,
) {
if (currentStatus == null) {
return null;
}
return forecasts.indexOf(currentStatus) == 0
? null
: forecasts.elementAt(forecasts.indexOf(currentStatus) - 1);
Expand All @@ -125,11 +134,13 @@ class ForecastBloc extends Bloc<ForecastEvent, ForecastState> {
if (state.status == ForecastStatus.initial) {
final forecasts = await _fetchForecasts(state.offset);
final currentStatus = _getCurrentStatus(forecasts);
final noMoreForecasts = currentStatus == null;
emit(state.copyWith(
status: ForecastStatus.success,
forecasts: forecasts,
currentForecast: currentStatus,
previousForecast: _getPreviousStatus(forecasts, currentStatus),
noMoreForecasts: noMoreForecasts,
hasReachedMax: false,
offset: state.offset + Const.forecastLimit,
));
Expand Down
4 changes: 4 additions & 0 deletions lib/bloc/forecast/forecast_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ForecastState extends Equatable {
final List<AbstractForecast> forecasts;
final AbstractForecast? currentForecast;
final AbstractForecast? previousForecast;
final bool noMoreForecasts;
final bool hasReachedMax;
final int offset;
final String message;
Expand All @@ -17,13 +18,15 @@ class ForecastState extends Equatable {
this.hasReachedMax = false,
this.offset = 0,
this.message = 'OK',
this.noMoreForecasts = false,
});

ForecastState copyWith({
ForecastStatus? status,
List<AbstractForecast>? forecasts,
AbstractForecast? currentForecast,
AbstractForecast? previousForecast,
bool? noMoreForecasts,
bool? hasReachedMax,
int? offset,
String? message,
Expand All @@ -33,6 +36,7 @@ class ForecastState extends Equatable {
forecasts: forecasts ?? this.forecasts,
currentForecast: currentForecast ?? this.currentForecast,
previousForecast: previousForecast ?? this.previousForecast,
noMoreForecasts: noMoreForecasts ?? this.noMoreForecasts,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
offset: offset ?? this.offset,
message: message ?? this.message,
Expand Down
8 changes: 4 additions & 4 deletions lib/bloc/status/status_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class StatusBloc extends Bloc<StatusEvent, StatusState> {
return Theme.of(context).colorScheme.error;
}
} else {
return state.backgroundColor;
return Theme.of(context).colorScheme.okColor;
}
}

Expand All @@ -129,7 +129,7 @@ class StatusBloc extends Bloc<StatusEvent, StatusState> {
? colorScheme.background
: colorScheme.onError;
} else {
return state.foregroundColor;
return Theme.of(context).colorScheme.background;
}
}

Expand All @@ -140,7 +140,7 @@ class StatusBloc extends Bloc<StatusEvent, StatusState> {
? '${AppLocalizations.of(context)!.scheduledToOpen.capitalize()} '
: '${AppLocalizations.of(context)!.nextClosingScheduled.capitalize()} ';
} else {
return 'NO_TIME';
return '';
}
}

Expand All @@ -162,7 +162,7 @@ class StatusBloc extends Bloc<StatusEvent, StatusState> {
: AppLocalizations.of(context)!.willSoonClose.capitalize();
} else {
return state.statusWidgetDimension == StatusWidgetDimension.large
? '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theChabanBridgeIsClosed}'
? '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theChabanBridgeIsOpen}'
: AppLocalizations.of(context)!.isClosed.capitalize();
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/bloc/status/status_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class StatusStateInitial extends StatusState {
durationUntilNextEvent: Duration.zero,
durationBetweenPreviousAndNextEvent: null,
durationForCloseClosing: Const.notificationDurationValueDefaultValue,
statusLifecycle: StatusLifecycle.empty,
statusLifecycle: StatusLifecycle.loading,
completionPercentage: 0,
mainMessageStatus: '',
timeMessagePrefix: '',
Expand All @@ -99,6 +99,6 @@ class StatusStateInitial extends StatusState {
);
}

enum StatusLifecycle { empty, populated }
enum StatusLifecycle { empty, populated, loading }

enum StatusWidgetDimension { small, large }
4 changes: 3 additions & 1 deletion lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,7 @@
"wineFestivalSailBoats": "Wine Festival Sailboats",
"externalLinks": "External links",
"rate": "Rate",
"timeFormatSubTitle": "Time format"
"timeFormatSubTitle": "Time format",
"noMoreForecastsTitle": "No upcoming events",
"noMoreForecastsMessage": "Bordeaux Métropole has not communicated any closure of the Chaban-Delmas Bridge for the coming weeks.\nStay informed of upcoming closures by returning here regularly"
}
4 changes: 3 additions & 1 deletion lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,7 @@
"wineFestivalSailBoats": "Veleros de la Fiesta del Vino",
"externalLinks": "Enlaces externos",
"rate": "Califica",
"timeFormatSubTitle": "Formato de hora"
"timeFormatSubTitle": "Formato de hora",
"noMoreForecastsTitle": "Ningún acontecimiento por venir",
"noMoreForecastsMessage": "Bordeaux Métropole no ha comunicado ningún cierre del Puente Chaban-Delmas para las próximas semanas.\nManténgase informado de los próximos cierres volviendo aquí regularmente"
}
4 changes: 3 additions & 1 deletion lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,7 @@
"wineFestivalSailBoats": "Voiliers de la fête du vin",
"externalLinks": "Liens externes",
"rate": "Noter",
"timeFormatSubTitle": "Format d'affichage des heures"
"timeFormatSubTitle": "Format d'affichage des heures",
"noMoreForecastsTitle": "Aucun évènement à venir",
"noMoreForecastsMessage": "Bordeaux Métropole n'a communiqué aucune fermeture du Pont Chaban-Delmas pour les prochaines semaines.\nTenez-vous informer des prochaines fermetures en revenant ici régulièrement"
}
4 changes: 4 additions & 0 deletions lib/models/boat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class Boat extends Equatable {
isWineFestivalSailBoats = name == Const.specialWineFestivalBoatsEvent;
}

factory Boat.fake() {
return Boat(name: 'fake', isLeaving: true);
}

void _launchURL(String url) async {
await launchUrlString(url, mode: LaunchMode.externalApplication);
}
Expand Down
9 changes: 9 additions & 0 deletions lib/models/boat_forecast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ class BoatForecast extends AbstractForecast {
closingReason: ForecastClosingReason.boat,
);

factory BoatForecast.fake() {
return BoatForecast(
totalClosing: true,
circulationClosingDate: DateTime.now(),
circulationReOpeningDate: DateTime.now(),
boats: [Boat.fake()],
closingType: ForecastClosingType.complete);
}

factory BoatForecast.fromJSON(Map<String, dynamic> json) {
var apiTimezone = AbstractForecast.getApiTimeZone(json['record_timestamp']);
var closingDate = AbstractForecast.parseFieldDate(
Expand Down
8 changes: 8 additions & 0 deletions lib/models/maintenance_forecast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ class MaintenanceForecast extends AbstractForecast {
closingReason: ForecastClosingReason.maintenance,
);

factory MaintenanceForecast.fake() {
return MaintenanceForecast(
totalClosing: true,
circulationClosingDate: DateTime.now(),
circulationReOpeningDate: DateTime.now(),
closingType: ForecastClosingType.complete);
}

factory MaintenanceForecast.fromJSON(Map<String, dynamic> json) {
var apiTimezone = AbstractForecast.getApiTimeZone(json['record_timestamp']);
var closingDate = AbstractForecast.parseFieldDate(
Expand Down
5 changes: 5 additions & 0 deletions lib/widgets/forecast/forecast_list_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:chabo_app/bloc/scroll_status/scroll_status_bloc.dart';
import 'package:chabo_app/bloc/time_slots/time_slots_bloc.dart';
import 'package:chabo_app/models/abstract_forecast.dart';
import 'package:chabo_app/widgets/forecast/forecast_widget/forecast_widget.dart';
import 'package:chabo_app/widgets/forecast/no_more_forecasts_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
Expand All @@ -24,6 +25,10 @@ class _ForecastListWidgetState extends State<ForecastListWidget> {
return SliverToBoxAdapter(
child: BlocBuilder<TimeSlotsBloc, TimeSlotsState>(
builder: (context, timeSlotState) {
// Check if the last forecast is before today
if (forecastState.noMoreForecasts) {
return const NoMoreForecastsWidget();
}
return ListView.separated(
shrinkWrap: true,
cacheExtent: 5000,
Expand Down
51 changes: 51 additions & 0 deletions lib/widgets/forecast/no_more_forecasts_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:chabo_app/models/boat_forecast.dart';
import 'package:chabo_app/models/maintenance_forecast.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

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

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 100.0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
AppLocalizations.of(context)!.noMoreForecastsTitle,
style: Theme.of(context)
.textTheme
.titleLarge!
.copyWith(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Center(
child: Text(
AppLocalizations.of(context)!.noMoreForecastsMessage,
textAlign: TextAlign.center,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BoatForecast.fake().getIconWidget(context, false, 40, true),
const Text(' • '),
MaintenanceForecast.fake()
.getIconWidget(context, false, 40, true),
],
),
)
],
),
);
}
}
7 changes: 4 additions & 3 deletions lib/widgets/forecast/status_widget/layout_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ class _LayoutWidget extends StatelessWidget {
statusState: statusState,
),
),
_ProgressIndicatorWidget(
statusState: statusState,
),
if (statusState.currentForecast != null)
_ProgressIndicatorWidget(
statusState: statusState,
),
const SizedBox(
height: 10,
),
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/forecast/status_widget/status_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class StatusWidgetState extends CustomWidgetState<StatusWidget> {
child: child,
);
},
child: state.statusLifecycle == StatusLifecycle.empty
child: state.statusLifecycle == StatusLifecycle.loading
? CustomCircularProgressIndicator(
message: AppLocalizations.of(context)!.statusLoadMessage,
)
Expand Down

0 comments on commit ce59836

Please sign in to comment.