From 11ca5019b5b6db2dc27e2fbe2ad87febdb704b94 Mon Sep 17 00:00:00 2001 From: Sofia Date: Thu, 4 Jun 2026 19:21:00 +0300 Subject: [PATCH] Add message listing and message reading states --- src/at_commands.rs | 14 +++---- src/states.rs | 101 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/src/at_commands.rs b/src/at_commands.rs index 7295c23..0b89f45 100644 --- a/src/at_commands.rs +++ b/src/at_commands.rs @@ -720,12 +720,12 @@ pub enum ListSMSMessagesResponse { #[derive(Debug, Clone)] pub struct SMSMessageListing { - index: u32, - stat: SMSMessageStat, - from_addr: String, - to_addr: String, - timestamp: String, - text: String, + pub index: u32, + pub stat: SMSMessageStat, + pub from_addr: String, + pub to_addr: String, + pub timestamp: String, + pub text: String, } impl ATResponse for ListSMSMessagesResponse { @@ -791,8 +791,8 @@ impl ATCommand for ListSMSMessages { let mut params = parser.params().unwrap(); let idx = params.read_u32().unwrap(); let stat = SMSMessageStat::from(¶ms.read_string().unwrap()); - let from_addr = params.read_string().unwrap(); let to_addr = params.read_string().unwrap(); + let from_addr = params.read_string().unwrap(); let timestamp = params.read_string().unwrap(); let mut message = String::new(); diff --git a/src/states.rs b/src/states.rs index 0a413f4..9078b46 100644 --- a/src/states.rs +++ b/src/states.rs @@ -5,6 +5,7 @@ use alloc::{ boxed::Box, format, string::{String, ToString}, + vec::Vec, }; use esp_hal::time::{Duration, Instant}; @@ -12,8 +13,9 @@ use crate::{ async_io::{ATPromise, KeypadButton, NumberInput, TextInput}, at_commands::{ ATCommand, ATError, ATInformationCommand, CheckPinCommand, CheckPinResult, EnterPinCommand, - EnterPinResult, ListSMSMessages, SMSFormat, SMSMessageStat, SelectSMSFormatCommand, - SendSMSCommand, SendSMSResponse, SetTECharsetCommand, SimpleATResponse, TECharset, + EnterPinResult, ListSMSMessages, ListSMSMessagesResponse, SMSFormat, SMSMessageListing, + SMSMessageStat, SelectSMSFormatCommand, SendSMSCommand, SendSMSResponse, + SetTECharsetCommand, SimpleATResponse, TECharset, }, display::{Position, Rgb565}, font::{HorizontalAlignment, VerticalAlignment}, @@ -339,18 +341,20 @@ impl State for MainMenuState { MainMenuItem::SendSMS => return Some(Box::new(PhoneNumberState::default())), MainMenuItem::ReadSMS => { return Some(Box::new(ATCommandState::with( - "Loading messages".to_owned(), + "Loading\nmessages".to_owned(), ListSMSMessages { stat: SMSMessageStat::All, }, |resp| match resp { - Ok(messages) => { - log::info!("{:?}", messages); - Box::new(TextState { - text: format!("Messages read"), + Ok(response) => match response { + ListSMSMessagesResponse::Ok(messages) => { + Box::new(ListSMSMessagesState::from(messages)) + } + ListSMSMessagesResponse::Error(err) => Box::new(TextState { + text: format!("Error:\n{:?}", err), after: MainMenuState::default(), - }) - } + }), + }, Err(err) => Box::new(TextState { text: format!("Error:\n{:?}", err), after: MainMenuState::default(), @@ -369,6 +373,85 @@ impl State for MainMenuState { } } +#[derive(Clone, Default)] +pub struct MessageListing { + from: String, + text: String, +} + +impl MenuItem for MessageListing { + fn as_text(&self) -> String { + format!("{}: {}", self.from, self.text) + } +} + +#[derive(Clone, Default)] +pub struct ListSMSMessagesState { + menu: Menu, +} + +impl ListSMSMessagesState { + pub fn from(messages: Vec) -> ListSMSMessagesState { + let mut menu = Menu::default(); + for message in &messages { + menu = menu.with_item(MessageListing { + from: message.from_addr.clone(), + text: message.text.clone(), + }) + } + + ListSMSMessagesState { menu } + } +} + +impl State for ListSMSMessagesState { + fn update(&mut self, data: &mut StateData) -> Option> { + if let Some(listing) = self.menu.poll(&mut data.io) { + return Some(Box::new(ReadMessageState { + message: listing.clone(), + })); + } + if data.io.keypad.get_presses(KeypadButton::KeypadB) > 0 { + Some(Box::new(MainMenuState::default())) + } else { + None + } + } + + fn draw(&self, data: &mut StateData) { + self.menu.draw(data); + } +} + +#[derive(Clone, Default)] +pub struct ReadMessageState { + message: MessageListing, +} + +impl State for ReadMessageState { + fn update(&mut self, data: &mut StateData) -> Option> { + if data.io.keypad.get_presses(KeypadButton::KeypadB) > 0 { + Some(Box::new(MainMenuState::default())) + } else { + None + } + } + + fn draw(&self, data: &mut StateData) { + data.clear_screen(Rgb565::black().as_color()); + data.draw_text( + self.message.from.clone(), + Position::new(0, 0), + TextSettings::default(), + ); + data.draw_text( + self.message.text.clone(), + Position::new(0, 30), + TextSettings::default(), + ); + } +} + #[derive(Clone, Default)] pub struct PhoneNumberState { input: NumberInput,