feat(bluetooth): add ability to rename Bluetooth devices (#2160)

This commit is contained in:
Kheven Colino 2026-09-01 12:06:07 -03:00 • committed by GitHub
parent 4b4b688d5a
commit 9c1a7fbc82
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 115 additions and 4 deletions

View file

@ -37,6 +37,10 @@ enum Dialog {
device: String,
pincode: String,
},
RenameDevice {
path: OwnedObjectPath,
name: String,
},
}
#[derive(Default)]
@ -353,6 +357,29 @@ impl page::Page<crate::pages::Message> for Page {
Some(dialog)
}
Dialog::RenameDevice { name, .. } => {
let is_valid = is_valid_bluetooth_alias(name);
let input = widget::text_input("", name)
.on_input(|value| Message::RenameDeviceInput(value))
.on_submit(|_| Message::RenameDeviceConfirm);
let rename_button =
widget::button::suggested(fl!("rename")).on_press_maybe(is_valid.then_some(Message::RenameDeviceConfirm));
let cancel_button =
widget::button::standard(fl!("cancel")).on_press(Message::RenameDeviceCancel);
let dialog = widget::dialog()
.title(fl!("bluetooth-rename-device"))
.control(input)
.primary_action(rename_button)
.secondary_action(cancel_button)
.apply(Element::from)
.map(Into::into);
Some(dialog)
}
}
}
}
@ -369,6 +396,10 @@ pub enum Message {
PinConfirm,
PopupDevice(Option<OwnedObjectPath>),
PopupSetting(bool),
RenameDevice(OwnedObjectPath),
RenameDeviceInput(String),
RenameDeviceConfirm,
RenameDeviceCancel,
SelectAdapter(Option<OwnedObjectPath>),
ServiceActivate,
ServiceEnable,
@ -629,6 +660,10 @@ impl Page {
_ => (),
}
},
Event::DeviceRenameFailed(path) => {
tracing::warn!("Failed to rename device {path}");
}
},
@ -836,6 +871,38 @@ impl Page {
}
}
Message::RenameDevice(path) => {
self.model.popup_device = None;
let name = self
.model
.devices
.get(&path)
.map_or_else(String::new, |d| d.alias_or_addr().to_owned());
self.dialog = Some(Dialog::RenameDevice { path, name });
}
Message::RenameDeviceInput(new_name) => {
if let Some(Dialog::RenameDevice { name, .. }) = &mut self.dialog {
*name = new_name;
}
}
Message::RenameDeviceCancel => {
if matches!(self.dialog, Some(Dialog::RenameDevice { .. })) {
self.dialog = None;
}
}
Message::RenameDeviceConfirm => {
if let Some(Dialog::RenameDevice { path, name }) = self.dialog.take() {
if let Some(connection) = self.connection.clone() {
return cosmic::task::future(rename_device(connection, path, name.trim().into()));
} else {
tracing::warn!("No DBus connection ready");
}
}
}
Message::ServiceActivate => {
let activate_future = self.service_manager.activate();
return cosmic::task::future(async move {
@ -934,6 +1001,11 @@ fn status() -> Section<crate::pages::Message> {
})
}
fn is_valid_bluetooth_alias(name: &str) -> bool {
let trimmed = name.trim();
!trimmed.is_empty() && trimmed.len() <= 248
}
fn popup_button(message: Option<Message>, text: &str) -> Element<'_, Message> {
let spacing = theme::spacing();
widget::text::body(text)
@ -954,6 +1026,7 @@ fn connected_devices() -> Section<crate::pages::Message> {
device_connect = fl!("bluetooth", "connect");
device_disconnect = fl!("bluetooth", "disconnect");
device_forget = fl!("bluetooth", "forget");
device_rename = fl!("rename");
});
Section::default()
@ -991,13 +1064,17 @@ fn connected_devices() -> Section<crate::pages::Message> {
.position(widget::popover::Position::Bottom)
.on_close(Message::PopupDevice(None))
.popup(
widget::column::with_capacity(2)
widget::column::with_capacity(3)
.push_maybe(device.is_connected().then(|| {
popup_button(
Some(Message::DisconnectDevice(path.clone())),
&descriptions[device_disconnect],
)
}))
.push(popup_button(
Some(Message::RenameDevice(path.clone())),
&descriptions[device_rename],
))
.push_maybe(device.paired.then(|| {
popup_button(
Some(Message::ForgetDevice(path.clone())),