feat: add inverted-colors to a11y applet
This commit is contained in:
parent
ca9238c9a7
commit
9ca6b4ed8f
4 changed files with 100 additions and 14 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
screen-reader = Screen reader
|
screen-reader = Screen reader
|
||||||
magnifier = Magnifier
|
magnifier = Magnifier
|
||||||
|
invert-colors = Invert colors
|
||||||
settings = Accessibility settings...
|
settings = Accessibility settings...
|
||||||
|
|
@ -21,17 +21,17 @@ use cosmic::{
|
||||||
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||||
window, Length, Subscription,
|
window, Length, Subscription,
|
||||||
},
|
},
|
||||||
iced_runtime::core::layout::Limits,
|
|
||||||
iced_widget::column,
|
|
||||||
surface, theme,
|
surface, theme,
|
||||||
widget::{divider, text},
|
widget::{divider, text, Column},
|
||||||
Element, Task,
|
Element, Task,
|
||||||
};
|
};
|
||||||
|
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::Filter;
|
||||||
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
static READER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
static READER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
static MAGNIFIER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
static MAGNIFIER_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
|
static INVERT_COLORS_TOGGLE: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
|
|
||||||
pub fn run() -> cosmic::iced::Result {
|
pub fn run() -> cosmic::iced::Result {
|
||||||
cosmic::applet::run::<CosmicA11yApplet>(())
|
cosmic::applet::run::<CosmicA11yApplet>(())
|
||||||
|
|
@ -42,9 +42,11 @@ struct CosmicA11yApplet {
|
||||||
core: cosmic::app::Core,
|
core: cosmic::app::Core,
|
||||||
reader_enabled: bool,
|
reader_enabled: bool,
|
||||||
magnifier_enabled: bool,
|
magnifier_enabled: bool,
|
||||||
|
inverted_colors_enabled: bool,
|
||||||
popup: Option<window::Id>,
|
popup: Option<window::Id>,
|
||||||
dbus_sender: Option<UnboundedSender<DBusRequest>>,
|
dbus_sender: Option<UnboundedSender<DBusRequest>>,
|
||||||
wayland_sender: Option<channel::SyncSender<AccessibilityRequest>>,
|
wayland_sender: Option<channel::SyncSender<AccessibilityRequest>>,
|
||||||
|
wayland_protocol_version: Option<u32>,
|
||||||
timeline: Timeline,
|
timeline: Timeline,
|
||||||
token_tx: Option<channel::Sender<TokenRequest>>,
|
token_tx: Option<channel::Sender<TokenRequest>>,
|
||||||
}
|
}
|
||||||
|
|
@ -55,6 +57,7 @@ enum Message {
|
||||||
CloseRequested(window::Id),
|
CloseRequested(window::Id),
|
||||||
ScreenReaderEnabled(chain::Toggler, bool),
|
ScreenReaderEnabled(chain::Toggler, bool),
|
||||||
MagnifierEnabled(chain::Toggler, bool),
|
MagnifierEnabled(chain::Toggler, bool),
|
||||||
|
InvertedColorsEnabled(chain::Toggler, bool),
|
||||||
Frame(Instant),
|
Frame(Instant),
|
||||||
Token(TokenUpdate),
|
Token(TokenUpdate),
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
|
|
@ -110,6 +113,18 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
self.magnifier_enabled = false;
|
self.magnifier_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::InvertedColorsEnabled(chain, enabled) => {
|
||||||
|
if let Some(tx) = &self.wayland_sender {
|
||||||
|
self.timeline.set_chain(chain).start();
|
||||||
|
self.inverted_colors_enabled = enabled;
|
||||||
|
let _ = tx.send(AccessibilityRequest::ScreenFilter {
|
||||||
|
inverted: enabled,
|
||||||
|
filter: Filter::Unknown,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.inverted_colors_enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
return destroy_popup(p);
|
return destroy_popup(p);
|
||||||
|
|
@ -119,7 +134,7 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
|
|
||||||
let mut popup_settings = self.core.applet.get_popup_settings(
|
let popup_settings = self.core.applet.get_popup_settings(
|
||||||
self.core.main_window_id().unwrap(),
|
self.core.main_window_id().unwrap(),
|
||||||
new_id,
|
new_id,
|
||||||
Some((1, 1)),
|
Some((1, 1)),
|
||||||
|
|
@ -181,11 +196,19 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
WaylandUpdate::Errored => {
|
WaylandUpdate::Errored => {
|
||||||
tracing::error!("Wayland error");
|
tracing::error!("Wayland error");
|
||||||
let _ = self.wayland_sender.take();
|
let _ = self.wayland_sender.take();
|
||||||
|
self.wayland_protocol_version = None;
|
||||||
self.magnifier_enabled = false;
|
self.magnifier_enabled = false;
|
||||||
|
self.inverted_colors_enabled = false;
|
||||||
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::Bound(ver)) => {
|
||||||
|
self.wayland_protocol_version = Some(ver);
|
||||||
}
|
}
|
||||||
WaylandUpdate::State(AccessibilityEvent::Magnifier(enabled)) => {
|
WaylandUpdate::State(AccessibilityEvent::Magnifier(enabled)) => {
|
||||||
self.magnifier_enabled = enabled;
|
self.magnifier_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
WaylandUpdate::State(AccessibilityEvent::ScreenFilter { inverted, .. }) => {
|
||||||
|
self.inverted_colors_enabled = inverted;
|
||||||
|
}
|
||||||
WaylandUpdate::Started(tx) => {
|
WaylandUpdate::Started(tx) => {
|
||||||
self.wayland_sender = Some(tx);
|
self.wayland_sender = Some(tx);
|
||||||
}
|
}
|
||||||
|
|
@ -234,14 +257,34 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
.text_size(14)
|
.text_size(14)
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
);
|
);
|
||||||
|
let invert_colors_toggle = padded_control(
|
||||||
|
anim!(
|
||||||
|
INVERT_COLORS_TOGGLE,
|
||||||
|
&self.timeline,
|
||||||
|
fl!("invert-colors"),
|
||||||
|
self.inverted_colors_enabled,
|
||||||
|
Message::InvertedColorsEnabled,
|
||||||
|
)
|
||||||
|
.text_size(14)
|
||||||
|
.width(Length::Fill),
|
||||||
|
);
|
||||||
|
|
||||||
|
let content_list = Column::with_capacity(5)
|
||||||
|
.push(reader_toggle)
|
||||||
|
.push_maybe(
|
||||||
|
self.wayland_protocol_version
|
||||||
|
.is_some()
|
||||||
|
.then_some(magnifier_toggle),
|
||||||
|
)
|
||||||
|
.push_maybe(
|
||||||
|
self.wayland_protocol_version
|
||||||
|
.is_some_and(|ver| ver >= 2)
|
||||||
|
.then_some(invert_colors_toggle),
|
||||||
|
)
|
||||||
|
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]))
|
||||||
|
.push(menu_button(text::body(fl!("settings"))).on_press(Message::OpenSettings))
|
||||||
|
.padding([8, 0]);
|
||||||
|
|
||||||
let content_list = column![
|
|
||||||
reader_toggle,
|
|
||||||
magnifier_toggle,
|
|
||||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
|
||||||
menu_button(text::body(fl!("settings"))).on_press(Message::OpenSettings)
|
|
||||||
]
|
|
||||||
.padding([8, 0]);
|
|
||||||
self.core.applet.popup_container(content_list).into()
|
self.core.applet.popup_container(content_list).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use cosmic::iced::{
|
||||||
futures::{self, channel::mpsc, SinkExt, StreamExt},
|
futures::{self, channel::mpsc, SinkExt, StreamExt},
|
||||||
stream, Subscription,
|
stream, Subscription,
|
||||||
};
|
};
|
||||||
|
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::Filter;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
|
@ -25,12 +26,15 @@ pub enum WaylandUpdate {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum AccessibilityEvent {
|
pub enum AccessibilityEvent {
|
||||||
|
Bound(u32),
|
||||||
Magnifier(bool),
|
Magnifier(bool),
|
||||||
|
ScreenFilter { inverted: bool, filter: Filter },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum AccessibilityRequest {
|
pub enum AccessibilityRequest {
|
||||||
Magnifier(bool),
|
Magnifier(bool),
|
||||||
|
ScreenFilter { inverted: bool, filter: Filter },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
pub fn a11y_subscription() -> iced::Subscription<WaylandUpdate> {
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,14 @@ use cctk::{
|
||||||
wayland_client::{self, globals::GlobalListContents, protocol::wl_registry, Dispatch, Proxy},
|
wayland_client::{self, globals::GlobalListContents, protocol::wl_registry, Dispatch, Proxy},
|
||||||
};
|
};
|
||||||
use cosmic::iced::futures::{self, SinkExt};
|
use cosmic::iced::futures::{self, SinkExt};
|
||||||
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1;
|
use cosmic_protocols::a11y::v1::client::cosmic_a11y_manager_v1::{self, Filter};
|
||||||
use futures::{channel::mpsc, executor::block_on};
|
use futures::{channel::mpsc, executor::block_on};
|
||||||
use wayland_client::{globals::registry_queue_init, Connection};
|
use wayland_client::{globals::registry_queue_init, Connection};
|
||||||
|
|
||||||
use super::{AccessibilityEvent, AccessibilityRequest};
|
use super::{AccessibilityEvent, AccessibilityRequest};
|
||||||
|
|
||||||
pub fn spawn_a11y(
|
pub fn spawn_a11y(
|
||||||
tx: mpsc::Sender<AccessibilityEvent>,
|
mut tx: mpsc::Sender<AccessibilityEvent>,
|
||||||
) -> anyhow::Result<SyncSender<AccessibilityRequest>> {
|
) -> anyhow::Result<SyncSender<AccessibilityRequest>> {
|
||||||
let (a11y_tx, a11y_rx) = calloop::channel::sync_channel(100);
|
let (a11y_tx, a11y_rx) = calloop::channel::sync_channel(100);
|
||||||
let conn = Connection::connect_to_env()?;
|
let conn = Connection::connect_to_env()?;
|
||||||
|
|
@ -33,6 +33,8 @@ pub fn spawn_a11y(
|
||||||
global: cosmic_a11y_manager_v1::CosmicA11yManagerV1,
|
global: cosmic_a11y_manager_v1::CosmicA11yManagerV1,
|
||||||
|
|
||||||
magnifier: bool,
|
magnifier: bool,
|
||||||
|
screen_inverted: bool,
|
||||||
|
screen_filter: Filter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, ()> for State {
|
impl Dispatch<cosmic_a11y_manager_v1::CosmicA11yManagerV1, ()> for State {
|
||||||
|
|
@ -60,6 +62,28 @@ pub fn spawn_a11y(
|
||||||
state.magnifier = magnifier;
|
state.magnifier = magnifier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cosmic_a11y_manager_v1::Event::ScreenFilter { inverted, filter } => {
|
||||||
|
let inverted = inverted
|
||||||
|
.into_result()
|
||||||
|
.unwrap_or(cosmic_a11y_manager_v1::ActiveState::Disabled)
|
||||||
|
== cosmic_a11y_manager_v1::ActiveState::Enabled;
|
||||||
|
let filter = filter.into_result().unwrap_or(Filter::Unknown);
|
||||||
|
|
||||||
|
if inverted != state.screen_inverted || filter != state.screen_filter {
|
||||||
|
if block_on(
|
||||||
|
state
|
||||||
|
.tx
|
||||||
|
.send(AccessibilityEvent::ScreenFilter { inverted, filter }),
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
state.loop_signal.stop();
|
||||||
|
state.loop_signal.wakeup();
|
||||||
|
};
|
||||||
|
state.screen_inverted = inverted;
|
||||||
|
state.screen_filter = filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -89,9 +113,11 @@ pub fn spawn_a11y(
|
||||||
|
|
||||||
let registry_state = RegistryState::new(&globals);
|
let registry_state = RegistryState::new(&globals);
|
||||||
let global = registry_state
|
let global = registry_state
|
||||||
.bind_one::<cosmic_a11y_manager_v1::CosmicA11yManagerV1, _, _>(&qhandle, 1..=1, ())
|
.bind_one::<cosmic_a11y_manager_v1::CosmicA11yManagerV1, _, _>(&qhandle, 1..=2, ())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let _ = block_on(tx.send(AccessibilityEvent::Bound(global.version())));
|
||||||
|
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(a11y_rx, |request, _, state| match request {
|
.insert_source(a11y_rx, |request, _, state| match request {
|
||||||
channel::Event::Msg(AccessibilityRequest::Magnifier(val)) => {
|
channel::Event::Msg(AccessibilityRequest::Magnifier(val)) => {
|
||||||
|
|
@ -101,6 +127,16 @@ pub fn spawn_a11y(
|
||||||
cosmic_a11y_manager_v1::ActiveState::Disabled
|
cosmic_a11y_manager_v1::ActiveState::Disabled
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
channel::Event::Msg(AccessibilityRequest::ScreenFilter { inverted, filter }) => {
|
||||||
|
state.global.set_screen_filter(
|
||||||
|
if inverted {
|
||||||
|
cosmic_a11y_manager_v1::ActiveState::Enabled
|
||||||
|
} else {
|
||||||
|
cosmic_a11y_manager_v1::ActiveState::Disabled
|
||||||
|
},
|
||||||
|
filter,
|
||||||
|
);
|
||||||
|
}
|
||||||
channel::Event::Closed => {
|
channel::Event::Closed => {
|
||||||
state.loop_signal.stop();
|
state.loop_signal.stop();
|
||||||
state.loop_signal.wakeup();
|
state.loop_signal.wakeup();
|
||||||
|
|
@ -114,6 +150,8 @@ pub fn spawn_a11y(
|
||||||
global,
|
global,
|
||||||
|
|
||||||
magnifier: false,
|
magnifier: false,
|
||||||
|
screen_inverted: false,
|
||||||
|
screen_filter: Filter::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
event_loop.run(None, &mut state, |_| {}).unwrap();
|
event_loop.run(None, &mut state, |_| {}).unwrap();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue