diff --git a/software/app/lib/leader_selection_screen.dart b/software/app/lib/leader_selection_screen.dart deleted file mode 100644 index b472082..0000000 --- a/software/app/lib/leader_selection_screen.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_blue_plus/flutter_blue_plus.dart'; -import 'package:lasertag_app/l10n/app_localizations.dart'; -import 'constants.dart'; - -class LeaderSelectionScreen extends StatefulWidget { - const LeaderSelectionScreen({super.key}); - - @override - State createState() => _LeaderSelectionScreenState(); -} - -class _LeaderSelectionScreenState extends State { - // Map, um Geräte und ihren erkannten Typ zu speichern - Map discoveredDevices = {}; - - @override - void initState() { - super.initState(); - _startDiscovery(); - } - - void _startDiscovery() async { - FlutterBluePlus.scanResults.listen((results) { - for (ScanResult r in results) { - // 1. Prüfen, ob Manufacturer Data für unsere Test-ID (0xFFFF / 65535) da ist - final mfgData = r.advertisementData.manufacturerData[65535]; - - if (mfgData != null && mfgData.isNotEmpty) { - int detectedType = mfgData[0]; // Das Typ-Byte vom nRF52 - - // 2. Nur hinzufügen, wenn es wirklich ein Leader (0x01) ist - if (detectedType == LasertagUUIDs.typeLeader) { - if (!discoveredDevices.containsKey(r.device)) { - setState(() { - discoveredDevices[r.device] = detectedType; - }); - } - } - } - } - }); - // 2. Warten, bis der Bluetooth-Adapter wirklich "on" ist - await FlutterBluePlus.adapterState - .where((s) => s == BluetoothAdapterState.on) - .first; - - // 3. Den Scan tatsächlich starten - try { - // Filtert nach der Service-UUID ...1000 aus ble_mgmt.c - await FlutterBluePlus.startScan( - withServices: [Guid(LasertagUUIDs.provService)], - timeout: const Duration(seconds: 15), - ); - } catch (e) { - debugPrint("Scan-Fehler: $e"); - } - } // <--- Hier endet _startDiscovery korrekt - - // Hilfsfunktion zur Übersetzung des Typs - String _getLocalizedTypeName(BuildContext context, int type) { - final l10n = AppLocalizations.of(context)!; - switch (type) { - case LasertagUUIDs.typeLeader: - return l10n.typeLeader; - case LasertagUUIDs.typeWeapon: - return l10n.typeWeapon; - case LasertagUUIDs.typeVest: - return l10n.typeVest; - case LasertagUUIDs.typeBeacon: - return l10n.typeBeacon; - default: - return "Unknown"; - } - } - - @override - Widget build(BuildContext context) { - final l10n = AppLocalizations.of(context)!; - - return Scaffold( - appBar: AppBar(title: Text(l10n.selectLeader)), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text(l10n.searching), - ), - Expanded( - child: ListView( - children: discoveredDevices.entries.map((entry) { - final device = entry.key; - final type = entry.value; - return ListTile( - leading: Icon( - Icons.hub, - // Holt sich die Akzentfarbe direkt vom Betriebssystem via Theme-Context - color: Theme.of(context).colorScheme.primary, - size: 32, - ), - title: Text( - device.platformName.isEmpty - ? "Lasertag Device" - : device.platformName, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text( - "${_getLocalizedTypeName(context, type)} (${device.remoteId})", - // Nutzt eine dezentere Farbe für den Untertitel - style: TextStyle( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - onTap: () => _onLeaderSelected(device), - ); - }).toList(), - ), - ), - ], - ), - ); - } - - void _onLeaderSelected(BluetoothDevice device) { - debugPrint("Leader ausgewählt: ${device.platformName}"); - // Hier öffnen wir als nächstes den Config-Dialog - } -} diff --git a/software/app/lib/main.dart b/software/app/lib/main.dart index 500882f..f1c4bc5 100644 --- a/software/app/lib/main.dart +++ b/software/app/lib/main.dart @@ -1,11 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; // Neu import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:lasertag_app/l10n/app_localizations.dart'; import 'ui/screens/device_selection_screen.dart'; +import 'providers/device_provider.dart'; // Neu void main() { - runApp(const LasertagApp()); + runApp( + // Den Provider hier für die ganze App bereitstellen + ChangeNotifierProvider( + create: (context) => DeviceProvider(), + child: const LasertagApp(), + ), + ); } class LasertagApp extends StatelessWidget { @@ -13,24 +21,13 @@ class LasertagApp extends StatelessWidget { @override Widget build(BuildContext context) { - // Der Builder holt die Systemfarben (Accent Color) return DynamicColorBuilder( builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) { return MaterialApp( debugShowCheckedModeBanner: false, - - // --- Lokalisierung --- - localizationsDelegates: const [ - AppLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: const [Locale('de')], + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, locale: const Locale('de'), - - // --- Theme-Logik --- - // Falls das OS Farben liefert, nutzen wir diese, sonst ein Standard-Blau theme: ThemeData( colorScheme: lightDynamic ?? ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, @@ -42,9 +39,8 @@ class LasertagApp extends StatelessWidget { ), useMaterial3: true, ), - themeMode: ThemeMode.system, // Folgt macOS/Android Hell/Dunkel Modus - - home: DeviceSelectionScreen(), + themeMode: ThemeMode.system, + home: const DeviceSelectionScreen(), ); }, ); diff --git a/software/app/lib/ui/screens/device_selection_screen.dart b/software/app/lib/ui/screens/device_selection_screen.dart index 60bfa75..f57a221 100644 --- a/software/app/lib/ui/screens/device_selection_screen.dart +++ b/software/app/lib/ui/screens/device_selection_screen.dart @@ -1,28 +1,39 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import '../../models/device_model.dart'; import '../../providers/device_provider.dart'; import '../../constants.dart'; import 'package:lasertag_app/l10n/app_localizations.dart'; -class DeviceSelectionScreen extends StatelessWidget { +class DeviceSelectionScreen extends StatefulWidget { const DeviceSelectionScreen({super.key}); + @override + State createState() => _DeviceSelectionScreenState(); +} + +class _DeviceSelectionScreenState extends State { + @override + void initState() { + super.initState(); + // Scan beim Starten genau einmal triggern + // "listen: false" ist wichtig in initState + Provider.of(context, listen: false).startScan(); + } + @override Widget build(BuildContext context) { - final provider = DeviceProvider(); // Später via "Provider"-Paket + // Hier "lauscht" der Screen jetzt auf Änderungen im Provider + final provider = context.watch(); final l10n = AppLocalizations.of(context)!; - provider.startScan(); // Scan starten beim Laden des Bildschirms - return Scaffold( appBar: AppBar(title: Text(l10n.appTitle)), body: CustomScrollView( slivers: [ - // SEKTION 1: SPIEL-LEITER _buildHeader(context, l10n.listTypeLeader), - _buildDeviceList(context, provider.leaders , isLeader: true), + _buildDeviceList(context, provider.leaders, isLeader: true), - // SEKTION 2: AUSRÜSTUNG (Waffen, Westen, etc.) _buildHeader(context, l10n.listTypeEquipment), _buildDeviceList(context, provider.peripherals, isLeader: false), ], @@ -64,7 +75,7 @@ class DeviceSelectionScreen extends StatelessWidget { device.name, style: const TextStyle(fontWeight: FontWeight.bold), ), - subtitle: Text("ID: ${device.id}"), + subtitle: Text("BTLE-ID: ${device.id}"), trailing: const Icon(Icons.chevron_right), onTap: () { debugPrint("${device.name} ausgewählt für Konfiguration"); diff --git a/software/app/pubspec.lock b/software/app/pubspec.lock index c074955..3c0e107 100644 --- a/software/app/pubspec.lock +++ b/software/app/pubspec.lock @@ -325,6 +325,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -349,6 +357,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.3" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" rxdart: dependency: transitive description: diff --git a/software/app/pubspec.yaml b/software/app/pubspec.yaml index 4a2ef37..9fcacce 100644 --- a/software/app/pubspec.yaml +++ b/software/app/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: flutter_localizations: sdk: flutter intl: ^0.20.2 + provider: ^6.1.5+1 dev_dependencies: flutter_test: