Files
rippr/lib/main.dart
uhryniuk 5013b7002f V3-06: live stats in the notification
RideNotificationController seam over flutter_local_notifications; RideNotificationCoordinator wires TripRepository.watchActiveTrip() to it and routes Pause/Resume actions back into RecordingEngine. Instantiated eagerly at app root rather than screen-owned, since a pocketed ride has no visible widget tree. Documents an unresolved risk: geolocator's own foreground-service notification cannot be suppressed, so two notifications may be visible until verified on a device.
2026-08-17 15:04:34 -05:00

48 lines
1.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'src/app/providers.dart';
import 'src/config/config.dart';
import 'src/ui/router.dart';
import 'src/ui/theme.dart';
void main() {
runApp(const ProviderScope(child: RipprApp()));
}
class RipprApp extends ConsumerStatefulWidget {
const RipprApp({super.key});
@override
ConsumerState<RipprApp> createState() => _RipprAppState();
}
class _RipprAppState extends ConsumerState<RipprApp> {
final _router = buildRouter();
@override
void initState() {
super.initState();
// Re-attach to a ride that was in progress when the process died. Must run before any
// user interaction, and the database is the only thing that knows a ride was open.
WidgetsBinding.instance.addPostFrameCallback((_) async {
// Preferences first: the uploader and the map toggle both read from them.
ref.read(configProvider.notifier).state = await Config.load();
await ref.read(recordingEngineProvider).restoreAfterProcessDeath();
});
}
@override
Widget build(BuildContext context) {
// V3-06: forces creation so the live notification keeps updating and Pause/Resume
// keeps working regardless of which screen is on top -- see the provider's doc.
ref.watch(rideNotificationCoordinatorProvider);
return MaterialApp.router(
title: 'Rippr',
debugShowCheckedModeBanner: false,
theme: ripprTheme(),
routerConfig: _router,
);
}
}