1. Où vit le code ?
assets/station_s/
+- include/app/ui/geomail/
¦ +- obb_geomail_threads.h ? structures & API de file
+- src/app/ui/geomail/
+- obb_geomail_threads.cpp ? logique FIFO + confirmations
Les handlers réseau/storage restent dans d'autres modules privés ; on expose ici la partie UI/queue.
Placeholder : un futur schéma montrera comment les messages passent de la file à LVGL.
2. File GeoMail locale
La file conserve les messages normalisés (texte + hash d'image). Extrait :
struct GeoMailMessage {
std::string mailbox; // Mairie, Home, Proxy1...
std::string human_id; // CVCV-123456
std::string alias; // prenom.nom.diff@...
std::string pseudo; // affiché côté UI
std::string subject;
std::string subject_long; // champ signé blockchain
std::string body_preview;
std::string body_full;
std::vector<GeoAttachment> attachments;
uint32_t attachment_hash = 0;
uint32_t timestamp = 0;
uint8_t priority = 0;
uint8_t hop_count = 0;
bool requires_ack = false;
};
On transporte désormais la boîte source, les champs sujet long, le corps complet (si présent) et la liste de pièces jointes.
3. Limite & purge douce
void enqueue_message(const GeoMailMessage &msg) {
if (s_pending.size() >= kMaxBuffer) {
s_pending.pop_front(); // ancien message envoyé vers microSD
}
s_pending.push_back(msg);
}
Le buffer reste court (32 éléments) pour garantir une lecture fluide sur écran 3.5?. Le stockage long terme vit sur microSD.
4. Ce que voit l'utilisateur
std::vector<GeoMailMessage> snapshot_queue(std::size_t limit) {
std::vector<GeoMailMessage> out;
out.reserve(std::min(limit, s_pending.size()));
for (const auto &msg : s_pending) {
out.push_back(msg);
if (out.size() >= limit) break;
}
return out;
}
Cette fonction alimente la vue LVGL (lecture offline, priorité aux urgences) citée dans la section « Travaux en cours ».
5. Accusés (P0/P1)
void mark_acknowledged(uint32_t timestamp) {
s_pending.erase(std::remove_if(s_pending.begin(), s_pending.end(),
[&](const GeoMailMessage &msg) {
return msg.timestamp == timestamp;
}),
s_pending.end());
}
Une fois le message poussé sur la station H/K (ou signé par le maire), on supprime l'entrée locale - exactement ce que promet la page concept.
6. En-tête + machine détat UI
struct GeoMailHeader {
std::string pseudo;
std::string obid; // complet
std::string obid_short; // 4 derniers pour la liste
std::string subject_long; // signé dans la blockchain
uint32_t timestamp;
uint8_t priority; // 0..3
uint8_t hop_count;
};
enum class GeoMailView {
MAILBOX_SELECTION,
HEADER_LIST,
READING,
WRITING
};
La tuile 4 ne fait que passer dun état à lautre : icônes ? liste ? lecture ? écriture. Le header sélectionné reste « docké » en haut de lécran (2 lignes) pendant la lecture ou la rédaction.
7. Contacts avec pseudos et IDs
struct GeoContact {
std::string pseudo;
std::string obid;
std::vector<std::string> aliases; // prenom.nom.diff
std::vector<std::string> capabilities; // MAY, POL, ...
};
void add_contact(const GeoContact &contact) {
s_contacts[contact.obid] = contact;
}
Les pseudos sont libres, mais lID officialise la fiche. Reply/Forward coche simplement plusieurs GeoContact et récupère leurs OBID pour lenveloppe.
8. Pièces jointes non chiffrées
struct GeoAttachment {
std::string name;
uint32_t size_bytes;
std::string tag;
std::string source_mailbox; // mairie, proxy1...
};
bool move_to_device(const GeoAttachment &att) {
return geo_storage_copy(att, kDeviceInboxPath);
}
Pas de popup de destination : on copie directement vers le dossier prévu durant le setup (kDeviceInboxPath). Le regroupement par mail/contact/type/#tag nest quun filtre sur ce tableau.