use crate::db::FeedItem; use crate::widgets::content_view; use crate::widgets::media_view; use crate::widgets::navbar; use super::db; use super::widgets; use iced::widget::row; use iced::widget::scrollable; use iced::widget::text_input; use iced::Task; use iced::{ widget::{button, column, container, text}, Element, Length::Fill, }; use rss_content::parse_content; use rss_content::Content; const ICON: &[u8] = include_bytes!("../assets/icon_placeholder.png"); pub fn user_interface() -> iced::Result { //iced::run(update, view) let icon = iced::window::icon::from_file_data(ICON, None).ok(); let app = iced::application(State::default,update,view) .title("RSSCar") .theme(iced::Theme::Dark) .window(iced::window::Settings{ icon, ..Default::default() }); app.run() } #[derive(Clone, Debug,PartialEq)] pub enum Page { Home, FeedView, AllItems, ItemView, CategoryView, Testing, } pub struct State { pub page: Page, pub current_feed: usize, pub current_item: Option, pub item_description: Vec, pub item_content: Vec, pub feed_input: String, } impl Default for State { fn default() -> Self { State { page: Page::Home, current_feed: 0, current_item: None, item_description: Vec::new(), item_content: Vec::new(), feed_input: String::from(""), } } } #[derive(Debug, Clone)] pub enum Message { ChangePage(Page), LoadFeed(usize), AddFeed(String), RemoveFeed(usize), LoadItem(usize), FieldUpdated(AppField, String), LinkClicked(String), Done(String), ResetDB, } #[derive(Debug, Clone)] pub enum AppField { FeedInput, } async fn add_feed_background(url: String) -> String { println!("Adding feed!"); db::add_feed(&url); "Done adding feed".to_string() } async fn remove_feed_background(id:usize) -> String { println!("Removing feed"); db::remove_feed(id); "Done removing feed".to_owned() } fn update(state: &mut State, mes: Message) -> Task { match mes { Message::ChangePage(p) => { state.page = p; Task::none() } Message::LoadFeed(feed_id) => { state.current_feed = feed_id; state.page = Page::FeedView; Task::none() } Message::AddFeed(f) => { state.feed_input = "".to_string(); Task::perform(add_feed_background(f.to_string()), Message::Done) } Message::RemoveFeed(id) => { Task::perform(remove_feed_background(id), Message::Done) } Message::LinkClicked(l) => { println!("Link clicked: {}", l); Task::none() } Message::LoadItem(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; Task::none() } Message::Done(_) => Task::none(), Message::FieldUpdated(field, value) => { match field { AppField::FeedInput => { state.feed_input = value; } } Task::none() } Message::ResetDB => { db::reset(); Task::none() } } } fn view(state: &State) -> Element<'_, Message> { match state.page { Page::Home => home(&state), Page::FeedView => feed_layout(&state), Page::AllItems => item_list(&state), Page::ItemView => item_view(&state), Page::CategoryView => category_view(&state), Page::Testing => testing(&state), } } fn home(state: &State) -> Element<'_, Message> { container(column!( widgets::navbar(state), scrollable(widgets::list_feeds()) .width(iced::Fill) .height(iced::Fill), button("Go to test!").on_press(Message::ChangePage(Page::Testing)) )) .padding(15) .height(Fill) .width(Fill) .into() } fn feed_layout(state: &State) -> Element<'_, Message> { container(column!( button(text("Home")).on_press(Message::ChangePage(Page::Home)), scrollable(widgets::list_items(state.current_feed)) .width(iced::Fill) .height(iced::Fill), )) .height(Fill) .width(Fill) .into() } fn item_view(state: &State) -> Element<'_, Message> { let title = match state.current_item.clone() { Some(i) => {i.title} None => {"".to_owned()} }; container(column!( row!( button(text("Home")).on_press(Message::ChangePage(Page::Home)), button(text("Feed")).on_press(Message::ChangePage(Page::FeedView)) ) .spacing(10), text(title).size(34), media_view(state), content_view(state), )) .height(Fill) .width(Fill) .into() } fn item_list(state: &State) -> Element<'_, Message> { container( column!( navbar(state), scrollable( column( db::get_all_items().iter().map(|i|{ widgets::list_item(i.item_id, i.title.clone(), i.description.clone().unwrap_or("".to_owned())) }).map(iced::Element::from) ).align_x(iced::Alignment::Center)).width(Fill).spacing(5) ), ).width(Fill).height(Fill).into() } fn category_view(state: &State) -> Element<'_,Message> { column!( navbar(state) ).spacing(5).into() } fn testing(state: &State) -> Element<'_, Message> { column!( text("Dev Panel"), 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/archive/index.xml" ))), row!( 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())) ) .spacing(5) .padding(10), button("Wipe DB").on_press(Message::ResetDB), button("go back!").on_press(Message::ChangePage(Page::Home)) ) .spacing(5) .into() }