This commit is contained in:
@@ -3,8 +3,9 @@
|
||||
"appTitle": "Lasertag Mission Control",
|
||||
"selectLeader": "Leader auswählen",
|
||||
"searching": "Suche nach Knoten...",
|
||||
"typeLeader": "Spiel-Leiter",
|
||||
"listTypeLeader": "Gameleadergeräte",
|
||||
"typeWeapon": "Waffe",
|
||||
"typeVest": "Weste",
|
||||
"typeBeacon": "Beacon"
|
||||
"typeBeacon": "Beacon",
|
||||
"listTypeEquipment": "Ausrüstungsgeräte"
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ abstract class AppLocalizations {
|
||||
/// **'Suche nach Knoten...'**
|
||||
String get searching;
|
||||
|
||||
/// No description provided for @typeLeader.
|
||||
/// No description provided for @listTypeLeader.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Spiel-Leiter'**
|
||||
String get typeLeader;
|
||||
/// **'Gameleadergeräte'**
|
||||
String get listTypeLeader;
|
||||
|
||||
/// No description provided for @typeWeapon.
|
||||
///
|
||||
@@ -135,6 +135,12 @@ abstract class AppLocalizations {
|
||||
/// In de, this message translates to:
|
||||
/// **'Beacon'**
|
||||
String get typeBeacon;
|
||||
|
||||
/// No description provided for @listTypeEquipment.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Ausrüstungsgeräte'**
|
||||
String get listTypeEquipment;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -18,7 +18,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
String get searching => 'Suche nach Knoten...';
|
||||
|
||||
@override
|
||||
String get typeLeader => 'Spiel-Leiter';
|
||||
String get listTypeLeader => 'Gameleadergeräte';
|
||||
|
||||
@override
|
||||
String get typeWeapon => 'Waffe';
|
||||
@@ -28,4 +28,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get typeBeacon => 'Beacon';
|
||||
|
||||
@override
|
||||
String get listTypeEquipment => 'Ausrüstungsgeräte';
|
||||
}
|
||||
|
||||
@@ -1,17 +1,85 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import '../models/device_model.dart';
|
||||
import '../constants.dart';
|
||||
|
||||
class DeviceProvider extends ChangeNotifier {
|
||||
// Unsere Dummy-Listen
|
||||
List<LasertagDevice> get dummyLeaders => [
|
||||
LasertagDevice(id: "L-01", name: "EdiLeader Alpha", type: LasertagUUIDs.typeLeader),
|
||||
LasertagDevice(id: "L-02", name: "Säntis Funker", type: LasertagUUIDs.typeLeader),
|
||||
];
|
||||
final List<LasertagDevice> _discoveredLeaders = [];
|
||||
final List<LasertagDevice> _discoveredPeripherals = [];
|
||||
StreamSubscription? _scanSubscription;
|
||||
|
||||
List<LasertagDevice> get dummyEquip => [
|
||||
LasertagDevice(id: "W-01", name: "Blaster 1", type: LasertagUUIDs.typeWeapon),
|
||||
LasertagDevice(id: "V-01", name: "Weste Blau", type: LasertagUUIDs.typeVest),
|
||||
LasertagDevice(id: "B-01", name: "Basis Mitte", type: LasertagUUIDs.typeBeacon),
|
||||
];
|
||||
List<LasertagDevice> get leaders => _discoveredLeaders;
|
||||
List<LasertagDevice> get peripherals => _discoveredPeripherals;
|
||||
|
||||
void startScan() async {
|
||||
// Listen leeren für neuen Scan
|
||||
_discoveredLeaders.clear();
|
||||
_discoveredPeripherals.clear();
|
||||
notifyListeners();
|
||||
|
||||
// 1. Bluetooth-Status prüfen
|
||||
await FlutterBluePlus.adapterState.where((s) => s == BluetoothAdapterState.on).first;
|
||||
|
||||
// 2. Scan-Ergebnisse verarbeiten
|
||||
_scanSubscription?.cancel();
|
||||
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
|
||||
for (ScanResult r in results) {
|
||||
final mfgData = r.advertisementData.manufacturerData[65535]; // Unsere ID 0xFFFF
|
||||
|
||||
if (mfgData != null && mfgData.isNotEmpty) {
|
||||
int type = mfgData[0]; // Typ-Byte vom nRF52
|
||||
|
||||
final device = LasertagDevice(
|
||||
id: r.device.remoteId.toString(),
|
||||
name: r.device.platformName.isEmpty ? "Unbekannt" : r.device.platformName,
|
||||
type: type,
|
||||
isConnected: false,
|
||||
);
|
||||
|
||||
_addDeviceToLists(device);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Scan starten (gefiltert nach unserem Service)
|
||||
try {
|
||||
await FlutterBluePlus.startScan(
|
||||
withServices: [Guid(LasertagUUIDs.provService)], //
|
||||
timeout: const Duration(seconds: 15),
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint("Scan-Fehler: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void _addDeviceToLists(LasertagDevice device) {
|
||||
if (device.isLeader) {
|
||||
if (!_discoveredLeaders.any((d) => d.id == device.id)) {
|
||||
_discoveredLeaders.add(device);
|
||||
_sortList(_discoveredLeaders);
|
||||
notifyListeners();
|
||||
}
|
||||
} else {
|
||||
if (!_discoveredPeripherals.any((d) => d.id == device.id)) {
|
||||
_discoveredPeripherals.add(device);
|
||||
_sortList(_discoveredPeripherals);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _sortList(List<LasertagDevice> list) {
|
||||
list.sort((a, b) {
|
||||
int typeComp = a.type.compareTo(b.type);
|
||||
if (typeComp != 0) return typeComp;
|
||||
return a.name.toLowerCase().compareTo(b.name.toLowerCase());
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scanSubscription?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -12,17 +12,19 @@ class DeviceSelectionScreen extends StatelessWidget {
|
||||
final provider = DeviceProvider(); // Später via "Provider"-Paket
|
||||
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.typeLeader),
|
||||
_buildDeviceList(context, provider.dummyLeaders, isLeader: true),
|
||||
_buildHeader(context, l10n.listTypeLeader),
|
||||
_buildDeviceList(context, provider.leaders , isLeader: true),
|
||||
|
||||
// SEKTION 2: AUSRÜSTUNG (Waffen, Westen, etc.)
|
||||
_buildHeader(context, "Meine Ausrüstung"), // Später in ARB übersetzen
|
||||
_buildDeviceList(context, provider.dummyEquip, isLeader: false),
|
||||
_buildHeader(context, l10n.listTypeEquipment),
|
||||
_buildDeviceList(context, provider.peripherals, isLeader: false),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -45,26 +47,45 @@ class DeviceSelectionScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDeviceList(BuildContext context, List<LasertagDevice> devices, {required bool isLeader}) {
|
||||
Widget _buildDeviceList(
|
||||
BuildContext context,
|
||||
List<LasertagDevice> devices, {
|
||||
required bool isLeader,
|
||||
}) {
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final device = devices[index];
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
isLeader ? Icons.hub : Icons.radar,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
title: Text(device.name, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
subtitle: Text("ID: ${device.id}"),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
debugPrint("${device.name} ausgewählt für Konfiguration");
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: devices.length,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
final device = devices[index];
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
_getIconForType(device.type), // Dynamisches Icon
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
title: Text(
|
||||
device.name,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text("ID: ${device.id}"),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
debugPrint("${device.name} ausgewählt für Konfiguration");
|
||||
},
|
||||
);
|
||||
}, childCount: devices.length),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
IconData _getIconForType(int type) {
|
||||
switch (type) {
|
||||
case LasertagUUIDs.typeLeader:
|
||||
return Icons.hub;
|
||||
case LasertagUUIDs.typeWeapon:
|
||||
return Icons.flash_on; // Blitz für Waffe
|
||||
case LasertagUUIDs.typeVest:
|
||||
return Icons.accessibility_new; // Person für Weste
|
||||
case LasertagUUIDs.typeBeacon:
|
||||
return Icons.flag; // Flagge für Basis
|
||||
default:
|
||||
return Icons.device_unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user