Starting to support fancier elements...

This commit is contained in:
Gabriel 2025-07-22 17:32:48 -04:00
parent 56a62e96fd
commit a4756b8ec4
2 changed files with 109 additions and 81 deletions

View file

@ -1,17 +1,20 @@
use crate::db::FeedItem;
use crate::widgets::content_view; use crate::widgets::content_view;
use super::db; use super::db;
use super::widgets; use super::widgets;
use iced::widget::markdown::Url;
use iced::widget::row; use iced::widget::row;
use iced::widget::scrollable; use iced::widget::scrollable;
use iced::widget::text_input; use iced::widget::text_input;
use iced::widget::markdown::Url;
use iced::Task; use iced::Task;
use iced::{ use iced::{
widget::{button, column, container, text}, widget::{button, column, container, text},
Element, Element,
Length::Fill, Length::Fill,
}; };
use rss_content::parse_content;
use rss_content::Content;
pub fn user_interface() -> iced::Result { pub fn user_interface() -> iced::Result {
iced::run(update, view) iced::run(update, view)
@ -26,19 +29,23 @@ pub enum Page {
Testing, Testing,
} }
struct State { pub struct State {
page: Page, page: Page,
current_feed: usize, current_feed: usize,
current_item: usize, pub current_item: Option<FeedItem>,
feed_input: String pub item_description: Vec<Content>,
pub item_content: Vec<Content>,
feed_input: String,
} }
impl Default for State { impl Default for State {
fn default() -> Self { fn default() -> Self {
State { State {
page: Page::Home, page: Page::Home,
current_feed: 0, current_feed: 0,
current_item: 0, current_item: None,
feed_input: String::from("") item_description: Vec::new(),
item_content: Vec::new(),
feed_input: String::from(""),
} }
} }
} }
@ -52,12 +59,12 @@ pub enum Message {
FieldUpdated(AppField, String), FieldUpdated(AppField, String),
LinkClicked(Url), LinkClicked(Url),
Done(String), Done(String),
ResetDB ResetDB,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AppField { pub enum AppField {
FeedInput FeedInput,
} }
async fn add_feed_background(url: String) -> String { async fn add_feed_background(url: String) -> String {
@ -71,29 +78,40 @@ fn update(state: &mut State, mes: Message) -> Task<Message>{
Message::ChangePage(p) => { Message::ChangePage(p) => {
state.page = p; state.page = p;
Task::none() Task::none()
}, }
Message::LoadFeed(feed_id) => { Message::LoadFeed(feed_id) => {
state.current_feed = feed_id; state.current_feed = feed_id;
state.page = Page::FeedView; state.page = Page::FeedView;
Task::none() Task::none()
}, }
Message::AddFeed(f) => { Message::AddFeed(f) => {
state.feed_input = "".to_string(); state.feed_input = "".to_string();
Task::perform( Task::perform(add_feed_background(f.to_string()), Message::Done)
add_feed_background(f.to_string()), }
Message::Done
)
},
Message::LinkClicked(l) => { Message::LinkClicked(l) => {
println!("Link clicked: {}", l); println!("Link clicked: {}", l);
Task::none() Task::none()
} }
Message::LoadItem(id) => { Message::LoadItem(id) => {
state.current_item = id; let item = db::get_item(id);
state.item_description = match &item.description {
Some(d) => {
parse_content(&d)
}
None => Vec::new()
};
state.item_content = match &item.content{
Some(c) => {
parse_content(&c)
}
None => Vec::new()
};
state.current_item = Some(item);
state.page = Page::ItemView; state.page = Page::ItemView;
Task::none() Task::none()
} }
Message::Done(_) => {Task::none()}, Message::Done(_) => Task::none(),
Message::FieldUpdated(field, value) => { Message::FieldUpdated(field, value) => {
match field { match field {
AppField::FeedInput => { AppField::FeedInput => {
@ -101,16 +119,12 @@ fn update(state: &mut State, mes: Message) -> Task<Message>{
} }
} }
Task::none() Task::none()
}, }
Message::ResetDB => { Message::ResetDB => {
db::reset(); db::reset();
Task::none() Task::none()
} }
} }
} }
fn view(state: &State) -> Element<'_, Message> { fn view(state: &State) -> Element<'_, Message> {
@ -125,7 +139,9 @@ fn view(state: &State) -> Element<'_, Message> {
fn home(_state: &State) -> Element<'_, Message> { fn home(_state: &State) -> Element<'_, Message> {
container(column!( container(column!(
scrollable(widgets::list_feeds()).width(iced::Fill).height(iced::Fill), scrollable(widgets::list_feeds())
.width(iced::Fill)
.height(iced::Fill),
button("Go to test!").on_press(Message::ChangePage(Page::Testing)) button("Go to test!").on_press(Message::ChangePage(Page::Testing))
)) ))
.padding(15) .padding(15)
@ -134,30 +150,27 @@ fn home(_state: &State) -> Element<'_, Message> {
.into() .into()
} }
fn feed_layout(state: &State) -> Element<'_, Message> { fn feed_layout(state: &State) -> Element<'_, Message> {
container( container(column!(
column!(
button(text("Home")).on_press(Message::ChangePage(Page::Home)), button(text("Home")).on_press(Message::ChangePage(Page::Home)),
scrollable(widgets::list_items(state.current_feed)).width(iced::Fill).height(iced::Fill), scrollable(widgets::list_items(state.current_feed))
) .width(iced::Fill)
) .height(iced::Fill),
))
.height(Fill) .height(Fill)
.width(Fill) .width(Fill)
.into() .into()
} }
fn item_view(state: &State) -> Element<'_, Message> { fn item_view(state: &State) -> Element<'_, Message> {
let item = db::get_item(state.current_item); container(column!(
container(
column!(
row!( row!(
button(text("Home")).on_press(Message::ChangePage(Page::Home)), button(text("Home")).on_press(Message::ChangePage(Page::Home)),
button(text("Feed")).on_press(Message::ChangePage(Page::FeedView)) button(text("Feed")).on_press(Message::ChangePage(Page::FeedView))
).spacing(10),
content_view(item),
)
) )
.spacing(10),
content_view(state),
))
.height(Fill) .height(Fill)
.width(Fill) .width(Fill)
.into() .into()
@ -170,11 +183,17 @@ fn testing(state: &State) -> Element<'_, Message> {
column!( column!(
text("Dev Panel"), text("Dev Panel"),
button("Add gabe.rocks").on_press(Message::AddFeed(String::from("https://gabe.rocks/rss"))), button("Add gabe.rocks").on_press(Message::AddFeed(String::from("https://gabe.rocks/rss"))),
button("Add LSN").on_press(Message::AddFeed(String::from("https://libresolutions.network/rss"))), button("Add LSN").on_press(Message::AddFeed(String::from(
"https://libresolutions.network/rss"
))),
row!( row!(
text_input("Add a feed",&state.feed_input).on_input(|val| Message::FieldUpdated(AppField::FeedInput,val)).width(300), text_input("Add a feed", &state.feed_input)
.on_input(|val| Message::FieldUpdated(AppField::FeedInput, val))
.width(300),
button("Add feed!").on_press(Message::AddFeed(state.feed_input.clone())) button("Add feed!").on_press(Message::AddFeed(state.feed_input.clone()))
).spacing(5).padding(10), )
.spacing(5)
.padding(10),
button("Wipe DB").on_press(Message::ResetDB), button("Wipe DB").on_press(Message::ResetDB),
button("go back!").on_press(Message::ChangePage(Page::Home)) button("go back!").on_press(Message::ChangePage(Page::Home))
) )

View file

@ -1,8 +1,9 @@
use crate::db::FeedItem;
use super::db; use super::db;
use super::ui; use super::ui;
use iced::widget::markdown;
use iced::widget::scrollable; use iced::widget::scrollable;
use iced::widget::Column;
use iced::Theme;
use rss_content::Content; use rss_content::Content;
use ui::Message; use ui::Message;
use rss_content; use rss_content;
@ -40,44 +41,52 @@ pub fn list_items(feed_id: usize) -> iced::widget::Column<'static,Message> {
.padding(15) .padding(15)
} }
pub fn content_area(cnt: String) -> iced::widget::Container<'static,Message>{ pub fn content_area(content: &Vec<Content>) -> iced::widget::Container<Message> {
let content = rss_content::parse_content(&cnt); let mut children: Vec<Element<Message>> = Vec::new();
container( for c in content {
column(
content.into_iter().map(|c: Content|{
match c { match c {
Content::Markdown(md) => { Content::MarkdownParsed(p) => {
text(md) children.push(
}, markdown(p, Theme::Dark).map(Message::LinkClicked)
Content::Image(_) => {text("Image goes here")}, );
Content::Audio(_) => {text("Audio widget here")},
Content::Video(_) => {text("video player here")},
_ => {text("")}
} }
}).map(Element::from) Content::Image(_) => {children.push(text("<Image goes here>")
) .size(32)
.into());},
Content::Audio(_) => {children.push(text("<Audio widget here>")
.size(32)
.into());},
Content::Video(_) => {children.push(text("<Video goes here>")
.size(32)
.into());},
_ => {}
}
}
container(
Column::with_children(children)
) )
} }
pub fn content_view(item: FeedItem) -> iced::widget::Scrollable<'static, Message> { pub fn content_view(state: &super::ui::State) -> iced::widget::Scrollable<Message> {
let item = state.current_item.clone().unwrap();
scrollable( scrollable(
column!( column!(
text(item.title).size(34), text(item.title).size(34),
match item.description { match item.description {
Some(d) => { Some(_d) => {
content_area(d) content_area(&state.item_description)
}, },
None => {container(text("No description found"))} None => {container(text("No description found"))}
}, },
match item.content { match item.content {
Some(c) => { Some(_c) => {
content_area(c) content_area(&state.item_content)
} }
None => {container(text("No content found"))} None => {container(text("No content found"))}
} }
) )
) ).width(iced::Fill)
} }