Five-layer architecture per DMC_Architektur_und_Design.md: FlightControllerLink abstraction (Mock + MSP stub), protocol-neutral mission domain layer, App-Mode state machine with Ready-to-Fly gate, Drift persistence schema, and placeholder UI screens wired via go_router. App icon generated from design/Y2_pink_dark.svg. Verified with flutter analyze and flutter test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
66 lines
1.9 KiB
Dart
66 lines
1.9 KiB
Dart
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
/// Explizite Zustandsfolge Plan -> Connect -> Upload -> Fly
|
|
/// (Architektur-Doku 2.2).
|
|
enum AppMode { plan, connect, upload, fly }
|
|
|
|
class AppModeState {
|
|
const AppModeState({
|
|
this.mode = AppMode.plan,
|
|
this.missionUploaded = false,
|
|
this.missionVerified = false,
|
|
this.droneArmed = false,
|
|
});
|
|
|
|
final AppMode mode;
|
|
final bool missionUploaded;
|
|
final bool missionVerified;
|
|
final bool droneArmed;
|
|
|
|
/// Ready-to-Fly-Gate (Doku 2.2 / 4.5): Upload + verifiziert + disarmed.
|
|
/// Muss technisch erzwungen werden, nicht nur als UI-Konvention gelten.
|
|
bool get readyToFly => missionUploaded && missionVerified && !droneArmed;
|
|
|
|
AppModeState copyWith({
|
|
AppMode? mode,
|
|
bool? missionUploaded,
|
|
bool? missionVerified,
|
|
bool? droneArmed,
|
|
}) {
|
|
return AppModeState(
|
|
mode: mode ?? this.mode,
|
|
missionUploaded: missionUploaded ?? this.missionUploaded,
|
|
missionVerified: missionVerified ?? this.missionVerified,
|
|
droneArmed: droneArmed ?? this.droneArmed,
|
|
);
|
|
}
|
|
}
|
|
|
|
class AppModeCubit extends Cubit<AppModeState> {
|
|
AppModeCubit() : super(const AppModeState());
|
|
|
|
void toConnect() => emit(state.copyWith(mode: AppMode.connect));
|
|
|
|
void toUpload() => emit(state.copyWith(mode: AppMode.upload));
|
|
|
|
void missionUploadConfirmed() =>
|
|
emit(state.copyWith(missionUploaded: true));
|
|
|
|
void missionVerifiedConfirmed() =>
|
|
emit(state.copyWith(missionVerified: true));
|
|
|
|
void droneArmedChanged(bool armed) =>
|
|
emit(state.copyWith(droneArmed: armed));
|
|
|
|
/// Wirft, wenn das Ready-to-Fly-Gate nicht erfuellt ist (Doku 4.5).
|
|
void toFly() {
|
|
if (!state.readyToFly) {
|
|
throw StateError('Ready-to-Fly-Gate nicht erfuellt.');
|
|
}
|
|
emit(state.copyWith(mode: AppMode.fly));
|
|
}
|
|
|
|
/// Verlassen des Fly-Modus setzt den kompletten Handover-Status zurueck.
|
|
void toPlan() => emit(const AppModeState());
|
|
}
|