feat: add first attempt for Sendungsverfolgung api
This commit is contained in:
parent
912f024163
commit
b36f7843f0
5 changed files with 531 additions and 3 deletions
|
@ -36,9 +36,12 @@ thiserror = "1.0.56"
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = [
|
||||||
"advices",
|
"advices",
|
||||||
"locker_all"
|
"locker_all",
|
||||||
|
"unstable",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
unstable = []
|
||||||
|
|
||||||
advices = [
|
advices = [
|
||||||
#"dep:sha2",
|
#"dep:sha2",
|
||||||
"dep:uuid",
|
"dep:uuid",
|
||||||
|
@ -74,4 +77,4 @@ locker_register_base = [
|
||||||
|
|
||||||
locker_register_regtoken = [
|
locker_register_regtoken = [
|
||||||
"locker_register_base"
|
"locker_register_base"
|
||||||
]
|
]
|
||||||
|
|
|
@ -21,6 +21,9 @@ pub mod advices;
|
||||||
#[cfg(feature = "advices")]
|
#[cfg(feature = "advices")]
|
||||||
pub use advices::AdviceClient;
|
pub use advices::AdviceClient;
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable")]
|
||||||
|
pub mod tracking;
|
||||||
|
|
||||||
/*#[cfg(test)]
|
/*#[cfg(test)]
|
||||||
pub(crate) mod private;*/
|
pub(crate) mod private;*/
|
||||||
|
|
||||||
|
@ -66,4 +69,4 @@ impl From<serde_json::Error> for LibraryError {
|
||||||
fn from(value: serde_json::Error) -> Self {
|
fn from(value: serde_json::Error) -> Self {
|
||||||
Self::DecodeError(value.to_string())
|
Self::DecodeError(value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
440
libpaket/src/tracking.rs
Normal file
440
libpaket/src/tracking.rs
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{login::DHLIdToken, LibraryResult};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TrackingParams {
|
||||||
|
pub language: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct ShipmentRequest {
|
||||||
|
international: bool,
|
||||||
|
piececode: String,
|
||||||
|
zip: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::WebClient {
|
||||||
|
pub async fn tracking_search(
|
||||||
|
&self,
|
||||||
|
params: TrackingParams,
|
||||||
|
ids: Vec<String>,
|
||||||
|
dhli: Option<&DHLIdToken>,
|
||||||
|
) -> LibraryResult<Vec<Shipment>> {
|
||||||
|
let api_key = crate::www::api_key_header();
|
||||||
|
let res = if let Some(dhli) = dhli {
|
||||||
|
let cookie_value = crate::utils::CookieHeaderValueBuilder::new()
|
||||||
|
.add_dhli(&dhli)
|
||||||
|
.add_dhlcs(&dhli)
|
||||||
|
.build_string();
|
||||||
|
request!(
|
||||||
|
self.web_client,
|
||||||
|
endpoint_data_search,
|
||||||
|
query(&query_parameters_data_search(¶ms, ids)),
|
||||||
|
header(api_key.0, api_key.1),
|
||||||
|
header("Cookie", cookie_value)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
request!(
|
||||||
|
self.web_client,
|
||||||
|
endpoint_data_search,
|
||||||
|
query(&query_parameters_data_search(¶ms, ids)),
|
||||||
|
header(api_key.0, api_key.1)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let resp = parse_json_response!(res, Response);
|
||||||
|
Ok(resp.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn tracking_shipment(
|
||||||
|
&self,
|
||||||
|
params: TrackingParams,
|
||||||
|
body: ShipmentRequest,
|
||||||
|
) -> LibraryResult<Vec<Shipment>> {
|
||||||
|
let api_key = crate::www::api_key_header();
|
||||||
|
let res = request_json!(
|
||||||
|
self.web_client,
|
||||||
|
endpoint_data_shipment,
|
||||||
|
body,
|
||||||
|
query(&query_parameters_data_shipment(¶ms)),
|
||||||
|
header(api_key.0, api_key.1)
|
||||||
|
);
|
||||||
|
|
||||||
|
let resp = parse_json_response!(res, Response);
|
||||||
|
Ok(resp.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungEmpfaenger {
|
||||||
|
name: String,
|
||||||
|
ort: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungsInfo {
|
||||||
|
gesuchte_sendungsnummer: String,
|
||||||
|
sendungsrichtung: String,
|
||||||
|
sendungsname: Option<String>,
|
||||||
|
sendungsliste: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungsVerlaufEvent {
|
||||||
|
pub datum: String,
|
||||||
|
ort: Option<String>,
|
||||||
|
pub ruecksendung: bool,
|
||||||
|
pub status: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SendungsVerlaufEvent {
|
||||||
|
fn get_ort(&self) -> Option<String> {
|
||||||
|
if let Some(ort) = self.ort.as_ref() {
|
||||||
|
if ort.len() > 0 {
|
||||||
|
return Some(ort.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungsVerlauf {
|
||||||
|
kurz_status: Option<String>,
|
||||||
|
icon_id: Option<String>,
|
||||||
|
datum_aktueller_status: Option<String>,
|
||||||
|
aktueller_status: Option<String>,
|
||||||
|
events: Option<Vec<SendungsVerlaufEvent>>,
|
||||||
|
|
||||||
|
farbe: u32,
|
||||||
|
fortschritt: u32,
|
||||||
|
maximal_fortschritt: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungZustellung {
|
||||||
|
abholcode_available: Option<bool>, // probably always there
|
||||||
|
benachrichtigt_in_filiale: Option<bool>, // probably always there
|
||||||
|
zustellzeitfenster_bis: Option<String>,
|
||||||
|
zustellzeitfenster_von: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungServices {
|
||||||
|
statusbenachrichtigung: SendungServiceStatusBenachrichtigung,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungServiceStatusBenachrichtigung {
|
||||||
|
aktueller_status: Option<bool>,
|
||||||
|
erfolgte_zustellung: Option<bool>,
|
||||||
|
geplante_zustellung: Option<bool>,
|
||||||
|
authentication_required: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
|
pub enum SendungsQuelle {
|
||||||
|
TTBRIEF,
|
||||||
|
PAKET,
|
||||||
|
SVB,
|
||||||
|
OPTIMA,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Nachhaltigkeitsstatus {
|
||||||
|
bahnpaket: bool,
|
||||||
|
co2_freie_zustellung: bool,
|
||||||
|
gg_versender: bool,
|
||||||
|
ggp_empfaenger: bool,
|
||||||
|
ggp_versender: bool,
|
||||||
|
klimafreundlicher_empfang: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungDetails {
|
||||||
|
quelle: SendungsQuelle, // PAKET
|
||||||
|
express_sendung: Option<bool>,
|
||||||
|
is_shipper_plz: Option<bool>,
|
||||||
|
ist_zugestellt: Option<bool>,
|
||||||
|
retoure: Option<bool>,
|
||||||
|
ruecksendung: Option<bool>,
|
||||||
|
sendungsverlauf: SendungsVerlauf,
|
||||||
|
show_quality_level_hint: Option<bool>,
|
||||||
|
two_man_handling: Option<bool>,
|
||||||
|
unplausibel: Option<bool>,
|
||||||
|
mehr_informationen_verfuegbar: Option<bool>,
|
||||||
|
|
||||||
|
nachhaltigkeitsstatus: Option<Nachhaltigkeitsstatus>,
|
||||||
|
brief_sendung: Option<bool>,
|
||||||
|
invalid_time_of_day: Option<bool>,
|
||||||
|
bahnpaket: Option<bool>,
|
||||||
|
email: Option<String>,
|
||||||
|
international: Option<bool>,
|
||||||
|
pan_empfaenger: Option<SendungEmpfaenger>,
|
||||||
|
produkt_name: Option<String>,
|
||||||
|
//sendungsnummern: (),
|
||||||
|
services: Option<SendungServiceStatusBenachrichtigung>,
|
||||||
|
show_digital_notification_cta_hint: Option<bool>,
|
||||||
|
warenpost: Option<bool>,
|
||||||
|
zielland: Option<String>, // localized string?
|
||||||
|
zustellung: Option<SendungZustellung>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ShipmentNotFoundError {
|
||||||
|
pub no_data_available: bool,
|
||||||
|
pub not_from_dhl: bool,
|
||||||
|
pub id_invalid: bool,
|
||||||
|
pub letter_not_found: bool,
|
||||||
|
pub data_to_old: bool,
|
||||||
|
pub id_not_searchable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct SendungNichtGefunden {
|
||||||
|
keine_daten_verfuegbar: Option<bool>,
|
||||||
|
keine_dhl_paket_sendung: Option<bool>,
|
||||||
|
sendungsnummer_ungueltig: Option<bool>,
|
||||||
|
brief_nicht_gefunden: Option<bool>,
|
||||||
|
sendungsdaten_zu_alt: Option<bool>,
|
||||||
|
sendungsnummer_nicht_suchbar: Option<bool>,
|
||||||
|
fehlertext: Option<String>,
|
||||||
|
fehlertextApp: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Sendung {
|
||||||
|
id: String,
|
||||||
|
has_complete_details: bool,
|
||||||
|
sendung_nicht_gefunden: Option<SendungNichtGefunden>,
|
||||||
|
sendungsdetails: SendungDetails,
|
||||||
|
sendungsinfo: SendungsInfo,
|
||||||
|
versand_datum_benoetigt: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct Response {
|
||||||
|
sendungen: Vec<Sendung>,
|
||||||
|
// TODO: parse RECEIVE_MERGED_SHIPMENTS, what is that?
|
||||||
|
//merged_anonymous_shipment_list_ids: Option<Vec<()>>,
|
||||||
|
is_rate_limited: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SendungNichtGefunden> for ShipmentNotFoundError {
|
||||||
|
fn from(value: SendungNichtGefunden) -> Self {
|
||||||
|
Self {
|
||||||
|
no_data_available: optional_default_false(value.keine_daten_verfuegbar),
|
||||||
|
not_from_dhl: optional_default_false(value.keine_dhl_paket_sendung),
|
||||||
|
id_invalid: optional_default_false(value.sendungsnummer_ungueltig),
|
||||||
|
letter_not_found: optional_default_false(value.brief_nicht_gefunden),
|
||||||
|
data_to_old: optional_default_false(value.sendungsdaten_zu_alt),
|
||||||
|
id_not_searchable: optional_default_false(value.sendungsnummer_nicht_suchbar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Nachhaltigkeitsstatus> for Vec<GoGreenWashing> {
|
||||||
|
fn from(value: Nachhaltigkeitsstatus) -> Self {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
|
||||||
|
if value.bahnpaket {
|
||||||
|
out.push(GoGreenWashing::ShippedByRailway);
|
||||||
|
}
|
||||||
|
if value.co2_freie_zustellung {
|
||||||
|
out.push(GoGreenWashing::CO2FreeSupposedly);
|
||||||
|
}
|
||||||
|
if value.gg_versender {
|
||||||
|
out.push(GoGreenWashing::GoGreenwashingByShipper);
|
||||||
|
}
|
||||||
|
if value.ggp_empfaenger {
|
||||||
|
out.push(GoGreenWashing::GoGreenwashingPlusByRecipient);
|
||||||
|
}
|
||||||
|
if value.ggp_versender {
|
||||||
|
out.push(GoGreenWashing::GoGreenwashingPlusByShipper);
|
||||||
|
}
|
||||||
|
if value.klimafreundlicher_empfang {
|
||||||
|
out.push(GoGreenWashing::SupposedlyClimateFriendlyReception);
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GoGreenWashing {
|
||||||
|
ShippedByRailway,
|
||||||
|
CO2FreeSupposedly,
|
||||||
|
GoGreenwashingByShipper,
|
||||||
|
GoGreenwashingPlusByShipper,
|
||||||
|
GoGreenwashingPlusByRecipient,
|
||||||
|
SupposedlyClimateFriendlyReception,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ShipmentSpecialDetails {
|
||||||
|
abholcode_available: bool,
|
||||||
|
benachrichtigt_in_filiale: bool,
|
||||||
|
|
||||||
|
zustellzeitfenster_bis: Option<String>,
|
||||||
|
zustellzeitfenster_von: Option<String>,
|
||||||
|
railway_shipment: Option<bool>,
|
||||||
|
express_shipment: Option<bool>,
|
||||||
|
warenpost: Option<bool>,
|
||||||
|
retoure: Option<bool>,
|
||||||
|
ruecksendung: Option<bool>,
|
||||||
|
two_man_handling: Option<bool>,
|
||||||
|
unplausibel: Option<bool>,
|
||||||
|
target_country: Option<String>,
|
||||||
|
recipient: Option<SendungEmpfaenger>,
|
||||||
|
pub product_name: Option<String>,
|
||||||
|
pub shipment_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Shipment {
|
||||||
|
pub id: String,
|
||||||
|
|
||||||
|
pub api_has_complete_details: bool,
|
||||||
|
|
||||||
|
pub needs_shipment_date: bool,
|
||||||
|
pub needs_plz: bool,
|
||||||
|
|
||||||
|
pub quelle: SendungsQuelle,
|
||||||
|
|
||||||
|
// probably not optional
|
||||||
|
pub international: Option<bool>,
|
||||||
|
// probably not optional
|
||||||
|
pub has_shipped: Option<bool>,
|
||||||
|
|
||||||
|
pub special: ShipmentSpecialDetails,
|
||||||
|
|
||||||
|
pub error: Option<ShipmentNotFoundError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn optional_default_false(value: Option<bool>) -> bool {
|
||||||
|
if let Some(value) = value {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sendung> for Shipment {
|
||||||
|
fn from(value: Sendung) -> Self {
|
||||||
|
let (
|
||||||
|
abholcode_available,
|
||||||
|
benachrichtigt_in_filiale,
|
||||||
|
zustellzeitfenster_bis,
|
||||||
|
zustellzeitfenster_von,
|
||||||
|
) = {
|
||||||
|
if let Some(zustellung) = value.sendungsdetails.zustellung {
|
||||||
|
(
|
||||||
|
optional_default_false(zustellung.abholcode_available),
|
||||||
|
optional_default_false(zustellung.benachrichtigt_in_filiale),
|
||||||
|
zustellung.zustellzeitfenster_bis,
|
||||||
|
zustellung.zustellzeitfenster_von,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(false, false, None, None)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
id: value.id,
|
||||||
|
api_has_complete_details: value.has_complete_details,
|
||||||
|
needs_shipment_date: value.versand_datum_benoetigt,
|
||||||
|
needs_plz: optional_default_false(value.sendungsdetails.mehr_informationen_verfuegbar),
|
||||||
|
international: value.sendungsdetails.international,
|
||||||
|
has_shipped: value.sendungsdetails.ist_zugestellt,
|
||||||
|
quelle: value.sendungsdetails.quelle,
|
||||||
|
error: {
|
||||||
|
if let Some(err) = value.sendung_nicht_gefunden {
|
||||||
|
Some(err.into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
special: ShipmentSpecialDetails {
|
||||||
|
abholcode_available,
|
||||||
|
benachrichtigt_in_filiale,
|
||||||
|
zustellzeitfenster_bis,
|
||||||
|
zustellzeitfenster_von,
|
||||||
|
shipment_name: value.sendungsinfo.sendungsname,
|
||||||
|
railway_shipment: value.sendungsdetails.bahnpaket,
|
||||||
|
express_shipment: value.sendungsdetails.express_sendung,
|
||||||
|
warenpost: value.sendungsdetails.warenpost,
|
||||||
|
retoure: value.sendungsdetails.retoure,
|
||||||
|
ruecksendung: value.sendungsdetails.ruecksendung,
|
||||||
|
two_man_handling: value.sendungsdetails.two_man_handling,
|
||||||
|
unplausibel: value.sendungsdetails.unplausibel,
|
||||||
|
target_country: value.sendungsdetails.zielland,
|
||||||
|
recipient: value.sendungsdetails.pan_empfaenger,
|
||||||
|
product_name: value.sendungsdetails.produkt_name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Response> for Vec<Shipment> {
|
||||||
|
fn from(value: Response) -> Self {
|
||||||
|
let mut arr = Vec::new();
|
||||||
|
|
||||||
|
for item in value.sendungen {
|
||||||
|
arr.push(item.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
arr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endpoint_data_search() -> &'static str {
|
||||||
|
"https://www.dhl.de/int-verfolgen/data/search"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_parameters_data_search(
|
||||||
|
params: &TrackingParams,
|
||||||
|
mut shippingnumbers: Vec<String>,
|
||||||
|
) -> Vec<(String, String)> {
|
||||||
|
let mut out = vec![("noRedirect".to_string(), "true".to_string())];
|
||||||
|
|
||||||
|
if let Some(lang) = params.language.as_ref() {
|
||||||
|
out.push(("language".to_string(), lang.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if shippingnumbers.len() > 0 {
|
||||||
|
let mut shippingnumbers_string = shippingnumbers.pop().unwrap();
|
||||||
|
for number in shippingnumbers {
|
||||||
|
shippingnumbers_string = format!(",{}", number);
|
||||||
|
}
|
||||||
|
out.push(("piececode".to_string(), shippingnumbers_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endpoint_data_shipment() -> &'static str {
|
||||||
|
"https://www.dhl.de/int-verfolgen/data/shipment"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_parameters_data_shipment(params: &TrackingParams) -> Vec<(String, String)> {
|
||||||
|
let mut out = vec![];
|
||||||
|
|
||||||
|
if let Some(lang) = params.language.as_ref() {
|
||||||
|
out.push(("language".to_string(), lang.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
|
@ -44,6 +44,10 @@ pub(crate) fn authorized_credentials() -> (&'static str, &'static str) {
|
||||||
("erkennen", "8XRUfutM8PTvUz3A")
|
("erkennen", "8XRUfutM8PTvUz3A")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn api_key_header() -> (&'static str, &'static str) {
|
||||||
|
("x-api-key", "a0d5b9049ba8918871e6e20bd5c49974")
|
||||||
|
}
|
||||||
|
|
||||||
// "/int-push/", "X-APIKey", "5{@8*nB=?\\.@t,XwWK>Y[=yY^*Y8&myzDE7_"
|
// "/int-push/", "X-APIKey", "5{@8*nB=?\\.@t,XwWK>Y[=yY^*Y8&myzDE7_"
|
||||||
// /int-stammdaten/", null, "zAuoC3%7*qbRVmiXdNGyYz9iJ7N@Ph3Cw4zV"
|
// /int-stammdaten/", null, "zAuoC3%7*qbRVmiXdNGyYz9iJ7N@Ph3Cw4zV"
|
||||||
// "/int-verfolgen/data/packstation/v2/", null, "a0d5b9049ba8918871e6e20bd5c49974",
|
// "/int-verfolgen/data/packstation/v2/", null, "a0d5b9049ba8918871e6e20bd5c49974",
|
||||||
|
|
78
paket/src/tracking.rs
Normal file
78
paket/src/tracking.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use adw::prelude::*;
|
||||||
|
use libpaket::tracking::Shipment;
|
||||||
|
use relm4::factory::FactoryComponent;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
use relm4::{adw, gtk};
|
||||||
|
|
||||||
|
pub struct ShipmentView {
|
||||||
|
model: Shipment,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::factory(pub)]
|
||||||
|
impl FactoryComponent for ShipmentView {
|
||||||
|
type CommandOutput = ();
|
||||||
|
type Init = Shipment;
|
||||||
|
type Output = ();
|
||||||
|
type Input = ();
|
||||||
|
type ParentWidget = gtk::Box;
|
||||||
|
type Index = String;
|
||||||
|
|
||||||
|
view! {
|
||||||
|
#[root]
|
||||||
|
gtk::Box {
|
||||||
|
add_css_class: relm4::css::CARD,
|
||||||
|
set_hexpand: true,
|
||||||
|
set_margin_all: 8,
|
||||||
|
|
||||||
|
// title box
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_margin_all: 8,
|
||||||
|
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_halign: gtk::Align::Start,
|
||||||
|
|
||||||
|
gtk::Label {
|
||||||
|
add_css_class: relm4::css::NUMERIC,
|
||||||
|
add_css_class: relm4::css::CAPTION_HEADING,
|
||||||
|
set_halign: gtk::Align::Start,
|
||||||
|
|
||||||
|
set_label: &self.model.id,
|
||||||
|
},
|
||||||
|
|
||||||
|
gtk::Label {
|
||||||
|
add_css_class: relm4::css::HEADING,
|
||||||
|
set_halign: gtk::Align::Start,
|
||||||
|
|
||||||
|
set_label: {
|
||||||
|
// TODO: gettext
|
||||||
|
if let Some(shipment_name) = &self.model.special.shipment_name {
|
||||||
|
shipment_name.as_str()
|
||||||
|
} else if let Some(product_name) = &self.model.special.product_name {
|
||||||
|
product_name.as_str()
|
||||||
|
} else {
|
||||||
|
match self.model.quelle {
|
||||||
|
libpaket::tracking::SendungsQuelle::TTBRIEF => "Letter",
|
||||||
|
libpaket::tracking::SendungsQuelle::PAKET => "Parcel",
|
||||||
|
libpaket::tracking::SendungsQuelle::SVB => "quelle: SVB",
|
||||||
|
libpaket::tracking::SendungsQuelle::OPTIMA => "quelle: OPTIMA",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_model(
|
||||||
|
init: Self::Init,
|
||||||
|
index: &Self::Index,
|
||||||
|
sender: relm4::FactorySender<Self>,
|
||||||
|
) -> Self {
|
||||||
|
let model = ShipmentView { model: init };
|
||||||
|
|
||||||
|
model
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue