Advencing bluetooth mist :)
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 17s
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 17s
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user