Merge remote-tracking branch 'origin/master'

This commit is contained in:
Hosted Weblate 2026-09-01 19:21:30 +02:00
commit 88902ec298
No known key found for this signature in database
GPG key ID: A3FAAA06E6569B4C
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())),

View file

@ -233,6 +233,7 @@ online-accounts = Online accounts
activate = Activate
confirm = Confirm
enable = Enable
rename = Rename
bluetooth = Bluetooth
.status = This system is visible as { $aliases } while Bluetooth settings are open.
@ -260,6 +261,8 @@ bluetooth-display-passkey = Bluetooth Pairing
bluetooth-display-pin = Bluetooth Pairing
.description = Please type the following PIN on { $device }, then press Enter
bluetooth-rename-device = Rename Device
bluetooth-available = Nearby devices
bluetooth-adapters = Bluetooth adapters

View file

@ -32,7 +32,7 @@ fn device_type_to_icon(device_type: &str) -> &'static str {
#[derive(Default, Debug, Clone)]
pub struct Device {
alias: Option<String>,
pub alias: Option<String>,
pub address: String,
pub adapter: OwnedObjectPath,
pub enabled: Active,
@ -46,7 +46,7 @@ impl Device {
let (address, adapter, alias) = join!(
proxy.device.address(),
proxy.device.adapter(),
proxy.device.name()
proxy.device.alias()
);
let address = address?;
if address.is_empty() {
@ -56,7 +56,10 @@ impl Device {
if adapter.is_empty() {
return Err(zbus::Error::Failure("Device has no adapter".to_owned()));
}
let alias = alias.ok();
let alias = match alias {
Ok(alias) if !alias.is_empty() && alias != address.replace(':', "-") => Some(alias),
_ => proxy.device.name().await.ok(),
};
let device_type: String = proxy.icon().await;
let paired = proxy.device.paired().await.unwrap_or(false);
let enabled = if proxy.device.connected().await.unwrap_or(false) {
@ -309,6 +312,33 @@ pub async fn forget_device(connection: zbus::Connection, device_path: OwnedObjec
}
}
pub async fn rename_device(
connection: zbus::Connection,
device_path: OwnedObjectPath,
name: String,
) -> Event {
let proxy = match bluez_zbus::get_device(&connection, device_path.clone()).await {
Err(why) => {
tracing::error!("Unable to get the device: {why}");
return Event::DeviceFailed(device_path);
}
Ok(proxy) => proxy,
};
for attempt in 1..5 {
let result = proxy.device.set_alias(&name).await;
if let Err(why) = result {
tracing::warn!("Unable to rename device: {why}");
tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;
} else {
return Event::Ok;
}
}
Event::DeviceRenameFailed(device_path)
}
pub async fn get_devices(connection: zbus::Connection, adapter_path: OwnedObjectPath) -> Event {
// TODO error handling
let result: zbus::Result<HashMap<OwnedObjectPath, Device>> = async {

View file

@ -21,6 +21,7 @@ pub enum Event {
DBusError(zbus::Error),
DBusServiceUnknown,
DeviceFailed(OwnedObjectPath),
DeviceRenameFailed(OwnedObjectPath),
Ok,
NameHasNoOwner,
RemovedAdapter(OwnedObjectPath),