Limit status errors to related control popups
This commit is contained in:
1 parent
7a9fd5c864
commit
5250eeca7b
3 files changed
+79
-12
No files matched your search
@@ -165,7 +165,7 @@ struct FereseShell {
|
||||
status: status::Snapshot,
|
||||
recorder: recording::Recorder,
|
||||
calendar_offset: i32,
|
||||
status_error: Option<String>,
|
||||
status_error: Option<status::ActionError>,
|
||||
theme_error: Option<String>,
|
||||
menu: Option<status_ui::OpenMenu>,
|
||||
system_modal: Option<system_modal::SystemModal>,
|
||||
|
||||
@@ -84,11 +84,17 @@ impl Action {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ActionError {
|
||||
pub action: Action,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Update {
|
||||
pub snapshot: Snapshot,
|
||||
pub generation: u64,
|
||||
pub error: Option<String>,
|
||||
pub error: Option<ActionError>,
|
||||
}
|
||||
|
||||
pub struct Service {
|
||||
@@ -123,7 +129,7 @@ impl Updates {
|
||||
}
|
||||
}
|
||||
|
||||
type PollState = (Mutex<(u64, bool, Option<String>, bool)>, Condvar);
|
||||
type PollState = (Mutex<(u64, bool, Option<ActionError>, bool)>, Condvar);
|
||||
|
||||
fn wait_for_poll(shared: &PollState) -> Option<u64> {
|
||||
let state = shared
|
||||
@@ -141,7 +147,7 @@ impl Service {
|
||||
let (updates, rx) = tokio::sync::watch::channel(None);
|
||||
// Polling and writes have separate workers: a missing D-Bus service must
|
||||
// never hold up volume/brightness changes. Publish only coherent polls.
|
||||
let shared = Arc::new((Mutex::new((0u64, false, None::<String>, false)), Condvar::new()));
|
||||
let shared = Arc::new((Mutex::new((0u64, false, None::<ActionError>, false)), Condvar::new()));
|
||||
let polling = shared.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
@@ -190,7 +196,9 @@ impl Service {
|
||||
state.1 = true;
|
||||
}
|
||||
let settings = settings.lock().unwrap().clone();
|
||||
let error = execute(&action, settings.as_deref()).err();
|
||||
let error = execute(&action, settings.as_deref())
|
||||
.err()
|
||||
.map(|message| ActionError { action, message });
|
||||
let mut state = shared.0.lock().unwrap();
|
||||
state.1 = false;
|
||||
state.2 = error;
|
||||
@@ -210,11 +218,13 @@ impl Service {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&mut self, action: Action) -> Result<(), String> {
|
||||
pub fn send(&mut self, action: Action) -> Result<(), ActionError> {
|
||||
let generation = self.generation + 1;
|
||||
self.tx
|
||||
.try_send((generation, action))
|
||||
.map_err(|_| "Controls are busy; please try again".to_owned())?;
|
||||
let error_action = action.clone();
|
||||
self.tx.try_send((generation, action)).map_err(|_| ActionError {
|
||||
action: error_action,
|
||||
message: "Controls are busy; please try again".to_owned(),
|
||||
})?;
|
||||
self.generation = generation;
|
||||
|
||||
Ok(())
|
||||
@@ -745,7 +755,10 @@ mod tests {
|
||||
..Snapshot::default()
|
||||
},
|
||||
generation,
|
||||
error: Some("service unavailable".into()),
|
||||
error: Some(ActionError {
|
||||
action: Action::Bluetooth(true),
|
||||
message: "service unavailable".into(),
|
||||
}),
|
||||
})
|
||||
};
|
||||
let (sender, receiver) = tokio::sync::watch::channel(None);
|
||||
@@ -763,7 +776,9 @@ mod tests {
|
||||
};
|
||||
assert_eq!(update.generation, 2);
|
||||
assert_eq!(update.snapshot.brightness, Some(42));
|
||||
assert_eq!(update.error.as_deref(), Some("service unavailable"));
|
||||
let error = update.error.as_ref().unwrap();
|
||||
assert_eq!(error.message, "service unavailable");
|
||||
assert!(matches!(error.action, Action::Bluetooth(true)));
|
||||
assert!(stream.as_mut().poll_next(&mut context).is_pending());
|
||||
let before = wakes.0.load(Ordering::Relaxed);
|
||||
thread::spawn(move || {
|
||||
|
||||
@@ -24,6 +24,19 @@ pub enum Menu {
|
||||
}
|
||||
|
||||
impl Menu {
|
||||
fn action_error(self, error: &status::ActionError) -> Option<&str> {
|
||||
let relevant = self == Self::System
|
||||
|| matches!(
|
||||
(self, &error.action),
|
||||
(Self::Network, Action::Wifi(_))
|
||||
| (Self::Bluetooth, Action::Bluetooth(_))
|
||||
| (Self::Audio, Action::Volume(_) | Action::Mute(_))
|
||||
| (Self::Battery, Action::Brightness(_) | Action::PowerProfile(_))
|
||||
| (Self::Notifications, Action::Dnd(_) | Action::Notifications)
|
||||
);
|
||||
relevant.then_some(error.message.as_str())
|
||||
}
|
||||
|
||||
fn width(self) -> f32 {
|
||||
match self {
|
||||
Self::System => 360.0,
|
||||
@@ -818,7 +831,11 @@ impl FereseShell {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(error) = &self.status_error {
|
||||
if let Some(error) = self
|
||||
.status_error
|
||||
.as_ref()
|
||||
.and_then(|error| menu.kind.action_error(error))
|
||||
{
|
||||
rows = rows.push(text(error).size(12).class(theme::Text::Color(Color {
|
||||
a: p,
|
||||
..Color::from_rgb8(230, 172, 90)
|
||||
@@ -1271,6 +1288,41 @@ fn status_icon(kind: Menu, s: &Snapshot) -> (&'static [u8], bool) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn failed_controls_only_show_errors_in_related_popups() {
|
||||
for (action, relevant) in [
|
||||
(Action::Bluetooth(true), Menu::Bluetooth),
|
||||
(Action::Wifi(true), Menu::Network),
|
||||
(Action::Volume(50), Menu::Audio),
|
||||
(Action::Mute(true), Menu::Audio),
|
||||
(Action::Brightness(50), Menu::Battery),
|
||||
(Action::PowerProfile("balanced"), Menu::Battery),
|
||||
(Action::Dnd(true), Menu::Notifications),
|
||||
] {
|
||||
let error = status::ActionError {
|
||||
action,
|
||||
message: "control failed".into(),
|
||||
};
|
||||
for menu in [
|
||||
Menu::Network,
|
||||
Menu::Bluetooth,
|
||||
Menu::Audio,
|
||||
Menu::Battery,
|
||||
Menu::Calendar,
|
||||
Menu::Recording,
|
||||
Menu::Notifications,
|
||||
Menu::System,
|
||||
] {
|
||||
assert_eq!(
|
||||
menu.action_error(&error),
|
||||
(menu == relevant || menu == Menu::System).then_some("control failed"),
|
||||
"{menu:?} showed the wrong control error: {:?}",
|
||||
error.action
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_captions_fit_one_short_line() {
|
||||
assert_eq!(super::connection_caption("88%"), "88%");
|
||||
|
||||
Reference in new issue
Block a user