Files
Client/lib/view/pages/rmv/stations/station_detail_view.dart
T

198 lines
5.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../api/connect/rmv/rmv_models.dart';
import '../../../../api/errors/error_mapper.dart';
import '../../../../routing/app_routes.dart';
import '../../../../state/app/modules/rmv/repository/rmv_repository.dart';
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../../widget/app_progress_indicator.dart';
import '../favorites_controller.dart';
import '../widgets/departure_arrival_tile.dart';
enum _Direction { departures, arrivals }
class StationDetailView extends StatefulWidget {
final StopLocation station;
const StationDetailView({super.key, required this.station});
@override
State<StationDetailView> createState() => _StationDetailViewState();
}
class _StationDetailViewState extends State<StationDetailView> {
final RmvRepository _repo = RmvRepository();
_Direction _direction = _Direction.departures;
List<Departure>? _departures;
List<Arrival>? _arrivals;
bool _loading = false;
Object? _error;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
setState(() {
_loading = true;
_error = null;
});
try {
if (_direction == _Direction.departures) {
final result = await _repo.departures(widget.station.id);
if (!mounted) return;
setState(() {
_departures = result;
_loading = false;
});
} else {
final result = await _repo.arrivals(widget.station.id);
if (!mounted) return;
setState(() {
_arrivals = result;
_loading = false;
});
}
} catch (e) {
if (!mounted) return;
setState(() {
_error = e;
_loading = false;
});
}
}
void _switch(_Direction d) {
if (d == _direction) return;
setState(() {
_direction = d;
_departures = null;
_arrivals = null;
});
_load();
}
@override
Widget build(BuildContext context) {
final settings = context.watch<SettingsCubit>();
final favCtrl = RmvFavoritesController(settings);
final isFav = favCtrl.isFavorite(widget.station);
return Scaffold(
appBar: AppBar(
title: Text(widget.station.name),
actions: [
IconButton(
tooltip: isFav ? 'Favorit entfernen' : 'Als Favorit speichern',
icon: Icon(isFav ? Icons.star : Icons.star_border),
onPressed: () => favCtrl.toggleFavorite(widget.station),
),
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
child: SegmentedButton<_Direction>(
segments: const [
ButtonSegment(
value: _Direction.departures,
icon: Icon(Icons.north_east),
label: Text('Abfahrten'),
),
ButtonSegment(
value: _Direction.arrivals,
icon: Icon(Icons.south_west),
label: Text('Ankünfte'),
),
],
selected: {_direction},
onSelectionChanged: (s) => _switch(s.first),
),
),
Expanded(child: _body()),
],
),
);
}
Widget _body() {
if (_loading) {
return const Center(child: AppProgressIndicator.large());
}
final err = _error;
if (err != null) {
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
errorToUserMessage(err),
textAlign: TextAlign.center,
style: TextStyle(color: Theme.of(context).colorScheme.error),
),
const SizedBox(height: 12),
FilledButton.icon(
icon: const Icon(Icons.refresh),
onPressed: _load,
label: const Text('Erneut versuchen'),
),
],
),
),
);
}
if (_direction == _Direction.departures) {
final list = _departures ?? const <Departure>[];
if (list.isEmpty) return _emptyState('Keine Abfahrten gefunden.');
return RefreshIndicator(
onRefresh: _load,
child: ListView.separated(
itemCount: list.length,
separatorBuilder: (_, _) => const Divider(height: 1),
itemBuilder: (_, i) => DepartureArrivalTile.fromDeparture(
list[i],
onTap: () => _openJourney(list[i].journeyRef),
),
),
);
}
final list = _arrivals ?? const <Arrival>[];
if (list.isEmpty) return _emptyState('Keine Ankünfte gefunden.');
return RefreshIndicator(
onRefresh: _load,
child: ListView.separated(
itemCount: list.length,
separatorBuilder: (_, _) => const Divider(height: 1),
itemBuilder: (_, i) => DepartureArrivalTile.fromArrival(
list[i],
onTap: () => _openJourney(list[i].journeyRef),
),
),
);
}
Widget _emptyState(String text) => RefreshIndicator(
onRefresh: _load,
child: ListView(
physics: const AlwaysScrollableScrollPhysics(),
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 80, horizontal: 24),
child: Center(
child: Text(text, style: Theme.of(context).textTheme.bodyLarge),
),
),
],
),
);
void _openJourney(String? ref) {
if (ref == null) return;
AppRoutes.openRmvJourneyDetail(context, ref);
}
}