Menu
cosmic-mobile
publicLatest change a8ee2eaae0bd8aa979db3219390e3b2d7a5b98e6 - Add core app pages and touch phone keypad by AkurAI Build
use std::{io, path::PathBuf};
pub struct Store {
pub rows: Vec<(String, String, String, String)>,
path: PathBuf,
}
impl Store {
pub fn load(path: PathBuf) -> io::Result<Self> {
let text = match std::fs::read_to_string(&path) {
Ok(text) => text,
Err(e) if e.kind() == io::ErrorKind::NotFound => String::new(),
Err(e) => return Err(e),
};
let mut rows = Vec::new();
for line in text.lines() {
let fields: Vec<_> = line.split('\t').collect();
if fields.len() != 4 {
return Err(io::Error::other("Invalid records; file preserved"));
}
rows.push((
fields[0].into(),
fields[1].into(),
fields[2].into(),
fields[3].into(),
));
}
Ok(Self { rows, path })
}
pub fn add(&mut self, app: &str, first: &str, second: &str) -> io::Result<()> {
let first = first.trim();
let second = second.trim();
if !["Phone", "Contacts", "Calendar", "Messages"].contains(&app)
|| [first, second]
.iter()
.any(|v| v.is_empty() || v.len() > 4096 || v.chars().any(char::is_control))
{
return Err(io::Error::other(
"Enter both fields; control characters are not allowed",
));
}
let number = match app {
"Contacts" => Some(second),
"Phone" | "Messages" => Some(first),
_ => None,
};
if let Some(number) = number {
if number.len() > 64
|| !number.bytes().any(|b| b.is_ascii_digit())
|| !number
.bytes()
.all(|b| b.is_ascii_digit() || b"+ -()*#".contains(&b))
{
return Err(io::Error::other("Enter a valid phone number"));
}
}
if app == "Calendar" {
let parts: Vec<_> = first.split('-').collect();
let date: Vec<u32> = parts.iter().filter_map(|v| v.parse().ok()).collect();
if parts.len() != 3
|| parts.iter().map(|s| s.len()).collect::<Vec<_>>() != [4, 2, 2]
|| date.len() != 3
{
return Err(io::Error::other("Use YYYY-MM-DD"));
}
let (y, m, d) = (date[0], date[1], date[2]);
let leap = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
let days = [
31,
if leap { 29 } else { 28 },
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
];
if y == 0 || !(1..=12).contains(&m) || d == 0 || d > days[(m - 1) as usize] {
return Err(io::Error::other("Invalid calendar date"));
}
}
let status = match app {
"Phone" => "Simulated — no call placed",
"Messages" => "Simulated — not sent",
_ => "Saved locally",
};
let mut rows = self.rows.clone();
rows.push((app.into(), first.into(), second.into(), status.into()));
let data: String = rows
.iter()
.map(|r| format!("{}\t{}\t{}\t{}\n", r.0, r.1, r.2, r.3))
.collect();
if let Some(parent) = self.path.parent() {
std::fs::create_dir_all(parent)?;
}
let tmp = self.path.with_extension("tmp");
std::fs::write(&tmp, data)?;
std::fs::rename(tmp, &self.path)?;
self.rows = rows;
Ok(())
}
}