Compare commits

..

No commits in common. "8791b08c4f3ba31d0dd1e9f83f8f01c1a8647b61" and "cd2bc321cd9254205345b5723613e1b0b7a2b6da" have entirely different histories.

11 changed files with 118 additions and 337 deletions

View file

@ -1,3 +0,0 @@
app_id = "de.j4ne.Paket"
icons = ["plus", "minus"]

View file

@ -1,6 +1,5 @@
use num_enum::TryFromPrimitive;
use uuid::Uuid;
use super::utils::{PrimitiveBuilder, PrimitiveReader};
use crate::{LibraryError, LibraryResult};
@ -82,6 +81,104 @@ pub struct Command {
metadata: Vec<u8>
}
struct PrimitiveBuilder {
bin: Vec<u8>,
}
impl PrimitiveBuilder {
fn new() -> Self {
PrimitiveBuilder {
bin: Vec::new()
}
}
fn write_u8(self, number: u8) -> Self {
self.write_array(&[number])
}
fn write_u16(self, number: u16) -> Self {
self.write_array(&number.to_be_bytes())
}
fn write_u32(self, number: u32) -> Self {
self.write_array(&number.to_be_bytes())
}
fn write_array(mut self, new: &[u8]) -> Self {
for b in new {
self.bin.push(*b);
}
self
}
fn write_array_with_len(self, bin: &[u8]) -> Self {
self
.write_u32(bin.len() as u32)
.write_array(bin)
}
fn finish(self) -> Vec<u8> {
self.bin
}
}
struct PrimitiveReader<'a> {
offset: usize,
vec: &'a [u8],
}
// Yes, I know Cursor exists and eio exists. from_be_bytes should be a stdlib trait tho.
impl<'a> PrimitiveReader<'a> {
fn read_u8(&mut self) -> u8 {
let number = self.vec[self.offset];
self.offset += 1;
number
}
fn read_u16(&mut self) -> u16 {
let arr: [u8; 2] = self.read_arr_const();
u16::from_be_bytes(arr)
}
fn read_u32(&mut self) -> u32 {
let arr: [u8; 4] = self.read_arr_const();
u32::from_be_bytes(arr)
}
fn read_u64(&mut self) -> u64 {
let arr: [u8; 8] = self.read_arr_const();
u64::from_be_bytes(arr)
}
fn read_arr_const<const N: usize>(&mut self) -> [u8; N] {
let mut arr = [0u8; N];
for n in 0..N {
arr[n] = self.read_u8();
}
return arr;
}
fn read_arr(&mut self, n: usize) -> Vec<u8> {
let mut arr: Vec<u8> = vec![];
for _ in 0..n {
arr.push(self.read_u8());
}
arr
}
fn read_arr_from_len(&mut self) -> Vec<u8> {
let size = self.read_u32() as usize;
self.read_arr(size)
}
fn left_to_process(&self) -> usize {
self.vec.len() - self.offset
}
}
impl Command {
fn checksum(bin: &[u8]) -> u16 {
// CRC16 of some kind...

View file

@ -1,24 +1,13 @@
#[cfg(feature = "locker_ble")]
#[cfg(feature = "unstable")]
mod command;
#[cfg(feature = "locker_ble")]
#[cfg(feature = "unstable")]
mod types;
#[cfg(feature = "locker_ble")]
#[cfg(feature = "unstable")]
pub use types::*;
#[cfg(feature = "locker_ble")]
#[cfg(feature = "unstable")]
mod api;
#[cfg(feature = "locker_ble")]
#[cfg(feature = "unstable")]
pub use api::*;
pub mod crypto;
pub(crate) mod utils;
#[cfg(feature = "locker_register_base")]
mod register_base;
#[cfg(feature = "locker_register_regtoken")]

View file

@ -1,107 +1,23 @@
use btleplug::platform::PeripheralId;
use super::utils::PrimitiveReader;
use crate::{LibraryError, LibraryResult};
use crate::LibraryError;
// 601e7028-0565-
pub static LOCKER_SERVICE_UUID_PREFIX: (u32, u16) = (0x601e7028, 0x0565);
pub enum LockerVendor {
Keba,
Snbc,
Unknown,
}
impl From<u8> for LockerVendor {
fn from(value: u8) -> Self {
if value == 1 {
Self::Keba
} else if value == 2 {
Self::Snbc
} else {
Self::Unknown
}
}
}
#[derive(Debug)]
pub struct LockerVersion {
pub tlv_version: u8,
pub vendor: u8,
pub major: u8,
pub minor: u8,
}
#[derive(Debug)]
pub struct LockerDevice {
pub id: PeripheralId,
pub service_uuid: LockerServiceUUID,
pub version: LockerVersion,
}
impl LockerDevice {
pub(crate) fn new(
id: PeripheralId,
service_uuid: LockerServiceUUID,
service_data: &Vec<u8>,
) -> LibraryResult<Self> {
mini_assert_inval!(service_data.len() == 14);
let mut reader = PrimitiveReader {
offset: 0,
vec: &service_data,
};
let version = LockerVersion {
tlv_version: reader.read_u8(),
vendor: reader.read_u8(),
major: reader.read_u8(),
minor: reader.read_u8(),
};
let part1: u16 = reader.read_u16();
let part2: u16 = reader.read_u16();
let part_last = reader.read_u32();
assert_eq!(reader.left_to_process(), 0);
println!(
"decoded: {:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>8x}",
LOCKER_SERVICE_UUID_PREFIX.0, LOCKER_SERVICE_UUID_PREFIX.1, part1, part2, part_last
);
println!("expected: {:?}", service_uuid);
Ok(LockerDevice {
id,
service_uuid,
version,
})
}
}
#[derive(Debug)]
pub struct LockerServiceUUID {
service_uuid: uuid::Uuid,
}
impl LockerServiceUUID {
pub fn get(&self) -> &uuid::Uuid {
&self.service_uuid
}
}
impl TryFrom<uuid::Uuid> for LockerServiceUUID {
type Error = crate::LibraryError;
fn try_from(value: uuid::Uuid) -> LibraryResult<Self> {
fn try_from(value: uuid::Uuid) -> Result<Self, Self::Error> {
let fields = value.as_fields();
if fields.0 != LOCKER_SERVICE_UUID_PREFIX.0 || fields.1 != LOCKER_SERVICE_UUID_PREFIX.1 {
return Err(LibraryError::InvalidArgument(
"TryFrom<Uuid> for LockerServiceUUID: prefix mismatch (expected 601e7028-0565-)"
.to_string(),
));
return Err(LibraryError::InvalidArgument("TryFrom<Uuid> for LockerServiceUUID: prefix mismatch (expected 601e7028-0565-)".to_string()))
}
Ok(LockerServiceUUID {
service_uuid: value,
service_uuid: value
})
}
}

View file

@ -1,93 +0,0 @@
pub(crate) struct PrimitiveBuilder {
pub bin: Vec<u8>,
}
impl PrimitiveBuilder {
pub(crate) fn new() -> Self {
PrimitiveBuilder { bin: Vec::new() }
}
pub(crate) fn write_u8(self, number: u8) -> Self {
self.write_array(&[number])
}
pub(crate) fn write_u16(self, number: u16) -> Self {
self.write_array(&number.to_be_bytes())
}
pub(crate) fn write_u32(self, number: u32) -> Self {
self.write_array(&number.to_be_bytes())
}
pub(crate) fn write_array(mut self, new: &[u8]) -> Self {
for b in new {
self.bin.push(*b);
}
self
}
pub(crate) fn write_array_with_len(self, bin: &[u8]) -> Self {
self.write_u32(bin.len() as u32).write_array(bin)
}
pub(crate) fn finish(self) -> Vec<u8> {
self.bin
}
}
pub(crate) struct PrimitiveReader<'a> {
pub offset: usize,
pub vec: &'a [u8],
}
// Yes, I know Cursor exists and eio exists. from_be_bytes should be a stdlib trait tho.
impl<'a> PrimitiveReader<'a> {
pub(crate) fn read_u8(&mut self) -> u8 {
let number = self.vec[self.offset];
self.offset += 1;
number
}
pub(crate) fn read_u16(&mut self) -> u16 {
let arr: [u8; 2] = self.read_arr_const();
u16::from_be_bytes(arr)
}
pub(crate) fn read_u32(&mut self) -> u32 {
let arr: [u8; 4] = self.read_arr_const();
u32::from_be_bytes(arr)
}
pub(crate) fn read_u64(&mut self) -> u64 {
let arr: [u8; 8] = self.read_arr_const();
u64::from_be_bytes(arr)
}
pub(crate) fn read_arr_const<const N: usize>(&mut self) -> [u8; N] {
let mut arr = [0u8; N];
for n in 0..N {
arr[n] = self.read_u8();
}
return arr;
}
pub(crate) fn read_arr(&mut self, n: usize) -> Vec<u8> {
let mut arr: Vec<u8> = vec![];
for _ in 0..n {
arr.push(self.read_u8());
}
arr
}
pub(crate) fn read_arr_from_len(&mut self) -> Vec<u8> {
let size = self.read_u32() as usize;
self.read_arr(size)
}
pub(crate) fn left_to_process(&self) -> usize {
self.vec.len() - self.offset
}
}

View file

@ -9,7 +9,7 @@ pub use self::openid_response::{RefreshToken, TokenResponse};
pub use self::utils::{create_nonce, CodeVerfier};
use super::common::APIResult;
use crate::LibraryResult;
use crate::{LibraryError, LibraryResult};
pub struct OpenIdClient {
client: reqwest::Client,

View file

@ -82,9 +82,9 @@ struct SendungsInfo {
sendungsliste: Option<String>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendungsVerlaufEvent {
struct SendungsVerlaufEvent {
pub datum: String,
ort: Option<String>,
pub ruecksendung: bool,
@ -102,18 +102,18 @@ impl SendungsVerlaufEvent {
}
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendungsVerlauf {
struct SendungsVerlauf {
kurz_status: Option<String>,
icon_id: Option<String>,
datum_aktueller_status: Option<String>,
aktueller_status: Option<String>,
pub events: Option<Vec<SendungsVerlaufEvent>>,
events: Option<Vec<SendungsVerlaufEvent>>,
farbe: u32,
pub fortschritt: u32,
pub maximal_fortschritt: u32,
fortschritt: u32,
maximal_fortschritt: u32,
}
#[derive(Deserialize)]
@ -321,7 +321,6 @@ pub struct Shipment {
pub special: ShipmentSpecialDetails,
pub history: SendungsVerlauf,
pub error: Option<ShipmentNotFoundError>,
}
@ -368,7 +367,6 @@ impl From<Sendung> for Shipment {
None
}
},
history: value.sendungsdetails.sendungsverlauf,
special: ShipmentSpecialDetails {
abholcode_available,
benachrichtigt_in_filiale,

View file

@ -16,4 +16,3 @@ reqwest = "0.12"
libpaket = { path = "../libpaket" }
glycin = { version = "2.0.0-beta", features = ["gdk4"] }
oo7 = { version = "0.3" }
relm4-icons = { version = "0.9" }

View file

@ -49,7 +49,6 @@ impl FactoryComponent for AppAdvice {
add_overlay = &gtk::Box {
add_css_class: relm4::css::OSD,
add_css_class: relm4::css::TOOLBAR,
add_css_class: relm4::css::NUMERIC,
set_valign: gtk::Align::End,
@ -58,6 +57,8 @@ impl FactoryComponent for AppAdvice {
set_margin_all: 8,
gtk::Label {
set_margin_all: 4,
set_label: self.metadata.date.as_str(),
},
},

View file

@ -3,7 +3,6 @@ use std::sync::Arc;
use login::{Login, LoginOutput, LoginSharedState};
use ready::{Ready, ReadyOutput};
use relm4::{
RELM_THREADS,
adw, gtk, main_adw_application, prelude::*, tokio::sync::Mutex,
AsyncComponentSender, SharedState,
};
@ -290,13 +289,6 @@ fn convert_ready_response(response: ReadyOutput) -> AppInput {
}
fn main() {
RELM_THREADS.set(4).unwrap();
gtk::init().unwrap();
let display = gtk::gdk::Display::default().unwrap();
let theme = gtk::IconTheme::for_display(&display);
theme.add_resource_path("/de/j4ne/Paket/icons/");
theme.add_resource_path("/de/j4ne/Paket/scalable/actions/");
relm4_icons::initialize_icons();
let app = RelmApp::new(constants::APP_ID);
app.run_async::<App>(());
}

View file

@ -6,20 +6,6 @@ use relm4::{adw, gtk};
pub struct ShipmentView {
model: Shipment,
// model abstraction
have_events: bool,
// state
expanded: bool,
// workarounds
list_box_history: gtk::ListBox,
}
#[derive(Debug)]
pub enum ViewInput {
ToggleExpand,
}
#[relm4::factory(pub)]
@ -27,7 +13,7 @@ impl FactoryComponent for ShipmentView {
type CommandOutput = ();
type Init = Shipment;
type Output = ();
type Input = ViewInput;
type Input = ();
type ParentWidget = gtk::Box;
type Index = String;
@ -37,26 +23,14 @@ impl FactoryComponent for ShipmentView {
add_css_class: relm4::css::CARD,
set_hexpand: true,
set_margin_all: 8,
set_orientation: gtk::Orientation::Vertical,
gtk::ProgressBar {
add_css_class: relm4::css::OSD,
set_margin_start: 8,
set_margin_end: 8,
set_margin_bottom: 1,
set_fraction: f64::from(self.model.history.maximal_fortschritt) / f64::from(self.model.history.fortschritt),
},
// title box
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_orientation: gtk::Orientation::Vertical,
set_margin_all: 8,
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_hexpand: true,
set_halign: gtk::Align::Start,
gtk::Label {
@ -87,52 +61,9 @@ impl FactoryComponent for ShipmentView {
}
}
}
},
gtk::Button {
set_halign: gtk::Align::End,
add_css_class: relm4::css::FLAT,
#[watch]
set_icon_name: {
if self.expanded {
relm4_icons::icon_names::MINUS
} else {
relm4_icons::icon_names::PLUS
}
},
connect_clicked => ViewInput::ToggleExpand,
}
}, // title box end
gtk::Revealer {
#[watch]
set_reveal_child: self.expanded,
#[wrap(Some)]
set_child = &gtk::Box {
// history viewstack
adw::StatusPage {
set_visible: !self.have_events,
set_title: "No events",
},
append = &self.list_box_history.clone() {
set_visible: self.have_events,
add_css_class: relm4::css::BOXED_LIST,
set_selection_mode: gtk::SelectionMode::None,
},
}
},
}
}
fn init_model(
@ -140,54 +71,8 @@ impl FactoryComponent for ShipmentView {
index: &Self::Index,
sender: relm4::FactorySender<Self>,
) -> Self {
let have_events = init.history.events.as_ref().is_some_and(|a| a.len() > 0);
let model = ShipmentView { model: init };
let list_box_history = gtk::ListBox::new();
let _self = ShipmentView {
have_events,
model: init,
list_box_history,
expanded: false,
};
for elem in _self.model.history.events.as_ref().unwrap() {
let label_datum = gtk::Label::builder()
.css_classes([relm4::css::NUMERIC])
.label(&elem.datum)
.halign(gtk::Align::Start)
.valign(gtk::Align::Start)
.build();
// TODO: is html, parse it
let label_status = gtk::Label::builder()
.wrap(true)
.halign(gtk::Align::Start)
.valign(gtk::Align::Start)
.build();
label_status.set_markup(&elem.status);
let boxie = gtk::Box::builder()
.orientation(gtk::Orientation::Horizontal)
.margin_start(8)
.margin_end(8)
.spacing(8)
.build();
boxie.append(&label_datum);
boxie.append(&label_status);
_self.list_box_history.append(&boxie);
}
_self
}
fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
match message {
ViewInput::ToggleExpand => {
self.expanded = !self.expanded;
}
}
model
}
}