restructure folders

This commit is contained in:
death916 2026-03-12 05:43:06 -07:00
parent 0b9f9c010f
commit ef3a2c4c57
4 changed files with 0 additions and 0 deletions

5883
rustclock/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

12
rustclock/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "rust"
version = "0.1.0"
edition = "2024"
[dependencies]
chrono = "0.4.44"
iced = { version = "0.14.0", features = ["image"] }
reqwest = "0.13.2"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
ureq = "3.2.0"

198
rustclock/src/main.rs Normal file
View file

@ -0,0 +1,198 @@
mod sports;
use chrono::DateTime;
use chrono::Local;
use iced::Border;
use iced::Element;
use iced::Fill;
use iced::widget::{column, container, image, pane_grid, row, text};
use sports::Game;
pub fn main() -> iced::Result {
iced::run(State::update, State::view)
}
#[derive(Debug, Clone)]
enum PaneType {
Main,
MlbPane,
NflPane,
NbaPane,
Weather,
Clock,
}
#[derive(Debug, Clone)]
enum Message {
PaneDragged(pane_grid::DragEvent),
PaneResized(pane_grid::ResizeEvent),
}
#[derive(Debug)]
struct State {
current_time: DateTime<Local>,
next_alarm: Option<DateTime<Local>>,
news: Vec<String>,
weather: Vec<u8>,
location: String,
nba_scores: Vec<Game>,
mlb_scores: Vec<Game>,
// nfl_scores: Vec<Game>,
panes: pane_grid::State<PaneType>,
}
impl State {
fn update(&mut self, message: Message) {
match message {
Message::PaneDragged(pane_grid::DragEvent::Dropped { pane, target }) => {
self.panes.drop(pane, target);
}
Message::PaneDragged(_) => {}
Message::PaneResized(pane_grid::ResizeEvent { split, ratio }) => {
self.panes.resize(split, ratio);
}
}
}
fn view(state: &State) -> Element<'_, Message> {
pane_grid(&state.panes, |_panes, pane_state, _is_maximized| {
let content: Element<'_, Message> = match pane_state {
PaneType::NbaPane => {
let games = &state.nba_scores;
column(games.iter().map(|game| {
container(
column![
row![
text(&game.team1).size(20).width(Fill),
text(&game.team2).size(20).width(Fill),
],
row![
text(&game.score1).size(20).width(Fill),
text(&game.score2).size(20).width(Fill),
],
text(format!("Period: {}", game.period)).size(14),
]
.padding(10),
)
.padding(5)
.width(Fill)
.style(|_| container::Style {
background: Some(iced::Background::Color(iced::Color::from_rgb(
0.2, 0.2, 0.2,
))),
border: Border {
width: 1.0,
color: iced::Color::WHITE,
radius: 0.0.into(),
},
text_color: Some(iced::Color::WHITE),
snap: true,
shadow: iced::Shadow {
color: iced::Color::BLACK,
offset: iced::Vector::new(0.0, 0.0),
blur_radius: 10.0,
},
})
.into()
}))
.padding(0)
.into()
}
PaneType::NflPane => text("NFL").into(),
PaneType::MlbPane => {
let games = &state.mlb_scores;
column(games.iter().map(|game| {
container(
column![
row![
text(&game.team1).size(20).width(Fill),
text(&game.team2).size(20).width(Fill),
],
row![
text(&game.score1).size(20).width(Fill),
text(&game.score2).size(20).width(Fill),
],
text(format!("Period: {}", game.period)).size(14),
]
.padding(10),
)
.padding(5)
.width(Fill)
.style(|_| container::Style {
background: Some(iced::Background::Color(iced::Color::from_rgb(
0.2, 0.2, 0.2,
))),
border: Border {
width: 1.0,
color: iced::Color::WHITE,
radius: 0.0.into(),
},
text_color: Some(iced::Color::WHITE),
snap: true,
shadow: iced::Shadow {
color: iced::Color::BLACK,
offset: iced::Vector::new(0.0, 0.0),
blur_radius: 10.0,
},
})
.into()
}))
.padding(0)
.into()
}
PaneType::Main => text("Main").into(),
PaneType::Clock => text("clock").into(),
PaneType::Weather => {
let weather_img = image::Handle::from_bytes(state.weather.clone());
let time = Local::now().format("%H:%M:%S").to_string();
container(
column![
text(time).size(20).center(),
text("Weather").size(50).center(),
image(weather_img).width(Fill),
text(state.location.clone()).size(30).center(),
]
.padding(0),
)
.into()
}
};
pane_grid::Content::new(content)
})
.on_drag(Message::PaneDragged)
.on_resize(10, Message::PaneResized)
.into()
}
}
impl Default for State {
fn default() -> Self {
sports::update_mlb();
let text = ureq::get("https://v2.wttr.in/Sacramento.png?u0")
.header("User-Agent", "deathclock-app/1.0")
.call()
.unwrap()
.into_body()
.read_to_vec()
.unwrap();
State {
current_time: Local::now(),
next_alarm: None,
news: Vec::new(),
weather: text,
location: "Sacramento".to_string(),
nba_scores: { sports::update_nba() },
mlb_scores: { sports::update_mlb() },
panes: {
let (mut panes, nba) = pane_grid::State::new(PaneType::NbaPane);
let (weather, _) = panes
.split(pane_grid::Axis::Vertical, nba, PaneType::Weather)
.unwrap();
let (mlb, _) = panes
.split(pane_grid::Axis::Vertical, weather, PaneType::MlbPane)
.unwrap();
panes.split(pane_grid::Axis::Horizontal, mlb, PaneType::NflPane);
panes
},
}
}
}

