reclaim/app/lib/main.dart
flemming-it 9dfa418e92 fix(ui): never hang on a blank frame when the hub is unreachable
main() awaited the hub health probe before runApp(); a gRPC-web
error out of HubRepository.connect propagated and left the app on a
white page. Guard the settings+probe in main() with a MockRepository
fallback so the first frame always paints.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-19 02:25:39 +02:00

74 lines
2.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'data/hub_endpoint.dart';
import 'data/hub_repository.dart';
import 'data/repository.dart';
import 'pages/landing_page.dart';
import 'theme/reclaim_theme.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Acquiring settings + probing the hub must never prevent the
// first frame. Any failure here falls back to demo data so the
// app always paints instead of hanging on a blank page.
HubSettings settings;
EvaluationRepository repository;
try {
settings = await HubSettings.load();
repository = await _pickRepository(settings);
} catch (_) {
settings = const HubSettings(
host: HubSettings.defaultHost,
port: HubSettings.defaultPort,
secure: false,
);
repository = const MockRepository();
}
runApp(ReclaimApp(repository: repository, settings: settings));
}
/// Decide which repository to start with.
///
/// useHub=false → MockRepository, explicit opt-in to
/// demo data via the Hub-Reiter.
/// useHub=true → HubRepository regardless of probe
/// outcome. When unhealthy the
/// repository's list() returns [] and
/// the ModeBanner shows 'hub-down' —
/// no silent mock fallback that would
/// quietly demote the app to demo
/// mode.
Future<EvaluationRepository> _pickRepository(HubSettings settings) async {
if (!settings.useHub) return const MockRepository();
return HubRepository.connect(settings);
}
class ReclaimApp extends StatelessWidget {
const ReclaimApp({
super.key,
this.repository = const MockRepository(),
this.settings,
});
final EvaluationRepository repository;
final HubSettings? settings;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Recl∆Im',
debugShowCheckedModeBanner: false,
theme: ReclaimTheme.light(),
darkTheme: ReclaimTheme.dark(),
themeMode: ThemeMode.dark,
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('de'), Locale('en')],
home: LandingPage(repository: repository),
);
}
}