feat: a11y applet
This commit is contained in:
parent
6b740c59be
commit
eb27387fee
15 changed files with 732 additions and 178 deletions
396
Cargo.lock
generated
396
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,6 +17,7 @@ members = [
|
||||||
"cosmic-applet-workspaces",
|
"cosmic-applet-workspaces",
|
||||||
"cosmic-panel-button",
|
"cosmic-panel-button",
|
||||||
"cosmic-applet-input-sources",
|
"cosmic-applet-input-sources",
|
||||||
|
"cosmic-applet-a11y",
|
||||||
]
|
]
|
||||||
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
18
cosmic-applet-a11y/Cargo.toml
Normal file
18
cosmic-applet-a11y/Cargo.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "cosmic-applet-a11y"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cosmic-dbus-a11y = { git = "https://github.com/pop-os/dbus-settings-bindings" }
|
||||||
|
cosmic-time.workspace = true
|
||||||
|
i18n-embed-fl.workspace = true
|
||||||
|
i18n-embed.workspace = true
|
||||||
|
libcosmic.workspace = true
|
||||||
|
rust-embed.workspace = true
|
||||||
|
once_cell = "1"
|
||||||
|
tokio = { version = "1.36.0", features = ["sync", "time", "macros"] }
|
||||||
|
tracing-log.workspace = true
|
||||||
|
tracing-subscriber.workspace = true
|
||||||
|
tracing.workspace = true
|
||||||
|
zbus.workspace = true
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Accessibility
|
||||||
|
Type=Application
|
||||||
|
Exec=cosmic-applet-a11y
|
||||||
|
Terminal=false
|
||||||
|
Categories=COSMIC;
|
||||||
|
Keywords=COSMIC;Iced;
|
||||||
|
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
|
Icon=preferences-desktop-accessibility
|
||||||
|
StartupNotify=true
|
||||||
|
NoDisplay=true
|
||||||
|
X-CosmicApplet=true
|
||||||
|
# Indicates that the auto-hover click should go to the "end" of the hover popup
|
||||||
|
X-CosmicHoverPopup=Center
|
||||||
|
X-OverflowPriority=10
|
||||||
|
X-CosmicApplet=true
|
||||||
|
X-CosmicHoverPopup=Auto
|
||||||
|
X-OverflowPriority=10
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="applet-sound" clip-path="url(#clip0_4614_124622)">
|
||||||
|
<g id="Group">
|
||||||
|
<path id="Vector" d="M0 0H16V16H0V0Z" fill="#808080" fill-opacity="0.01"/>
|
||||||
|
<path id="Vector_2" d="M7.07001 2.04997C6.86376 2.05624 6.66456 2.1265 6.5 2.25098L3 5.00098H1C0.446 5.00098 0 5.44698 0 6.00098V10.001C0 10.555 0.446 11.001 1 11.001H3L6.5 13.751C7 14.144 8 14.001 8 13.001V3.00098C8 2.31398 7.52801 2.03097 7.07001 2.04997Z" fill="#232323"/>
|
||||||
|
<path id="Vector_3" d="M9 5.62L11 4.995C12 6.995 12 8.995 11 10.995L9 10.37C10 8.37 10 7.62 9 5.62Z" fill="#232323"/>
|
||||||
|
<path id="Vector_4" opacity="0.35" d="M12 3.94L14 3.00201C16 6.00201 16 10.002 14 13.002L12 12.065C14 9.065 14 6.94 12 3.94Z" fill="#232323"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_4614_124622">
|
||||||
|
<rect width="16" height="16" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 903 B |
4
cosmic-applet-a11y/i18n.toml
Normal file
4
cosmic-applet-a11y/i18n.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
fallback_language = "en"
|
||||||
|
|
||||||
|
[fluent]
|
||||||
|
assets_dir = "i18n"
|
||||||
1
cosmic-applet-a11y/i18n/en/cosmic_applet_a11y.ftl
Normal file
1
cosmic-applet-a11y/i18n/en/cosmic_applet_a11y.ftl
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
accessibility = Accessibility
|
||||||
236
cosmic-applet-a11y/src/app.rs
Normal file
236
cosmic-applet-a11y/src/app.rs
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backend::{self, A11yRequest},
|
||||||
|
fl,
|
||||||
|
};
|
||||||
|
use cosmic::{
|
||||||
|
applet::{
|
||||||
|
menu_button, padded_control,
|
||||||
|
token::subscription::{activation_token_subscription, TokenRequest, TokenUpdate},
|
||||||
|
},
|
||||||
|
cctk::sctk::reexports::calloop,
|
||||||
|
cosmic_theme::Spacing,
|
||||||
|
iced::{
|
||||||
|
alignment::Horizontal,
|
||||||
|
platform_specific::shell::wayland::commands::popup::{destroy_popup, get_popup},
|
||||||
|
widget::{column, container, row, slider},
|
||||||
|
window, Alignment, Length, Subscription,
|
||||||
|
},
|
||||||
|
iced_core::{alignment::Vertical, Background, Border, Color, Shadow},
|
||||||
|
iced_runtime::core::layout::Limits,
|
||||||
|
iced_widget::{Column, Row},
|
||||||
|
theme,
|
||||||
|
widget::{divider, horizontal_space, icon, scrollable, text, vertical_space},
|
||||||
|
Element, Task,
|
||||||
|
};
|
||||||
|
use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
||||||
|
|
||||||
|
use std::{collections::HashMap, path::PathBuf, time::Duration};
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
static ENABLED: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||||
|
|
||||||
|
pub fn run() -> cosmic::iced::Result {
|
||||||
|
cosmic::applet::run::<CosmicA11yApplet>(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
struct CosmicA11yApplet {
|
||||||
|
core: cosmic::app::Core,
|
||||||
|
icon_name: String,
|
||||||
|
a11y_enabled: bool,
|
||||||
|
popup: Option<window::Id>,
|
||||||
|
a11y_sender: Option<UnboundedSender<backend::A11yRequest>>,
|
||||||
|
timeline: Timeline,
|
||||||
|
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Message {
|
||||||
|
TogglePopup,
|
||||||
|
CloseRequested(window::Id),
|
||||||
|
Errored(String),
|
||||||
|
Enabled(chain::Toggler, bool),
|
||||||
|
Frame(Instant),
|
||||||
|
Token(TokenUpdate),
|
||||||
|
OpenSettings,
|
||||||
|
Update(backend::Update),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl cosmic::Application for CosmicA11yApplet {
|
||||||
|
type Message = Message;
|
||||||
|
type Executor = cosmic::SingleThreadExecutor;
|
||||||
|
type Flags = ();
|
||||||
|
const APP_ID: &'static str = "com.system76.CosmicAppletA11y";
|
||||||
|
|
||||||
|
fn init(
|
||||||
|
core: cosmic::app::Core,
|
||||||
|
_flags: Self::Flags,
|
||||||
|
) -> (
|
||||||
|
Self,
|
||||||
|
cosmic::iced::Task<cosmic::app::Message<Self::Message>>,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
core,
|
||||||
|
token_tx: None,
|
||||||
|
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Task::none(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn core(&self) -> &cosmic::app::Core {
|
||||||
|
&self.core
|
||||||
|
}
|
||||||
|
|
||||||
|
fn core_mut(&mut self) -> &mut cosmic::app::Core {
|
||||||
|
&mut self.core
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(
|
||||||
|
&mut self,
|
||||||
|
message: Self::Message,
|
||||||
|
) -> cosmic::iced::Task<cosmic::app::Message<Self::Message>> {
|
||||||
|
match message {
|
||||||
|
Message::Frame(now) => self.timeline.now(now),
|
||||||
|
Message::Enabled(chain, enabled) => {
|
||||||
|
self.timeline.set_chain(chain).start();
|
||||||
|
self.a11y_enabled = enabled;
|
||||||
|
|
||||||
|
if let Some(tx) = &self.a11y_sender {
|
||||||
|
let _ = tx.send(A11yRequest::Status(enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::Errored(why) => {
|
||||||
|
tracing::error!("{}", why);
|
||||||
|
}
|
||||||
|
Message::TogglePopup => {
|
||||||
|
if let Some(p) = self.popup.take() {
|
||||||
|
return destroy_popup(p);
|
||||||
|
} else {
|
||||||
|
self.timeline = Timeline::new();
|
||||||
|
|
||||||
|
let new_id = window::Id::unique();
|
||||||
|
self.popup.replace(new_id);
|
||||||
|
|
||||||
|
let mut popup_settings = self.core.applet.get_popup_settings(
|
||||||
|
self.core.main_window_id().unwrap(),
|
||||||
|
new_id,
|
||||||
|
Some((1, 1)),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
popup_settings.positioner.size_limits = Limits::NONE
|
||||||
|
.max_width(300.0)
|
||||||
|
.min_width(200.0)
|
||||||
|
.min_height(10.0)
|
||||||
|
.max_height(1080.0);
|
||||||
|
|
||||||
|
return get_popup(popup_settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::CloseRequested(id) => {
|
||||||
|
if Some(id) == self.popup {
|
||||||
|
self.popup = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::OpenSettings => {
|
||||||
|
let exec = "cosmic-settings a11y".to_string();
|
||||||
|
if let Some(tx) = self.token_tx.as_ref() {
|
||||||
|
let _ = tx.send(TokenRequest {
|
||||||
|
app_id: Self::APP_ID.to_string(),
|
||||||
|
exec,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
tracing::error!("Wayland tx is None");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Message::Token(u) => match u {
|
||||||
|
TokenUpdate::Init(tx) => {
|
||||||
|
self.token_tx = Some(tx);
|
||||||
|
}
|
||||||
|
TokenUpdate::Finished => {
|
||||||
|
self.token_tx = None;
|
||||||
|
}
|
||||||
|
TokenUpdate::ActivationToken { token, .. } => {
|
||||||
|
let mut cmd = std::process::Command::new("cosmic-settings");
|
||||||
|
cmd.arg("a11y");
|
||||||
|
if let Some(token) = token {
|
||||||
|
cmd.env("XDG_ACTIVATION_TOKEN", &token);
|
||||||
|
cmd.env("DESKTOP_STARTUP_ID", &token);
|
||||||
|
}
|
||||||
|
tokio::spawn(cosmic::process::spawn(cmd));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Message::Update(update) => match update {
|
||||||
|
backend::Update::Error(err) => {
|
||||||
|
tracing::error!("{err}");
|
||||||
|
}
|
||||||
|
backend::Update::Status(enabled) => {
|
||||||
|
self.a11y_enabled = enabled;
|
||||||
|
}
|
||||||
|
backend::Update::Init(enabled, tx) => {
|
||||||
|
self.a11y_enabled = enabled;
|
||||||
|
self.a11y_sender = Some(tx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Element<Message> {
|
||||||
|
self.core
|
||||||
|
.applet
|
||||||
|
.icon_button("preferences-desktop-accessibility")
|
||||||
|
.on_press_down(Message::TogglePopup)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
||||||
|
let Spacing {
|
||||||
|
space_xxs, space_s, ..
|
||||||
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
||||||
|
let toggle = padded_control(
|
||||||
|
anim!(
|
||||||
|
//toggler
|
||||||
|
ENABLED,
|
||||||
|
&self.timeline,
|
||||||
|
fl!("accessibility"),
|
||||||
|
self.a11y_enabled,
|
||||||
|
Message::Enabled,
|
||||||
|
)
|
||||||
|
.text_size(14)
|
||||||
|
.width(Length::Fill),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.core
|
||||||
|
.applet
|
||||||
|
.popup_container(toggle.padding([8, 8]))
|
||||||
|
.max_width(372.)
|
||||||
|
.max_height(600.)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
|
Subscription::batch(vec![
|
||||||
|
backend::subscription().map(Message::Update),
|
||||||
|
self.timeline
|
||||||
|
.as_subscription()
|
||||||
|
.map(|(_, now)| Message::Frame(now)),
|
||||||
|
activation_token_subscription(0).map(Message::Token),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_close_requested(&self, id: window::Id) -> Option<Message> {
|
||||||
|
Some(Message::CloseRequested(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style(&self) -> Option<cosmic::iced_runtime::Appearance> {
|
||||||
|
Some(cosmic::applet::style())
|
||||||
|
}
|
||||||
|
}
|
||||||
139
cosmic-applet-a11y/src/backend/mod.rs
Normal file
139
cosmic-applet-a11y/src/backend/mod.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use cosmic::iced::futures::FutureExt;
|
||||||
|
use cosmic::{
|
||||||
|
iced::{
|
||||||
|
self,
|
||||||
|
futures::{self, select, SinkExt, StreamExt},
|
||||||
|
Subscription,
|
||||||
|
},
|
||||||
|
iced_futures::stream,
|
||||||
|
};
|
||||||
|
use cosmic_dbus_a11y::*;
|
||||||
|
use std::{fmt::Debug, hash::Hash};
|
||||||
|
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||||
|
use zbus::{Connection, Result};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Update {
|
||||||
|
Error(String),
|
||||||
|
Status(bool),
|
||||||
|
Init(bool, UnboundedSender<A11yRequest>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum A11yRequest {
|
||||||
|
Status(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum State {
|
||||||
|
Ready,
|
||||||
|
Waiting(Connection, u8, bool, UnboundedReceiver<A11yRequest>),
|
||||||
|
Finished,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscription() -> iced::Subscription<Update> {
|
||||||
|
struct MyId;
|
||||||
|
|
||||||
|
Subscription::run_with_id(
|
||||||
|
std::any::TypeId::of::<MyId>(),
|
||||||
|
stream::channel(50, move |mut output| async move {
|
||||||
|
let mut state = State::Ready;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
state = start_listening(state, &mut output).await;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_listening(
|
||||||
|
state: State,
|
||||||
|
output: &mut futures::channel::mpsc::Sender<Update>,
|
||||||
|
) -> State {
|
||||||
|
match state {
|
||||||
|
State::Ready => {
|
||||||
|
let conn = match Connection::session().await.map_err(|e| e.to_string()) {
|
||||||
|
Ok(conn) => conn,
|
||||||
|
Err(e) => {
|
||||||
|
_ = output.send(Update::Error(e)).await;
|
||||||
|
return State::Finished;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let mut enabled = false;
|
||||||
|
if let Ok(proxy) = StatusProxy::new(&conn).await {
|
||||||
|
if let Ok(status) = proxy.screen_reader_enabled().await {
|
||||||
|
enabled = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = output.send(Update::Init(enabled, tx)).await;
|
||||||
|
State::Waiting(conn, 20, enabled, rx)
|
||||||
|
}
|
||||||
|
State::Waiting(conn, mut retry, mut enabled, mut rx) => {
|
||||||
|
let Ok(proxy) = StatusProxy::new(&conn).await else {
|
||||||
|
if retry == 0 {
|
||||||
|
tracing::error!("Accessibility Status is unavailable.");
|
||||||
|
return State::Finished;
|
||||||
|
} else {
|
||||||
|
_ = tokio::time::sleep(tokio::time::Duration::from_secs(
|
||||||
|
2_u64.pow(retry as u32),
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
retry -= 1;
|
||||||
|
return State::Waiting(conn, retry, enabled, rx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
retry = 20;
|
||||||
|
|
||||||
|
let mut watch_changes = proxy.receive_screen_reader_enabled_changed().await;
|
||||||
|
|
||||||
|
if let Ok(status) = proxy.screen_reader_enabled().await {
|
||||||
|
if enabled != status {
|
||||||
|
_ = output.send(Update::Status(enabled));
|
||||||
|
}
|
||||||
|
enabled = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok(status) = proxy.screen_reader_enabled().await {
|
||||||
|
if enabled != status {
|
||||||
|
_ = output.send(Update::Status(enabled));
|
||||||
|
}
|
||||||
|
enabled = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut next_change = Box::pin(watch_changes.next()).fuse();
|
||||||
|
let mut next_request = Box::pin(rx.recv()).fuse();
|
||||||
|
|
||||||
|
select! {
|
||||||
|
v = next_request => {
|
||||||
|
match v {
|
||||||
|
Some(A11yRequest::Status(is_enabled)) => {
|
||||||
|
// Set status
|
||||||
|
enabled = is_enabled;
|
||||||
|
_ = proxy.set_is_enabled(is_enabled).await;
|
||||||
|
_ = proxy.set_screen_reader_enabled(is_enabled).await;
|
||||||
|
}
|
||||||
|
None => return State::Finished,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = next_change => {
|
||||||
|
match v {
|
||||||
|
Some(f) => {
|
||||||
|
if let Ok(enabled) = f.get().await {
|
||||||
|
_ = output.send(Update::Status(enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
State::Waiting(conn, retry, enabled, rx)
|
||||||
|
}
|
||||||
|
State::Finished => iced::futures::future::pending().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
13
cosmic-applet-a11y/src/lib.rs
Normal file
13
cosmic-applet-a11y/src/lib.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod backend;
|
||||||
|
mod localize;
|
||||||
|
|
||||||
|
use localize::localize;
|
||||||
|
|
||||||
|
pub fn run() -> cosmic::iced::Result {
|
||||||
|
localize();
|
||||||
|
app::run()
|
||||||
|
}
|
||||||
48
cosmic-applet-a11y/src/localize.rs
Normal file
48
cosmic-applet-a11y/src/localize.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use i18n_embed::{
|
||||||
|
fluent::{fluent_language_loader, FluentLanguageLoader},
|
||||||
|
DefaultLocalizer, LanguageLoader, Localizer,
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use rust_embed::RustEmbed;
|
||||||
|
|
||||||
|
#[derive(RustEmbed)]
|
||||||
|
#[folder = "i18n/"]
|
||||||
|
struct Localizations;
|
||||||
|
|
||||||
|
pub static LANGUAGE_LOADER: Lazy<FluentLanguageLoader> = Lazy::new(|| {
|
||||||
|
let loader: FluentLanguageLoader = fluent_language_loader!();
|
||||||
|
|
||||||
|
loader
|
||||||
|
.load_fallback_language(&Localizations)
|
||||||
|
.expect("Error while loading fallback language");
|
||||||
|
|
||||||
|
loader
|
||||||
|
});
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! fl {
|
||||||
|
($message_id:literal) => {{
|
||||||
|
i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id)
|
||||||
|
}};
|
||||||
|
|
||||||
|
($message_id:literal, $($args:expr),*) => {{
|
||||||
|
i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id, $($args), *)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the `Localizer` to be used for localizing this library.
|
||||||
|
pub fn localizer() -> Box<dyn Localizer> {
|
||||||
|
Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER, &Localizations))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn localize() {
|
||||||
|
let localizer = localizer();
|
||||||
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
|
eprintln!("Error while loading language for App List {}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
cosmic-applet-a11y/src/main.rs
Normal file
13
cosmic-applet-a11y/src/main.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
fn main() -> cosmic::iced::Result {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
let _ = tracing_log::LogTracer::init();
|
||||||
|
|
||||||
|
tracing::info!("Starting battery applet with version {VERSION}");
|
||||||
|
|
||||||
|
cosmic_applet_a11y::run()
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ license = "GPL-3.0-only"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmic-app-list = { path = "../cosmic-app-list" }
|
cosmic-app-list = { path = "../cosmic-app-list" }
|
||||||
cosmic-applet-audio = { path = "../cosmic-applet-audio" }
|
cosmic-applet-audio = { path = "../cosmic-applet-audio" }
|
||||||
|
cosmic-applet-a11y = { path = "../cosmic-applet-a11y" }
|
||||||
cosmic-applet-battery = { path = "../cosmic-applet-battery" }
|
cosmic-applet-battery = { path = "../cosmic-applet-battery" }
|
||||||
cosmic-applet-bluetooth = { path = "../cosmic-applet-bluetooth" }
|
cosmic-applet-bluetooth = { path = "../cosmic-applet-bluetooth" }
|
||||||
cosmic-applet-minimize = { path = "../cosmic-applet-minimize" }
|
cosmic-applet-minimize = { path = "../cosmic-applet-minimize" }
|
||||||
|
|
@ -17,8 +18,8 @@ cosmic-applet-status-area = { path = "../cosmic-applet-status-area" }
|
||||||
cosmic-applet-tiling = { path = "../cosmic-applet-tiling" }
|
cosmic-applet-tiling = { path = "../cosmic-applet-tiling" }
|
||||||
cosmic-applet-time = { path = "../cosmic-applet-time" }
|
cosmic-applet-time = { path = "../cosmic-applet-time" }
|
||||||
cosmic-applet-workspaces = { path = "../cosmic-applet-workspaces" }
|
cosmic-applet-workspaces = { path = "../cosmic-applet-workspaces" }
|
||||||
cosmic-applet-input-sources = { path = "../cosmic-applet-input-sources"}
|
cosmic-applet-input-sources = { path = "../cosmic-applet-input-sources" }
|
||||||
cosmic-panel-button = { path = "../cosmic-panel-button"}
|
cosmic-panel-button = { path = "../cosmic-panel-button" }
|
||||||
libcosmic.workspace = true
|
libcosmic.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ fn main() -> cosmic::iced::Result {
|
||||||
|
|
||||||
match cmd {
|
match cmd {
|
||||||
"cosmic-app-list" => cosmic_app_list::run(),
|
"cosmic-app-list" => cosmic_app_list::run(),
|
||||||
|
"cosmic-applet-a11y" => cosmic_applet_a11y::run(),
|
||||||
"cosmic-applet-audio" => cosmic_applet_audio::run(),
|
"cosmic-applet-audio" => cosmic_applet_audio::run(),
|
||||||
"cosmic-applet-battery" => cosmic_applet_battery::run(),
|
"cosmic-applet-battery" => cosmic_applet_battery::run(),
|
||||||
"cosmic-applet-bluetooth" => cosmic_applet_bluetooth::run(),
|
"cosmic-applet-bluetooth" => cosmic_applet_bluetooth::run(),
|
||||||
|
|
|
||||||
2
justfile
2
justfile
|
|
@ -58,7 +58,7 @@ _install_metainfo:
|
||||||
install -Dm0644 {{metainfo-src}} {{metainfo-dst}}
|
install -Dm0644 {{metainfo-src}} {{metainfo-dst}}
|
||||||
|
|
||||||
# Installs files into the system
|
# Installs files into the system
|
||||||
install: (_install_bin 'cosmic-applets') (_link_applet 'cosmic-panel-button') (_install_applet 'com.system76.CosmicAppList' 'cosmic-app-list') (_install_default_schema 'cosmic-app-list') (_install_applet 'com.system76.CosmicAppletAudio' 'cosmic-applet-audio') (_install_applet 'com.system76.CosmicAppletInputSources' 'cosmic-applet-input-sources') (_install_applet 'com.system76.CosmicAppletBattery' 'cosmic-applet-battery') (_install_applet 'com.system76.CosmicAppletBluetooth' 'cosmic-applet-bluetooth') (_install_applet 'com.system76.CosmicAppletMinimize' 'cosmic-applet-minimize') (_install_applet 'com.system76.CosmicAppletNetwork' 'cosmic-applet-network') (_install_applet 'com.system76.CosmicAppletNotifications' 'cosmic-applet-notifications') (_install_applet 'com.system76.CosmicAppletPower' 'cosmic-applet-power') (_install_applet 'com.system76.CosmicAppletStatusArea' 'cosmic-applet-status-area') (_install_applet 'com.system76.CosmicAppletTiling' 'cosmic-applet-tiling') (_install_applet 'com.system76.CosmicAppletTime' 'cosmic-applet-time') (_install_applet 'com.system76.CosmicAppletWorkspaces' 'cosmic-applet-workspaces') (_install_button 'com.system76.CosmicPanelAppButton' 'cosmic-panel-app-button') (_install_button 'com.system76.CosmicPanelLauncherButton' 'cosmic-panel-launcher-button') (_install_button 'com.system76.CosmicPanelWorkspacesButton' 'cosmic-panel-workspaces-button') (_install_metainfo)
|
install: (_install_bin 'cosmic-applets') (_link_applet 'cosmic-panel-button') (_install_applet 'com.system76.CosmicAppList' 'cosmic-app-list') (_install_default_schema 'cosmic-app-list') (_install_applet 'com.system76.CosmicAppletA11y' 'cosmic-applet-a11y') (_install_applet 'com.system76.CosmicAppletAudio' 'cosmic-applet-audio') (_install_applet 'com.system76.CosmicAppletInputSources' 'cosmic-applet-input-sources') (_install_applet 'com.system76.CosmicAppletBattery' 'cosmic-applet-battery') (_install_applet 'com.system76.CosmicAppletBluetooth' 'cosmic-applet-bluetooth') (_install_applet 'com.system76.CosmicAppletMinimize' 'cosmic-applet-minimize') (_install_applet 'com.system76.CosmicAppletNetwork' 'cosmic-applet-network') (_install_applet 'com.system76.CosmicAppletNotifications' 'cosmic-applet-notifications') (_install_applet 'com.system76.CosmicAppletPower' 'cosmic-applet-power') (_install_applet 'com.system76.CosmicAppletStatusArea' 'cosmic-applet-status-area') (_install_applet 'com.system76.CosmicAppletTiling' 'cosmic-applet-tiling') (_install_applet 'com.system76.CosmicAppletTime' 'cosmic-applet-time') (_install_applet 'com.system76.CosmicAppletWorkspaces' 'cosmic-applet-workspaces') (_install_button 'com.system76.CosmicPanelAppButton' 'cosmic-panel-app-button') (_install_button 'com.system76.CosmicPanelLauncherButton' 'cosmic-panel-launcher-button') (_install_button 'com.system76.CosmicPanelWorkspacesButton' 'cosmic-panel-workspaces-button') (_install_metainfo)
|
||||||
|
|
||||||
# Vendor Cargo dependencies locally
|
# Vendor Cargo dependencies locally
|
||||||
vendor:
|
vendor:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue