implemented RMV public transit module including trip search, station departures, and nearby stop lookup, added "Marianum Connect" API integration with bearer token authentication and auto-refresh logic, integrated geolocator for location-based station search, added persistent storage for favorite stations and recent trip queries, and implemented comprehensive UI for journey details, trip results, and disruption alerts
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../routing/app_routes.dart';
|
||||
import '../../../state/app/infrastructure/loadable_state/loadable_state.dart';
|
||||
import '../../../state/app/infrastructure/utility_widgets/bloc_module.dart';
|
||||
import '../../../state/app/modules/rmv/bloc/rmv_bloc.dart';
|
||||
import '../../../state/app/modules/rmv/bloc/rmv_state.dart';
|
||||
import 'stations/station_overview_tab.dart';
|
||||
import 'trip_search/trip_search_tab.dart';
|
||||
|
||||
class RmvView extends StatelessWidget {
|
||||
const RmvView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) =>
|
||||
BlocModule<RmvBloc, LoadableState<RmvState>>(
|
||||
create: (context) => RmvBloc(),
|
||||
autoRebuild: true,
|
||||
child: (context, bloc, state) {
|
||||
final disruptions = bloc.getDisruptions();
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('RMV-Fahrplan'),
|
||||
bottom: const TabBar(
|
||||
tabs: [
|
||||
Tab(icon: Icon(Icons.alt_route), text: 'Verbindung'),
|
||||
Tab(icon: Icon(Icons.directions_bus), text: 'Stationen'),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Builder(
|
||||
builder: (ctx) => IconButton(
|
||||
icon: _disruptionsIcon(disruptions.length),
|
||||
tooltip: 'Störungsmeldungen',
|
||||
onPressed: () => AppRoutes.openRmvDisruptions(ctx),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: const TabBarView(
|
||||
children: [
|
||||
TripSearchTab(),
|
||||
StationOverviewTab(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Widget _disruptionsIcon(int count) {
|
||||
if (count <= 0) return const Icon(Icons.warning_amber_outlined);
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
const Icon(Icons.warning_amber_outlined),
|
||||
Positioned(
|
||||
right: -6,
|
||||
top: -6,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
constraints: const BoxConstraints(minWidth: 16, minHeight: 16),
|
||||
child: Text(
|
||||
count > 99 ? '99+' : '$count',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user