138
rustclock/src/sports.rs Normal file
View file

@ -0,0 +1,138 @@
#[derive(Debug, Clone)]
pub enum Sport {
NBA,
NFL,
MLB,
}
#[derive(Debug)]
pub struct Game {
pub sport: Sport,
pub team1: String,
pub team2: String,
pub score1: String,
pub score2: String,
pub period: u8,
}
impl Game {
pub fn new(
sport: Sport,
team1: &str,
team2: &str,
score1: &str,
score2: &str,
period: u8,
) -> Self {
Game {
sport,
team1: team1.to_string(),
team2: team2.to_string(),
score1: score1.to_string(),
score2: score2.to_string(),
period,
}
}
pub fn update(&mut self, score1: &str, score2: &str, period: u8) {
self.score1 = score1.to_string();
self.score2 = score2.to_string();
self.period = period;
}
}
pub fn update_mlb() -> Vec<Game> {
let date = chrono::Local::now().format("%Y-%m-%d").to_string();
let mlb_url = format!(
"https://statsapi.mlb.com/api/v1/schedule?sportId=1&date={}",
date
);
let mlb_games = ureq::get(&mlb_url)
.header("User-Agent", "deathclock-app/1.0")
.call()
.unwrap()
.into_body()
.read_to_vec()
.unwrap();
let mlb_json: serde_json::Value = serde_json::from_slice(&mlb_games).unwrap();
let games = mlb_json["dates"][0]["games"].as_array().unwrap();
let mut mlb_games_vec = Vec::new();
for game in games {
let home_team = game["teams"]["away"]["team"]["name"].as_str().unwrap();
let away_team = game["teams"]["home"]["team"]["name"].as_str().unwrap();
let home_score = game["teams"]["away"]["score"]
.as_str()
.unwrap_or_else(|| "0");
let away_score = game["teams"]["home"]["score"]
.as_str()
.unwrap_or_else(|| "0");
let period = game["status"]["period"]
.as_str()
.unwrap_or_default()
.parse::<u8>()
.unwrap_or_default();
let mut mlb_game_struct = Game::new(
Sport::MLB,
home_team,
away_team,
home_score,
away_score,
period,
);
mlb_game_struct.update(&home_score, &away_score, period);
mlb_games_vec.push(mlb_game_struct);
println!("Home Team: {}", home_team);
println!("Away Team: {}", away_team);
println!("Home Score: {}", home_score);
println!("Away Score: {}", away_score);
println!("Period: {}", period);
}
mlb_games_vec
}
pub fn update_nba() -> Vec<Game> {
let nba_games =
ureq::get("https://cdn.nba.com/static/json/liveData/scoreboard/todaysScoreboard_00.json")
.header("User-Agent", "deathclock-app/1.0")
.call()
.unwrap()
.into_body()
.read_to_vec()
.unwrap();
let json: serde_json::Value = serde_json::from_slice(&nba_games).unwrap();
let games = json["scoreboard"]["games"].as_array().unwrap();
let mut updated_games: Vec<Game> = Vec::new();
for game in games {
let game_id = game["gameId"].as_str().unwrap();
let home_team = game["homeTeam"]["teamName"].as_str().unwrap();
let away_team = game["awayTeam"]["teamName"].as_str().unwrap();
let home_score = game["homeTeam"]["score"].as_u64().unwrap().to_string();
let away_score = game["awayTeam"]["score"].as_u64().unwrap().to_string();
let period = game["period"].as_u64().unwrap() as u8;
let mut game = Game::new(
Sport::NBA,
home_team,
away_team,
&home_score,
&away_score,
period,
);
game.update(&home_score, &away_score, period);
updated_games.push(game);
println!("Game ID: {}", game_id);
println!("Home Team: {}", home_team);
println!("Away Team: {}", away_team);
println!("Home Score: {}", home_score);
println!("Away Score: {}", away_score);
println!("Period: {}", period);
}
updated_games
}