able to retrieve feeds, make sure UI displays and can add/remove feeds. (State has to load from DB)

This commit is contained in:
Gabriel 2025-07-02 20:11:43 -04:00
parent 942c7d89aa
commit f2e00c7034
3 changed files with 118 additions and 64 deletions

139
src/db.rs
View file

@ -1,26 +1,26 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use rusqlite::{params, Connection, Result};
use crate::files; use crate::files;
use rusqlite::{params, Connection, Result};
use super::net::{*}; use super::files::*;
use super::files::{*}; use super::net::*;
use chrono::Utc; //Maybe use a different time?
/* /*
Cache is the in-memory database Cache is the in-memory database
Any changes/updates are written to file database Any changes/updates are written to file database
*/ */
struct Item {
struct Item{
title: String, title: String,
content: Option<String> content: Option<String>,
} }
const DB_LOCATION: &str = "rsscar.db"; const DB_LOCATION: &str = "rsscar.db";
fn get_db_path() -> PathBuf{ fn get_db_path() -> PathBuf {
get_data_directory().join(DB_LOCATION) get_data_directory().join(DB_LOCATION)
} }
@ -34,7 +34,7 @@ const feeds_table_create: &str = "CREATE TABLE IF NOT EXISTS 'feeds' (
'last_updated' TEXT , 'last_updated' TEXT ,
PRIMARY KEY('feedID') PRIMARY KEY('feedID')
);"; );";
const feeds_index_create: &str = "CREATE INDEX IF NOT EXISTS 'subscribed_feeds_idx' ON 'feeds' ( const feeds_index_create: &str = "CREATE INDEX IF NOT EXISTS 'subscribed_feeds_idx' ON 'feeds' (
'feedID' ASC 'feedID' ASC
) WHERE 'subscribed' = 1;"; ) WHERE 'subscribed' = 1;";
@ -53,68 +53,117 @@ const items_table_create: &str = "CREATE TABLE IF NOT EXISTS 'items' (
const items_index_create: &str = "CREATE INDEX IF NOT EXISTS 'items_idx' on 'items'('itemID' ASC);"; const items_index_create: &str = "CREATE INDEX IF NOT EXISTS 'items_idx' on 'items'('itemID' ASC);";
pub fn initialize() { pub fn initialize() {
let path = get_db_path();
let conn = Connection::open(get_db_path()).unwrap(); println!("Database at {} initialized", path.as_os_str().display());
conn.execute(feeds_table_create,[]).unwrap(); let conn = Connection::open(path).unwrap();
conn.execute(feeds_index_create,[]).unwrap(); conn.execute(feeds_table_create, []).unwrap();
conn.execute(items_table_create,[]).unwrap(); conn.execute(feeds_index_create, []).unwrap();
conn.execute(items_index_create,[]).unwrap(); conn.execute(items_table_create, []).unwrap();
conn.execute(items_index_create, []).unwrap();
conn.close(); conn.close();
println!("Database Initialized.") println!("Database Initialized.")
} }
pub fn add_feed(url: &str) { pub fn add_feed(url: &str) {
let conn = Connection::open(get_db_path()).unwrap(); let conn = Connection::open(get_db_path()).unwrap();
let feed = load_rss(url).unwrap(); let feed = load_rss(url).unwrap();
let new_feed = feed.clone(); let new_feed = feed.clone();
conn.execute("insert into feeds(title,url,description) values(?1,?2,?3)", let time = Utc::now().to_rfc2822();
[feed.title,url.to_owned(),feed.description]).unwrap(); conn.execute(
"insert into feeds(title,url,description,last_updated) values(?1,?2,?3,?4)",
[feed.title, url.to_owned(), feed.description, time],
)
.unwrap();
conn.close(); conn.close();
store_items(new_feed); store_items(new_feed);
} }
pub fn store_items(feed: rss::Channel) { pub fn store_items(feed: rss::Channel) {
let conn = Connection::open(get_db_path()).unwrap(); let conn = Connection::open(get_db_path()).unwrap();
feed.items.iter().for_each(|i: &rss::Item|{ feed.items.iter().for_each(|i: &rss::Item| {
conn.execute("insert into items(url,title,description,content) values(?1,?2,?3,?4)",[ conn.execute(
i.link.clone(), "insert into items(url,title,description,content) values(?1,?2,?3,?4)",
i.title.clone(), [
i.description.clone(), i.link.clone(),
i.content.clone()] i.title.clone(),
).unwrap(); i.description.clone(),
}); i.content.clone(),
],
)
.unwrap();
});
conn.close(); conn.close();
} }
pub fn return_item() -> String{ pub fn return_item() -> String {
let conn = Connection::open(get_db_path()).unwrap(); let conn = Connection::open(get_db_path()).unwrap();
let item = conn.query_row("select title,content from items where rowid=?1",[488],|row|{ let item = conn
Ok( .query_row(
Item { title: row.get(0).unwrap(), content: row.get(1).unwrap() } "select title,content from items where rowid=?1",
[],
|row| {
Ok(Item {
title: row.get(0).unwrap(),
content: row.get(1).unwrap(),
})
},
) )
}).unwrap(); .unwrap();
match item.content { match item.content {
Some(content) => content, Some(content) => content,
None => panic!() None => panic!(),
} }
} }
struct ReturnedFeedURLs{ pub struct Feed {
url: String feedID: u8,
title: String,
description: Option<String>,
icon: Option<String>,
url: String,
subscribed: Option<String>, //needs to be bool
last_updated: Option<String>,
}
pub fn get_feeds() -> Vec<Feed> {
let conn = Connection::open(get_db_path()).unwrap();
let mut stmt = conn.prepare("select feedID,title,description,icon,url,subscribed,last_updated from feeds").unwrap();
let rows: Result<Vec<Feed>> = stmt
.query_map([], |row| {
Ok(Feed {
feedID: row.get(0).unwrap(),
title: row.get(1).unwrap(),
description: row.get(2).unwrap(),
icon: row.get(3).unwrap(),
url: row.get(4).unwrap(),
subscribed: row.get(5).unwrap(),
last_updated: row.get(6).unwrap(),
})
}).unwrap().collect();
match rows {
Ok(r) => {
println!("Feed found\n{}",r[0].title);
r
}
Err(e) => {panic!()}
}
}
struct ReturnedFeedURLs {
url: String,
} }
pub fn update_feeds() { pub fn update_feeds() {
//get feeds //get feeds
let conn = Connection::open(get_db_path()).unwrap(); let conn = Connection::open(get_db_path()).unwrap();
let mut stmt = conn.prepare("select url from feeds").unwrap(); let mut stmt = conn.prepare("select url from feeds").unwrap();
let rows = stmt.query_map([],|row| { let rows = stmt
Ok(ReturnedFeedURLs{ .query_map([], |row| {
url:row.get(0).unwrap() Ok(ReturnedFeedURLs {
url: row.get(0).unwrap(),
})
}) })
}).unwrap(); .unwrap();
let mut urls: Vec<String> = Vec::new(); let mut urls: Vec<String> = Vec::new();
for feed in rows{ for feed in rows {
let url = feed.unwrap().url.clone(); let url = feed.unwrap().url.clone();
urls.push(url); urls.push(url);
} }
@ -125,10 +174,8 @@ pub fn update_feeds() {
store_items(load_rss(&u).unwrap()); store_items(load_rss(&u).unwrap());
} }
//for each feed //for each feed
// insert items into database // insert items into database
//close out //close out
} }

View file

@ -1,30 +1,16 @@
mod net; mod net;
use db::initialize; use db::initialize;
use iced::{application, widget::{self, button, column, markdown, row, text}, Settings, Theme};
use net::load_rss; use net::load_rss;
use rss::Channel;
mod ui; mod ui;
mod html; mod html;
mod db; mod db;
use db::Feed;
mod files; mod files;
pub fn main() -> iced::Result {
//build CLI first, then create GUI
/*
TO DO:
1) Create basic CLI interactions
2) Create comprehensive Schema
3) Add/remove subscriptions
4)
*/
pub fn main() {
db::initialize(); db::initialize();
db::add_feed("https://gabe.rocks/rss"); db::get_feeds();
ui::user_interface()
} }

View file

@ -0,0 +1,21 @@
use iced::{Element, Result};
pub fn user_interface() -> iced::Result {
iced::run(update, view)
}
#[derive(Default)]
struct State{
}
#[derive(Debug,Clone)]
enum Message {}
fn update(state: &mut State,message: Message) {
}
fn view(state: &State) -> Element<'_, Message> {
iced::widget::text("Ayy lmao").into()
}