diff --git a/icons/cover.svg b/icons/cover.svg
new file mode 100644
index 0000000..f7df12b
--- /dev/null
+++ b/icons/cover.svg
@@ -0,0 +1 @@
+
diff --git a/src/app.rs b/src/app.rs
index d36ba60..b3d474f 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -671,7 +671,7 @@ pub fn run() -> Result<(), Error> {
task.id == TaskId::Suspend) {
continue;
}
- if let Ok(v) = context.battery.capacity() {
+ if let Ok(v) = context.battery.capacity().map(|v| v[0]) {
if v < context.settings.battery.power_off {
power_off(view.as_mut(), &mut history, &mut updating, &mut context);
exit_status = ExitStatus::PowerOff;
diff --git a/src/battery/fake.rs b/src/battery/fake.rs
index 08b4a78..1449f2c 100644
--- a/src/battery/fake.rs
+++ b/src/battery/fake.rs
@@ -13,11 +13,11 @@ impl FakeBattery {
}
impl Battery for FakeBattery {
- fn capacity(&mut self) -> Result {
- Ok(self.capacity)
+ fn capacity(&mut self) -> Result, Error> {
+ Ok(vec![self.capacity])
}
- fn status(&mut self) -> Result {
- Ok(self.status)
+ fn status(&mut self) -> Result, Error> {
+ Ok(vec![self.status])
}
}
diff --git a/src/battery/kobo.rs b/src/battery/kobo.rs
index 04031e4..3b12329 100644
--- a/src/battery/kobo.rs
+++ b/src/battery/kobo.rs
@@ -1,20 +1,32 @@
use std::fs::File;
use std::path::Path;
use std::io::{Read, Seek, SeekFrom};
-use anyhow::{Error, format_err};
+use anyhow::Error;
use crate::device::CURRENT_DEVICE;
use super::{Battery, Status};
const BATTERY_INTERFACE_A: &str = "/sys/class/power_supply/mc13892_bat";
const BATTERY_INTERFACE_B: &str = "/sys/class/power_supply/battery";
+const POWER_COVER_INTERFACE: &str = "/sys/class/misc/cilix";
const BATTERY_CAPACITY: &str = "capacity";
const BATTERY_STATUS: &str = "status";
+const POWER_COVER_CAPACITY: &str = "cilix_bat_capacity";
+const POWER_COVER_STATUS: &str = "charge_status";
+const POWER_COVER_CONNECTED: &str = "cilix_conn";
+
+pub struct PowerCover {
+ capacity: File,
+ status: File,
+ connected: File,
+}
+
// TODO: health, technology, time_to_full_now, time_to_empty_now
pub struct KoboBattery {
capacity: File,
status: File,
+ power_cover: Option,
}
impl KoboBattery {
@@ -26,28 +38,79 @@ impl KoboBattery {
};
let capacity = File::open(base.join(BATTERY_CAPACITY))?;
let status = File::open(base.join(BATTERY_STATUS))?;
- Ok(KoboBattery { capacity, status })
+ let power_cover = if CURRENT_DEVICE.has_power_cover() {
+ let base = Path::new(POWER_COVER_INTERFACE);
+ let capacity = File::open(base.join(POWER_COVER_CAPACITY))?;
+ let status = File::open(base.join(POWER_COVER_STATUS))?;
+ let connected = File::open(base.join(POWER_COVER_CONNECTED))?;
+ Some(PowerCover { capacity, status, connected })
+ } else {
+ None
+ };
+ Ok(KoboBattery { capacity, status, power_cover })
+ }
+}
+
+impl KoboBattery {
+ fn is_power_cover_connected(&mut self) -> Result {
+ if let Some(power_cover) = self.power_cover.as_mut() {
+ let mut buf = String::new();
+ power_cover.connected.seek(SeekFrom::Start(0))?;
+ power_cover.connected.read_to_string(&mut buf)?;
+ Ok(buf.trim_end().parse::().map_or(false, |v| v == 1))
+ } else {
+ Ok(false)
+ }
}
}
impl Battery for KoboBattery {
- fn capacity(&mut self) -> Result {
+ fn capacity(&mut self) -> Result, Error> {
let mut buf = String::new();
self.capacity.seek(SeekFrom::Start(0))?;
self.capacity.read_to_string(&mut buf)?;
- Ok(buf.trim_end().parse::().unwrap_or(0.0))
+ let capacity = buf.trim_end().parse::()
+ .unwrap_or(0.0);
+ if matches!(self.is_power_cover_connected(), Ok(true)) {
+ let mut buf = String::new();
+ self.power_cover.iter_mut().for_each(|power_cover| {
+ power_cover.capacity.seek(SeekFrom::Start(0)).ok();
+ power_cover.capacity.read_to_string(&mut buf).ok();
+ });
+ let aux_capacity = buf.trim_end().parse::()
+ .unwrap_or(0.0);
+ Ok(vec![capacity, aux_capacity])
+ } else {
+ Ok(vec![capacity])
+ }
}
- fn status(&mut self) -> Result {
+ fn status(&mut self) -> Result, Error> {
let mut buf = String::new();
self.status.seek(SeekFrom::Start(0))?;
self.status.read_to_string(&mut buf)?;
- match buf.trim_end() {
- "Discharging" => Ok(Status::Discharging),
- "Charging" => Ok(Status::Charging),
- "Not charging" | "Full" => Ok(Status::Charged),
- _ => Err(format_err!("unknown battery status")),
+ let status = match buf.trim_end() {
+ "Discharging" => Status::Discharging,
+ "Charging" => Status::Charging,
+ "Not charging" | "Full" => Status::Charged,
+ _ => Status::Unknown,
+ };
+ if matches!(self.is_power_cover_connected(), Ok(true)) {
+ let mut buf = String::new();
+ self.power_cover.iter_mut().for_each(|power_cover| {
+ power_cover.status.seek(SeekFrom::Start(0)).ok();
+ power_cover.status.read_to_string(&mut buf).ok();
+ });
+ let aux_status = match buf.trim_end().parse::() {
+ Ok(0) => Status::Discharging,
+ Ok(2) => Status::Charging,
+ Ok(3) => Status::Charged,
+ _ => Status::Unknown,
+ };
+ Ok(vec![status, aux_status])
+ } else {
+ Ok(vec![status])
}
}
}
diff --git a/src/battery/mod.rs b/src/battery/mod.rs
index c876c09..d63f392 100644
--- a/src/battery/mod.rs
+++ b/src/battery/mod.rs
@@ -11,11 +11,11 @@ pub enum Status {
Discharging,
Charging,
Charged,
+ Unknown
// Full,
- // Unknown
}
pub trait Battery {
- fn capacity(&mut self) -> Result;
- fn status(&mut self) -> Result;
+ fn capacity(&mut self) -> Result, Error>;
+ fn status(&mut self) -> Result, Error>;
}
diff --git a/src/device.rs b/src/device.rs
index 36c2e38..da74b74 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -232,6 +232,10 @@ impl Device {
Model::Sage | Model::Libra2)
}
+ pub fn has_power_cover(&self) -> bool {
+ matches!(self.model, Model::Sage)
+ }
+
pub fn has_removable_storage(&self) -> bool {
matches!(self.model,
Model::AuraH2O | Model::Aura | Model::AuraHD |
diff --git a/src/view/battery.rs b/src/view/battery.rs
index 0571908..1570949 100644
--- a/src/view/battery.rs
+++ b/src/view/battery.rs
@@ -36,8 +36,8 @@ impl Battery {
}
pub fn update(&mut self, rq: &mut RenderQueue, context: &mut Context) {
- self.capacity = context.battery.capacity().unwrap_or(self.capacity);
- self.status = context.battery.status().unwrap_or(self.status);
+ self.capacity = context.battery.capacity().map_or(self.capacity, |v| v[0]);
+ self.status = context.battery.status().map_or(self.status, |v| v[0]);
rq.add(RenderData::new(self.id, self.rect, UpdateMode::Gui));
}
}
diff --git a/src/view/common.rs b/src/view/common.rs
index 7feffdb..3122c65 100644
--- a/src/view/common.rs
+++ b/src/view/common.rs
@@ -156,13 +156,21 @@ pub fn toggle_battery_menu(view: &mut dyn View, rect: Rectangle, enable: Option<
if let Some(false) = enable {
return;
}
- let text = match (context.battery.status(), context.battery.capacity()) {
- (Ok(status), Ok(capacity)) => format!("{:?} {}%", status, capacity),
- (Ok(status), Err(..)) => format!("{:?}", status),
- (Err(..), Ok(capacity)) => format!("{} %", capacity),
- _ => "Unknown".to_string(),
- };
- let entries = vec![EntryKind::Message(text)];
+
+ let mut entries = Vec::new();
+
+ match context.battery.status().ok().zip(context.battery.capacity().ok()) {
+ Some((status, capacity)) => {
+ for (i, (s, c)) in status.iter().zip(capacity.iter()).enumerate() {
+ entries.push(EntryKind::Message(format!("{:?} {}%", s, c),
+ if i > 0 { Some("cover".to_string()) } else { None }));
+ }
+ },
+ _ => {
+ entries.push(EntryKind::Message("Information Unavailable".to_string(), None));
+ },
+ }
+
let battery_menu = Menu::new(rect, ViewId::BatteryMenu, MenuKind::DropDown, entries, context);
rq.add(RenderData::new(battery_menu.id(), *battery_menu.rect(), UpdateMode::Gui));
view.children_mut().push(Box::new(battery_menu) as Box);
@@ -181,7 +189,7 @@ pub fn toggle_clock_menu(view: &mut dyn View, rect: Rectangle, enable: Option);
diff --git a/src/view/icon.rs b/src/view/icon.rs
index 7bf32de..d5a136a 100644
--- a/src/view/icon.rs
+++ b/src/view/icon.rs
@@ -27,7 +27,7 @@ lazy_static! {
"close", "check_mark-small", "check_mark", "check_mark-large", "bullet",
"arrow-left", "arrow-right", "angle-down", "angle-up", "crop", "toc", "font_family",
"font_size", "line_height", "align-justify", "align-left", "align-right",
- "align-center", "margin", "plug", "enclosed_menu", "contrast", "gray"].iter().cloned() {
+ "align-center", "margin", "plug", "cover", "enclosed_menu", "contrast", "gray"].iter().cloned() {
let path = dir.join(&format!("{}.svg", name));
let doc = PdfOpener::new().and_then(|o| o.open(path)).unwrap();
let pixmap = doc.page(0).and_then(|p| p.pixmap(scale)).unwrap();
diff --git a/src/view/menu_entry.rs b/src/view/menu_entry.rs
index 27564dd..19681c1 100644
--- a/src/view/menu_entry.rs
+++ b/src/view/menu_entry.rs
@@ -86,7 +86,7 @@ impl View for MenuEntry {
EntryKind::SubMenu(_, ref entries) | EntryKind::More(ref entries) => {
bus.push_back(Event::SubMenu(self.anchor, entries.clone()));
},
- EntryKind::Message(_) => {
+ EntryKind::Message(..) => {
bus.push_back(Event::Validate);
},
_ => (),
@@ -145,6 +145,7 @@ impl View for MenuEntry {
let (icon_name, x_offset) = match self.kind {
EntryKind::CheckBox(_, _, value) if value => ("check_mark", 0),
EntryKind::RadioButton(_, _, value) if value => ("bullet", 0),
+ EntryKind::Message(_, Some(ref name)) => (name.as_str(), 0),
EntryKind::SubMenu(..) |
EntryKind::More(..) => ("angle-right-small",
self.rect.width() as i32 - padding / 2),
diff --git a/src/view/mod.rs b/src/view/mod.rs
index 61cad7e..fa4dd2a 100644
--- a/src/view/mod.rs
+++ b/src/view/mod.rs
@@ -494,7 +494,7 @@ pub enum TextKind {
#[derive(Debug, Clone)]
pub enum EntryKind {
- Message(String),
+ Message(String, Option),
Command(String, EntryId),
CheckBox(String, EntryId, bool),
RadioButton(String, EntryId, bool),
@@ -585,7 +585,7 @@ impl EntryKind {
pub fn text(&self) -> &str {
match *self {
- EntryKind::Message(ref s) |
+ EntryKind::Message(ref s, ..) |
EntryKind::Command(ref s, ..) |
EntryKind::CheckBox(ref s, ..) |
EntryKind::RadioButton(ref s, ..) |
diff --git a/src/view/top_bar.rs b/src/view/top_bar.rs
index da28f98..bfa1185 100644
--- a/src/view/top_bar.rs
+++ b/src/view/top_bar.rs
@@ -43,8 +43,8 @@ impl TopBar {
children.push(Box::new(title_label) as Box);
children.push(Box::new(clock_label) as Box);
- let capacity = context.battery.capacity().unwrap_or(0.0);
- let status = context.battery.status().unwrap_or(crate::battery::Status::Discharging);
+ let capacity = context.battery.capacity().map_or(0.0, |v| v[0]);
+ let status = context.battery.status().map_or(crate::battery::Status::Discharging, |v| v[0]);
let battery_widget = Battery::new(rect![rect.max - pt!(3*side, side),
rect.max - pt!(2*side, 0)],
capacity,