feat(ui): comment out gpui ui code and improve iced ui logic

This commit is contained in:
uttarayan21
2025-12-09 23:46:00 +05:30
parent 73fcf9bad1
commit d75a2fb7e4
2 changed files with 320 additions and 310 deletions

View File

@@ -1,262 +1,262 @@
use ::tap::*; // use ::tap::*;
//
use std::{collections::BTreeMap, sync::Arc}; // use std::{collections::BTreeMap, sync::Arc};
//
use gpui::{ // use gpui::{
App, Application, Bounds, ClickEvent, Context, ImageId, ImageSource, RenderImage, Resource, // App, Application, Bounds, ClickEvent, Context, ImageId, ImageSource, RenderImage, Resource,
SharedString, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size, // SharedString, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, rgb, size,
}; // };
//
#[derive(Clone, Debug)] // #[derive(Clone, Debug)]
pub struct AppState { // pub struct AppState {
pub title: SharedString, // pub title: SharedString,
pub items: BTreeMap<SharedString, Item>, // pub items: BTreeMap<SharedString, Item>,
pub item_ids: BTreeMap<usize, SharedString>, // pub item_ids: BTreeMap<usize, SharedString>,
pub current_item: Option<SharedString>, // pub current_item: Option<SharedString>,
pub errors: Vec<String>, // pub errors: Vec<String>,
pub jellyfin_client: api::JellyfinClient, // pub jellyfin_client: api::JellyfinClient,
}
#[derive(Clone, Debug)]
pub struct Item {
pub id: SharedString,
pub name: SharedString,
pub item_type: SharedString,
pub media_type: SharedString,
}
impl Render for AppState {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.flex()
.flex_col()
.size_full()
.justify_center()
.text_color(rgb(0xffffff))
.child(Self::header())
.child(Self::body(self, window, cx))
.child(Self::footer())
}
}
actions!(jello_actions, [OpenItem, OnLoadItem, MouseDownEvent]);
impl AppState {
fn new(title: impl AsRef<str>, jellyfin_client: api::JellyfinClient) -> Self {
AppState {
title: SharedString::new(title.as_ref()),
items: BTreeMap::new(),
item_ids: BTreeMap::new(),
current_item: None,
errors: Vec::new(),
jellyfin_client,
}
}
// fn on_mouse_down(
// &mut self,
// event: &MouseDownEvent,
// window: &mut Window,
// cx: &mut Context<Self>,
// ) {
// // Handle mouse down event
// } // }
//
fn load_item(id: usize) -> impl Fn(&mut Self, &ClickEvent, &mut Window, &mut Context<Self>) { // #[derive(Clone, Debug)]
move |state: &mut Self, event: &ClickEvent, window: &mut Window, cx: &mut Context<Self>| { // pub struct Item {
let item_id = id; // pub id: SharedString,
cx.spawn(async move |entity, app| { // pub name: SharedString,
tracing::info!("Loading item with id: {}", item_id); // pub item_type: SharedString,
}); // pub media_type: SharedString,
} // }
} //
// impl Render for AppState {
fn hover_item(id: usize) -> impl Fn(&mut Self, &bool, &mut Window, &mut Context<Self>) { // fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
move |state: &mut Self, item: &bool, window: &mut Window, cx: &mut Context<Self>| { // div()
dbg!("Hovering over item: {:?}", id); // .flex()
} // .flex_col()
} // .size_full()
// .justify_center()
fn header() -> impl IntoElement { // .text_color(rgb(0xffffff))
div() // .child(Self::header())
.flex() // .child(Self::body(self, window, cx))
.flex_row() // .child(Self::footer())
.w_full() // }
.justify_end() // }
.h_20() //
.border_10() // actions!(jello_actions, [OpenItem, OnLoadItem, MouseDownEvent]);
.bg(rgb(0x333333)) //
.child(Self::button("Refresh")) // impl AppState {
} // fn new(title: impl AsRef<str>, jellyfin_client: api::JellyfinClient) -> Self {
// AppState {
fn footer() -> impl IntoElement { // title: SharedString::new(title.as_ref()),
div().flex().flex_row().w_full().h_20().bg(rgb(0x333333)) // items: BTreeMap::new(),
} // item_ids: BTreeMap::new(),
// current_item: None,
fn body(&mut self, window: &mut Window, cx: &mut Context<AppState>) -> impl IntoElement { // errors: Vec::new(),
div() // jellyfin_client,
.flex() // }
.flex_row() // }
.size_full() //
.child(Self::content(self, window, cx)) // // fn on_mouse_down(
.child(Self::sidebar(self, window, cx)) // // &mut self,
} // // event: &MouseDownEvent,
// // window: &mut Window,
fn button(label: &str) -> impl IntoElement { // // cx: &mut Context<Self>,
div() // // ) {
.flex() // // // Handle mouse down event
.justify_center() // // }
.items_center() //
.bg(rgb(0xff00ff)) // fn load_item(id: usize) -> impl Fn(&mut Self, &ClickEvent, &mut Window, &mut Context<Self>) {
.text_color(rgb(0xffffff)) // move |state: &mut Self, event: &ClickEvent, window: &mut Window, cx: &mut Context<Self>| {
.border_5() // let item_id = id;
.rounded_lg() // cx.spawn(async move |entity, app| {
.child(label.to_string()) // tracing::info!("Loading item with id: {}", item_id);
} // });
// }
fn content(&mut self, window: &mut Window, cx: &mut Context<AppState>) -> impl IntoElement { // }
div() //
.debug_below() // fn hover_item(id: usize) -> impl Fn(&mut Self, &bool, &mut Window, &mut Context<Self>) {
.w_3_4() // move |state: &mut Self, item: &bool, window: &mut Window, cx: &mut Context<Self>| {
// dbg!("Hovering over item: {:?}", id);
// }
// }
//
// fn header() -> impl IntoElement {
// div()
// .flex()
// .flex_row()
// .w_full()
// .justify_end()
// .h_20()
// .border_10()
// .bg(rgb(0x333333))
// .child(Self::button("Refresh"))
// }
//
// fn footer() -> impl IntoElement {
// div().flex().flex_row().w_full().h_20().bg(rgb(0x333333))
// }
//
// fn body(&mut self, window: &mut Window, cx: &mut Context<AppState>) -> impl IntoElement {
// div()
// .flex()
// .flex_row()
// .size_full()
// .child(Self::content(self, window, cx))
// .child(Self::sidebar(self, window, cx))
// }
//
// fn button(label: &str) -> impl IntoElement {
// div()
// .flex()
// .justify_center()
// .items_center()
// .bg(rgb(0xff00ff))
// .text_color(rgb(0xffffff))
// .border_5()
// .rounded_lg()
// .child(label.to_string())
// }
//
// fn content(&mut self, window: &mut Window, cx: &mut Context<AppState>) -> impl IntoElement {
// div()
// .debug_below()
// .w_3_4()
// // .flex()
// // .flex_wrap()
// .bg(rgb(0x111111))
// .justify_start()
// .items_start()
// .overflow_hidden()
// .child(
// div()
// .size_full()
// .flex() // .flex()
// .flex_wrap() // .flex_wrap()
.bg(rgb(0x111111)) // .justify_start()
.justify_start() // .items_start()
.items_start() // .content_start()
.overflow_hidden() // .gap_y_10()
.child( // .gap_x_10()
div() // .border_t_10()
.size_full() // .p_5()
.flex() // .child(Self::card(cx, 1))
.flex_wrap() // .child(Self::card(cx, 2))
.justify_start() // .child(Self::card(cx, 3))
.items_start() // .child(Self::card(cx, 4))
.content_start() // .child(Self::card(cx, 5))
.gap_y_10() // .child(Self::card(cx, 6))
.gap_x_10() // .child(Self::card(cx, 7))
.border_t_10() // .child(Self::card(cx, 8))
.p_5() // .child(Self::card(cx, 9)),
.child(Self::card(cx, 1)) // )
.child(Self::card(cx, 2)) // }
.child(Self::card(cx, 3)) //
.child(Self::card(cx, 4)) // fn sidebar(&mut self, window: &mut Window, cx: &mut Context<AppState>) -> impl IntoElement {
.child(Self::card(cx, 5)) // div()
.child(Self::card(cx, 6)) // .flex()
.child(Self::card(cx, 7)) // .flex_col()
.child(Self::card(cx, 8)) // .w_1_4()
.child(Self::card(cx, 9)), // .min_w_1_6()
) // .bg(rgb(0x222222))
} // .child(div().size_full().bg(gpui::yellow()))
// }
fn sidebar(&mut self, window: &mut Window, cx: &mut Context<AppState>) -> impl IntoElement { //
div() // fn card(cx: &mut Context<AppState>, number: usize) -> impl IntoElement {
.flex() // div()
.flex_col() // .id(number)
.w_1_4() // .on_click(cx.listener(Self::load_item(number)))
.min_w_1_6() // .on_hover(cx.listener(Self::hover_item(number)))
.bg(rgb(0x222222)) // .flex()
.child(div().size_full().bg(gpui::yellow())) // .flex_col()
} // .w_48()
// .h_64()
fn card(cx: &mut Context<AppState>, number: usize) -> impl IntoElement { // .p_10()
div() // .bg(rgb(0xff00ff))
.id(number) // .rounded_lg()
.on_click(cx.listener(Self::load_item(number))) // }
.on_hover(cx.listener(Self::hover_item(number))) // }
.flex() //
.flex_col() // pub fn ui(jellyfin_client: api::JellyfinClient) {
.w_48() // Application::new().run(|cx: &mut App| {
.h_64() // let bounds = Bounds::centered(None, size(px(500.0), px(500.0)), cx);
.p_10() // cx.open_window(
.bg(rgb(0xff00ff)) // WindowOptions {
.rounded_lg() // window_bounds: Some(WindowBounds::Windowed(bounds)),
} // ..Default::default()
} // },
// |_, cx| cx.new(|_| AppState::new("Jello Media Browser", jellyfin_client)),
pub fn ui(jellyfin_client: api::JellyfinClient) { // )
Application::new().run(|cx: &mut App| { // .expect("Failed to open window");
let bounds = Bounds::centered(None, size(px(500.0), px(500.0)), cx); // })
cx.open_window( // }
WindowOptions { //
window_bounds: Some(WindowBounds::Windowed(bounds)), // #[derive(Clone, Debug)]
..Default::default() // pub struct Card {
}, // pub id: usize,
|_, cx| cx.new(|_| AppState::new("Jello Media Browser", jellyfin_client)), // pub title: SharedString,
) // pub description: SharedString,
.expect("Failed to open window"); // pub image: SharedString,
}) // pub image_blurhash: BlurHash,
} // pub media_type: SharedString,
// pub loading: bool,
#[derive(Clone, Debug)] // }
pub struct Card { //
pub id: usize, // impl Render for Card {
pub title: SharedString, // fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
pub description: SharedString, // div()
pub image: SharedString, // .id(self.id)
pub image_blurhash: BlurHash, // .flex()
pub media_type: SharedString, // .flex_col()
pub loading: bool, // .w_48()
} // .h_64()
// .p_10()
impl Render for Card { // .bg(rgb(0xff00ff))
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement { // .rounded_lg()
div() // .pipe(|card| {
.id(self.id) // if self.loading {
.flex() // card.child(self.image_blurhash.clone())
.flex_col() // } else {
.w_48() // card.child(gpui::img(self.image.clone()))
.h_64() // }
.p_10() // })
.bg(rgb(0xff00ff)) // }
.rounded_lg() // }
.pipe(|card| { //
if self.loading { // #[derive(Clone, Debug)]
card.child(self.image_blurhash.clone()) // pub struct BlurHash {
} else { // pub id: ImageId,
card.child(gpui::img(self.image.clone())) // pub data: Arc<RenderImage>,
} // }
}) //
} // impl BlurHash {
} // pub fn new(
// data: impl AsRef<str>,
#[derive(Clone, Debug)] // width: u32,
pub struct BlurHash { // height: u32,
pub id: ImageId, // punch: f32,
pub data: Arc<RenderImage>, // ) -> Result<Self, error_stack::Report<crate::Error>> {
} // use error_stack::ResultExt;
// let decoded =
impl BlurHash { // blurhash::decode(data.as_ref(), width, height, punch).change_context(crate::Error)?;
pub fn new( // let buffer = image::RgbaImage::from_raw(width, height, decoded)
data: impl AsRef<str>, // .ok_or(crate::Error)
width: u32, // .attach("Failed to convert")?;
height: u32, // let frame = image::Frame::new(buffer);
punch: f32, // let render_image = RenderImage::new([frame]);
) -> Result<Self, error_stack::Report<crate::Error>> { // Ok(Self {
use error_stack::ResultExt; // id: render_image.id,
let decoded = // data: Arc::from(render_image),
blurhash::decode(data.as_ref(), width, height, punch).change_context(crate::Error)?; // })
let buffer = image::RgbaImage::from_raw(width, height, decoded) // }
.ok_or(crate::Error) // }
.attach("Failed to convert")?; //
let frame = image::Frame::new(buffer); // impl Render for BlurHash {
let render_image = RenderImage::new([frame]); // fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
Ok(Self { // gpui::img(ImageSource::Render(self.data.clone()))
id: render_image.id, // }
data: Arc::from(render_image), // }
}) //
} // impl IntoElement for BlurHash {
} // type Element = gpui::Img;
//
impl Render for BlurHash { // fn into_element(self) -> Self::Element {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement { // gpui::img(ImageSource::Render(self.data.clone()))
gpui::img(ImageSource::Render(self.data.clone())) // }
} // }
}
impl IntoElement for BlurHash {
type Element = gpui::Img;
fn into_element(self) -> Self::Element {
gpui::img(ImageSource::Render(self.data.clone()))
}
}

