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:
@@ -33,7 +33,7 @@ int main(void)
|
||||
if (rc) {
|
||||
LOG_ERR("Thread initialization failed (err %d)", rc);
|
||||
} else {
|
||||
LOG_INF("Leader Application successfully started with Thread Mesh.");
|
||||
LOG_INF("Vest Application successfully started with Thread Mesh.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ LOG_MODULE_REGISTER(ble_mgmt, CONFIG_BLE_MGMT_LOG_LEVEL);
|
||||
|
||||
/* --- Global Variables --- */
|
||||
static uint8_t device_role = 0; // Store device type for provisioning
|
||||
static uint8_t adv_enabled = 0; // Track advertising state
|
||||
|
||||
/* --- GATT Callbacks --- */
|
||||
|
||||
@@ -104,6 +105,12 @@ static ssize_t write_lasertag_val(struct bt_conn *conn, const struct bt_gatt_att
|
||||
if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_NAME_CHAR) == 0)
|
||||
{
|
||||
rc = lasertag_set_device_name(buf, len);
|
||||
if (rc == 0 && adv_enabled) {
|
||||
LOG_INF("Stopping advertising to update device name");
|
||||
ble_mgmt_adv_stop();
|
||||
LOG_INF("Restarting advertising with new device name");
|
||||
ble_mgmt_adv_start();
|
||||
}
|
||||
}
|
||||
else if (bt_uuid_cmp(attr->uuid, BT_UUID_LT_PROV_PANID_CHAR) == 0)
|
||||
{
|
||||
@@ -248,6 +255,7 @@ int ble_mgmt_adv_start(void)
|
||||
if (!err)
|
||||
{
|
||||
LOG_INF("Advertising started as: %s, type: %d", name, device_role);
|
||||
adv_enabled = 1;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -258,6 +266,7 @@ int ble_mgmt_adv_stop(void)
|
||||
if (!err)
|
||||
{
|
||||
LOG_INF("Advertising stopped");
|
||||
adv_enabled = 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -19,40 +19,55 @@ static uint8_t thread_channel = 15;
|
||||
static uint8_t thread_ext_pan_id[8] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe};
|
||||
static uint8_t thread_network_key[16] = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
|
||||
};
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
|
||||
|
||||
/* --- Settings Handler --- */
|
||||
|
||||
static int lasertag_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
const char *next;
|
||||
if (settings_name_steq(name, "name", &next) && !next) {
|
||||
if (len > sizeof(device_name) - 1) return -EINVAL;
|
||||
if (settings_name_steq(name, "name", &next) && !next)
|
||||
{
|
||||
if (len > sizeof(device_name) - 1)
|
||||
return -EINVAL;
|
||||
ssize_t rc = read_cb(cb_arg, device_name, len);
|
||||
if (rc >= 0) { device_name[rc] = '\0'; return 0; }
|
||||
if (rc >= 0)
|
||||
{
|
||||
device_name[rc] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (settings_name_steq(name, "pan_id", &next) && !next) {
|
||||
if (settings_name_steq(name, "pan_id", &next) && !next)
|
||||
{
|
||||
return read_cb(cb_arg, &thread_pan_id, sizeof(thread_pan_id)) >= 0 ? 0 : -EIO;
|
||||
}
|
||||
if (settings_name_steq(name, "net_name", &next) && !next) {
|
||||
if (len > sizeof(thread_network_name) - 1) return -EINVAL;
|
||||
if (settings_name_steq(name, "net_name", &next) && !next)
|
||||
{
|
||||
if (len > sizeof(thread_network_name) - 1)
|
||||
return -EINVAL;
|
||||
ssize_t rc = read_cb(cb_arg, thread_network_name, len);
|
||||
if (rc >= 0) { thread_network_name[rc] = '\0'; return 0; }
|
||||
if (rc >= 0)
|
||||
{
|
||||
thread_network_name[rc] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (settings_name_steq(name, "channel", &next) && !next) {
|
||||
if (settings_name_steq(name, "channel", &next) && !next)
|
||||
{
|
||||
return read_cb(cb_arg, &thread_channel, sizeof(thread_channel)) >= 0 ? 0 : -EIO;
|
||||
}
|
||||
if (settings_name_steq(name, "ext_pan_id", &next) && !next) {
|
||||
if (settings_name_steq(name, "ext_pan_id", &next) && !next)
|
||||
{
|
||||
return read_cb(cb_arg, thread_ext_pan_id, sizeof(thread_ext_pan_id)) >= 0 ? 0 : -EIO;
|
||||
}
|
||||
if (settings_name_steq(name, "net_key", &next) && !next) {
|
||||
if (settings_name_steq(name, "net_key", &next) && !next)
|
||||
{
|
||||
return read_cb(cb_arg, thread_network_key, sizeof(thread_network_key)) >= 0 ? 0 : -EIO;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
struct settings_handler lasertag_conf = { .name = "lasertag", .h_set = lasertag_settings_set };
|
||||
struct settings_handler lasertag_conf = {.name = "lasertag", .h_set = lasertag_settings_set};
|
||||
|
||||
void lasertag_utils_init(void)
|
||||
{
|
||||
@@ -71,39 +86,47 @@ void lasertag_utils_init(void)
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
const char* lasertag_get_device_name(void) { return device_name; }
|
||||
const char *lasertag_get_device_name(void) { return device_name; }
|
||||
uint16_t lasertag_get_thread_pan_id(void) { return thread_pan_id; }
|
||||
const char* lasertag_get_thread_network_name(void) { return thread_network_name; }
|
||||
const char *lasertag_get_thread_network_name(void) { return thread_network_name; }
|
||||
uint8_t lasertag_get_thread_channel(void) { return thread_channel; }
|
||||
const uint8_t* lasertag_get_thread_ext_pan_id(void) { return thread_ext_pan_id; }
|
||||
const uint8_t* lasertag_get_thread_network_key(void) { return thread_network_key; }
|
||||
const uint8_t *lasertag_get_thread_ext_pan_id(void) { return thread_ext_pan_id; }
|
||||
const uint8_t *lasertag_get_thread_network_key(void) { return thread_network_key; }
|
||||
|
||||
/* Setters */
|
||||
int lasertag_set_device_name(const char *name, size_t len) {
|
||||
if (len >= sizeof(device_name)) len = sizeof(device_name) - 1;
|
||||
int lasertag_set_device_name(const char *name, size_t len)
|
||||
{
|
||||
if (len >= sizeof(device_name))
|
||||
len = sizeof(device_name) - 1;
|
||||
memcpy(device_name, name, len);
|
||||
device_name[len] = '\0';
|
||||
return settings_save_one("lasertag/name", device_name, len);
|
||||
}
|
||||
int lasertag_set_thread_pan_id(uint16_t pan_id) {
|
||||
int lasertag_set_thread_pan_id(uint16_t pan_id)
|
||||
{
|
||||
thread_pan_id = pan_id;
|
||||
return settings_save_one("lasertag/pan_id", &thread_pan_id, sizeof(thread_pan_id));
|
||||
}
|
||||
int lasertag_set_thread_network_name(const char *name, size_t len) {
|
||||
if (len >= sizeof(thread_network_name)) len = sizeof(thread_network_name) - 1;
|
||||
int lasertag_set_thread_network_name(const char *name, size_t len)
|
||||
{
|
||||
if (len >= sizeof(thread_network_name))
|
||||
len = sizeof(thread_network_name) - 1;
|
||||
memcpy(thread_network_name, name, len);
|
||||
thread_network_name[len] = '\0';
|
||||
return settings_save_one("lasertag/net_name", thread_network_name, len);
|
||||
}
|
||||
int lasertag_set_thread_channel(uint8_t channel) {
|
||||
int lasertag_set_thread_channel(uint8_t channel)
|
||||
{
|
||||
thread_channel = channel;
|
||||
return settings_save_one("lasertag/channel", &thread_channel, sizeof(thread_channel));
|
||||
}
|
||||
int lasertag_set_thread_ext_pan_id(const uint8_t *ext_id) {
|
||||
int lasertag_set_thread_ext_pan_id(const uint8_t *ext_id)
|
||||
{
|
||||
memcpy(thread_ext_pan_id, ext_id, 8);
|
||||
return settings_save_one("lasertag/ext_pan_id", thread_ext_pan_id, 8);
|
||||
}
|
||||
int lasertag_set_thread_network_key(const uint8_t *key) {
|
||||
int lasertag_set_thread_network_key(const uint8_t *key)
|
||||
{
|
||||
memcpy(thread_network_key, key, 16);
|
||||
return settings_save_one("lasertag/net_key", thread_network_key, 16);
|
||||
}
|
||||
@@ -112,71 +135,77 @@ int lasertag_set_thread_network_key(const uint8_t *key) {
|
||||
|
||||
#if CONFIG_LASERTAG_SHELL
|
||||
|
||||
static int lasertag_hex2bin(const char *hex, uint8_t *bin, size_t bin_len) {
|
||||
for (size_t i = 0; i < bin_len; i++) {
|
||||
char buf[3] = { hex[i*2], hex[i*2+1], '\0' };
|
||||
static int lasertag_hex2bin(const char *hex, uint8_t *bin, size_t bin_len)
|
||||
{
|
||||
for (size_t i = 0; i < bin_len; i++)
|
||||
{
|
||||
char buf[3] = {hex[i * 2], hex[i * 2 + 1], '\0'};
|
||||
bin[i] = (uint8_t)strtoul(buf, NULL, 16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_reboot(const struct shell *sh, size_t argc, char **argv) {
|
||||
static int cmd_reboot(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
shell_print(sh, "Rebooting...");
|
||||
sys_reboot(SYS_REBOOT_COLD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_name_set(const struct shell *sh, size_t argc, char **argv) {
|
||||
static int cmd_name_set(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
lasertag_set_device_name(argv[1], strlen(argv[1]));
|
||||
shell_print(sh, "Name gespeichert.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_thread_ping(const struct shell *sh, size_t argc, char **argv) {
|
||||
static int cmd_thread_ping(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
char msg[64];
|
||||
snprintf(msg, sizeof(msg), "Ping von %s", device_name);
|
||||
shell_print(sh, "Sende Multicast-Ping an ff03::1...");
|
||||
int rc = thread_mgmt_send_udp("ff03::1", (uint8_t*)msg, strlen(msg));
|
||||
if (rc) shell_error(sh, "Ping fehlgeschlagen (%d)", rc);
|
||||
int rc = thread_mgmt_send_udp("ff03::1", (uint8_t *)msg, strlen(msg));
|
||||
if (rc)
|
||||
shell_error(sh, "Ping fehlgeschlagen (%d)", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subcommands definitions omitted for brevity, but they should include 'ping' */
|
||||
static int cmd_thread_set_panid(const struct shell *sh, size_t argc, char **argv) {
|
||||
static int cmd_thread_set_panid(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
uint16_t pan = (uint16_t)strtoul(argv[1], NULL, 0);
|
||||
lasertag_set_thread_pan_id(pan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_thread_set_chan(const struct shell *sh, size_t argc, char **argv) {
|
||||
static int cmd_thread_set_chan(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
uint8_t chan = (uint8_t)strtoul(argv[1], NULL, 10);
|
||||
lasertag_set_thread_channel(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_thread,
|
||||
SHELL_CMD_ARG(panid, NULL, "Set PAN ID", cmd_thread_set_panid, 2, 0),
|
||||
SHELL_CMD_ARG(chan, NULL, "Set channel", cmd_thread_set_chan, 2, 0),
|
||||
SHELL_CMD(ping, NULL, "Send multicast ping", cmd_thread_ping),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
SHELL_CMD_ARG(panid, NULL, "Set PAN ID", cmd_thread_set_panid, 2, 0),
|
||||
SHELL_CMD_ARG(chan, NULL, "Set channel", cmd_thread_set_chan, 2, 0),
|
||||
SHELL_CMD(ping, NULL, "Send multicast ping", cmd_thread_ping),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
static int cmd_ble_start(const struct shell *sh, size_t argc, char **argv) {
|
||||
static int cmd_ble_start(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
return ble_mgmt_adv_start();
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_ble,
|
||||
SHELL_CMD(start, NULL, "Start BLE", cmd_ble_start),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
SHELL_CMD(start, NULL, "Start BLE", cmd_ble_start),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_lasertag,
|
||||
SHELL_CMD_ARG(name, NULL, "Set name", cmd_name_set, 2, 0),
|
||||
SHELL_CMD(thread, &sub_thread, "Thread configuration", NULL),
|
||||
SHELL_CMD(ble, &sub_ble, "BLE Management", NULL),
|
||||
SHELL_CMD(reboot, NULL, "Reboot", cmd_reboot),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
SHELL_CMD_ARG(name, NULL, "Set name", cmd_name_set, 2, 0),
|
||||
SHELL_CMD(thread, &sub_thread, "Thread configuration", NULL),
|
||||
SHELL_CMD(ble, &sub_ble, "BLE Management", NULL),
|
||||
SHELL_CMD(reboot, NULL, "Reboot", cmd_reboot),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_CMD_REGISTER(lasertag, &sub_lasertag, "Lasertag Befehle", NULL);
|
||||
|
||||
|
||||
@@ -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