feat(client): Flutter app (web target) — Phase 7 start
Single Flutter codebase under client/app/ with web enabled (mobile/desktop can be added later; lib/ is platform-agnostic). Talks to the NestJS backend via a thin REST wrapper; API_BASE is a --dart-define (defaults to the local backend). Screens: - Login: Konfi/guest (invite code), local Teamer password login, Teamer invite redemption. Token persisted in shared_preferences, restored on start; GET /auth/me drives a role-aware home. - Workshop-Wahl (guests): loads /wahl/guest/overview, ordered pick of up to 3 workshops, submits to /wahl/:id/teilnehmer. - Dateien: /files/:kcId list. - Chat: channel + message list (read-only; WS send is a follow-up). State: AppState (ChangeNotifier) exposed via an InheritedNotifier (AppScope) — no third-party state package. flutter analyze clean, flutter build web --release passes, one widget smoke test. Also: interim client/web/ HTML placeholder stays as-is (per plan it is superseded by this Flutter web build). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'api.dart';
|
||||
import 'screens/home_screen.dart';
|
||||
import 'screens/login_screen.dart';
|
||||
|
||||
void main() {
|
||||
final state = AppState(Api(http.Client()))..bootstrap();
|
||||
runApp(KcApp(state: state));
|
||||
}
|
||||
|
||||
/// Minimal InheritedNotifier so screens can read `AppState.of(context)` and
|
||||
/// rebuild on change — no third-party state management.
|
||||
class AppScope extends InheritedNotifier<AppState> {
|
||||
const AppScope({super.key, required AppState state, required super.child})
|
||||
: super(notifier: state);
|
||||
|
||||
static AppState of(BuildContext context) {
|
||||
final scope = context.dependOnInheritedWidgetOfExactType<AppScope>();
|
||||
assert(scope != null, 'AppScope missing above this widget');
|
||||
return scope!.notifier!;
|
||||
}
|
||||
}
|
||||
|
||||
class KcApp extends StatelessWidget {
|
||||
const KcApp({super.key, required this.state});
|
||||
final AppState state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppScope(
|
||||
state: state,
|
||||
child: MaterialApp(
|
||||
title: 'KC-App',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
colorSchemeSeed: const Color(0xFF3B5BA5),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const _AuthGate(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AuthGate extends StatelessWidget {
|
||||
const _AuthGate();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = AppScope.of(context);
|
||||
if (state.loading) {
|
||||
return const Scaffold(body: Center(child: CircularProgressIndicator()));
|
||||
}
|
||||
return state.isLoggedIn ? const HomeScreen() : const LoginScreen();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user