View File

@@ -190,7 +190,8 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
// if let Some(client) = state.jellyfin_client.clone() { // if let Some(client) = state.jellyfin_client.clone() {
match message { match message {
Message::Settings(msg) => settings::update(&mut state.settings, msg), Message::Settings(msg) => settings::update(&mut state.settings, msg),
Message::OpenItem(id) if let Some(client) = state.jellyfin_client.clone() => { Message::OpenItem(id) => {
if let Some(client) = state.jellyfin_client.clone() {
use api::jellyfin::BaseItemKind::*; use api::jellyfin::BaseItemKind::*;
if let Some(cached) = id.as_ref().and_then(|id| state.cache.get(id)) if let Some(cached) = id.as_ref().and_then(|id| state.cache.get(id))
&& matches!(cached._type, Video | Movie | Episode) && matches!(cached._type, Video | Movie | Episode)
@@ -214,6 +215,9 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
}, },
) )
} }
} else {
Task::none()
}
} }
Message::LoadedItem(id, items) => { Message::LoadedItem(id, items) => {
state.cache.extend(id, items); state.cache.extend(id, items);
@@ -221,9 +225,8 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
state.current = id; state.current = id;
Task::none() Task::none()
} }
Message::Refresh if let Some(client) = state.jellyfin_client.clone() => { Message::Refresh => {
// Handle refresh logic if let Some(client) = state.jellyfin_client.clone() {
// let client = state.jellyfin_client.clone();
let current = state.current; let current = state.current;
Task::perform( Task::perform(
async move { async move {
@@ -238,6 +241,9 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
Ok(items) => Message::LoadedItem(msg, items), Ok(items) => Message::LoadedItem(msg, items),
}, },
) )
} else {
Task::none()
}
} }
Message::Error(err) => { Message::Error(err) => {
tracing::error!("Error: {}", err); tracing::error!("Error: {}", err);
@@ -266,9 +272,10 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
// Handle search query change // Handle search query change
Task::none() Task::none()
} }
Message::Search if let Some(client) = state.jellyfin_client.clone() => { Message::Search => {
// Handle search action // Handle search action
// let client = state.jellyfin_client.clone(); // let client = state.jellyfin_client.clone();
if let Some(client) = state.jellyfin_client.clone() {
let query = state.query.clone().unwrap_or_default(); let query = state.query.clone().unwrap_or_default();
Task::perform(async move { client.search(query).await }, |r| match r { Task::perform(async move { client.search(query).await }, |r| match r {
Err(e) => Message::Error(format!("Search failed: {}", e)), Err(e) => Message::Error(format!("Search failed: {}", e)),
@@ -277,6 +284,9 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
Message::LoadedItem(None, items) Message::LoadedItem(None, items)
} }
}) })
} else {
Task::none()
}
} }
Message::Video(msg) => video::update(state, msg), Message::Video(msg) => video::update(state, msg),
_ => todo!(), _ => todo!(),