Advencing bluetooth mist :)
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 17s

This commit is contained in:
2026-01-12 14:29:09 +01:00
parent 6b1bbca992
commit c13b6d73c9
6 changed files with 187 additions and 121 deletions

View File

@@ -13,12 +13,51 @@ class DeviceProvider extends ChangeNotifier {
List<LasertagDevice> get leaders => _discoveredLeaders;
List<LasertagDevice> get peripherals => _discoveredPeripherals;
Future<String> readDeviceNameFromHardware(LasertagDevice ltDevice) async {
try {
if (!ltDevice.btDevice.isConnected) {
await ltDevice.btDevice.connect(
license: License.free,
timeout: const Duration(seconds: 5),
);
}
List<BluetoothService> services = await ltDevice.btDevice
.discoverServices();
var service = services.firstWhere(
(s) => s.uuid == Guid(LasertagUUIDs.provService),
);
var characteristic = service.characteristics.firstWhere(
(c) => c.uuid == Guid(LasertagUUIDs.provNameChar),
);
// Namen von der Hardware lesen
List<int> value = await characteristic.read();
String hardwareName = utf8.decode(value);
// Lokalen Cache in der App ebenfalls aktualisieren, um Caching zu umgehen
updateDeviceName(ltDevice.id, hardwareName);
return hardwareName;
} catch (e) {
debugPrint("Fehler beim Lesen der Hardware: $e");
rethrow;
}
}
Future<void> updateDeviceNameOnHardware(
LasertagDevice ltDevice,
String newName,
) async {
try {
await ltDevice.btDevice.connect();
await ltDevice.btDevice.connect(
license: License.free,
autoConnect: false,
timeout: const Duration(seconds: 10),
);
await Future.delayed(const Duration(milliseconds: 500));
List<BluetoothService> services = await ltDevice.btDevice
.discoverServices();
@@ -88,6 +127,11 @@ class DeviceProvider extends ChangeNotifier {
_scanSubscription?.cancel();
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
for (ScanResult r in results) {
bool hasService = r.advertisementData.serviceUuids.contains(
Guid(LasertagUUIDs.provService),
);
if (!hasService) continue;
final mfgData =
r.advertisementData.manufacturerData[65535]; // Unsere ID 0xFFFF
@@ -109,12 +153,9 @@ class DeviceProvider extends ChangeNotifier {
}
});
// 3. Scan starten (gefiltert nach unserem Service)
// 3. Bluetooth-Scan starten
try {
await FlutterBluePlus.startScan(
withServices: [Guid(LasertagUUIDs.provService)], //
timeout: const Duration(seconds: 15),
);
await FlutterBluePlus.startScan(timeout: const Duration(seconds: 15));
} catch (e) {
debugPrint("Scan-Fehler: $e");
}

View File

@@ -103,55 +103,4 @@ class _DeviceSelectionScreenState extends State<DeviceSelectionScreen> {
return Icons.device_unknown;
}
}
void _showNameEditDialog(BuildContext context, LasertagDevice device) {
final TextEditingController nameController = TextEditingController(
text: device.name,
);
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Row(
children: [
Icon(
_getIconForType(device.type),
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(width: 10),
const Text("Gerät umbenennen"),
],
),
content: TextField(
controller: nameController,
decoration: const InputDecoration(
labelText: "Anzeigename",
border: OutlineInputBorder(),
),
autofocus: true,
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("Abbrechen"),
),
ElevatedButton(
onPressed: () {
if (nameController.text.trim().isNotEmpty) {
// Provider aktualisieren
context.read<DeviceProvider>().updateDeviceName(
device.id,
nameController.text.trim(),
);
Navigator.pop(context);
}
},
child: const Text("Speichern"),
),
],
);
},
);
}
}

View File

@@ -14,32 +14,70 @@ class RenameDialog extends StatefulWidget {
class _RenameDialogState extends State<RenameDialog> {
late TextEditingController _controller;
bool _isSaving = false;
bool _isReading = true; // Neu: Startet im Lade-Modus
@override
void initState() {
super.initState();
_controller = TextEditingController(text: widget.device.name);
_fetchHardwareName(); // Namen beim Öffnen abfragen
}
Future<void> _fetchHardwareName() async {
try {
String hName = await context
.read<DeviceProvider>()
.readDeviceNameFromHardware(widget.device);
if (mounted) {
setState(() {
_controller.text = hName;
_isReading = false;
});
}
} catch (e) {
if (mounted) setState(() => _isReading = false);
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text("${widget.device.name} umbenennen"),
content: TextField(
controller: _controller,
decoration: const InputDecoration(labelText: "Neuer Name"),
enabled: !_isSaving,
title: Text("${widget.device.name} umbenennen"), // Titel bleibt gleich
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_isReading)
const Padding(
padding: EdgeInsets.only(bottom: 10),
child:
LinearProgressIndicator(), // Zeigt, dass wir die Hardware abfragen
),
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: _isReading ? "Lese Hardware..." : "Neuer Name",
border: const OutlineInputBorder(),
),
enabled: !_isSaving && !_isReading,
),
],
),
actions: [
TextButton(
onPressed: _isSaving ? null : () => Navigator.pop(context),
onPressed: (_isSaving || _isReading)
? null
: () => Navigator.pop(context),
child: const Text("Abbrechen"),
),
ElevatedButton(
onPressed: _isSaving ? null : _save,
child: _isSaving
? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Text("Speichern"),
onPressed: (_isSaving || _isReading) ? null : _save,
child: _isSaving
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text("Speichern"),
),
],
);
@@ -49,8 +87,8 @@ class _RenameDialogState extends State<RenameDialog> {
setState(() => _isSaving = true);
try {
await context.read<DeviceProvider>().updateDeviceNameOnHardware(
widget.device,
_controller.text.trim()
widget.device,
_controller.text.trim(),
);
if (mounted) Navigator.pop(context);
} catch (e) {
@@ -63,4 +101,4 @@ class _RenameDialogState extends State<RenameDialog> {
if (mounted) setState(() => _isSaving = false);
}
}
}
}