From 2b2e8060e761883da5f72610be8e77c11eba4831 Mon Sep 17 00:00:00 2001 From: uttarayan21 Date: Fri, 26 Dec 2025 21:21:58 +0530 Subject: [PATCH] feat(ui-iced): implement settings screen with navigation and basic UI elements --- Cargo.lock | 84 ++++++++++++++++++++++++- crates/iced-video/examples/minimal.rs | 9 ++- ui-iced/Cargo.toml | 5 +- ui-iced/src/lib.rs | 5 +- ui-iced/src/settings.rs | 89 ++++++++++++++++++++++++--- ui-iced/src/video.rs | 11 ++-- 6 files changed, 182 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a54e6cb..caf7d23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -688,6 +688,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bindgen" version = "0.71.1" @@ -1038,6 +1058,18 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cargo-hot-protocol" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a718cb9648aec5f3088527d5e5fa4fb2304672c452d157e233f31e39258806" +dependencies = [ + "anyhow", + "bincode 2.0.1", + "log", + "subsecond", +] + [[package]] name = "cbc" version = "0.1.2" @@ -3441,7 +3473,7 @@ name = "iced_beacon" version = "0.14.0" source = "git+https://github.com/uttarayan21/iced?branch=0.14#5846d52983d7e2eecc478130ba6373f0c1f82c94" dependencies = [ - "bincode", + "bincode 1.3.3", "futures", "iced_core", "log", @@ -3485,6 +3517,7 @@ name = "iced_debug" version = "0.14.0" source = "git+https://github.com/uttarayan21/iced?branch=0.14#5846d52983d7e2eecc478130ba6373f0c1f82c94" dependencies = [ + "cargo-hot-protocol", "iced_beacon", "iced_core", "iced_futures", @@ -4435,6 +4468,15 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memfd" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" +dependencies = [ + "rustix 1.1.3", +] + [[package]] name = "memmap2" version = "0.9.9" @@ -7148,6 +7190,34 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "subsecond" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c09bc2c9ef0381b403ab8b58122961cb83266d16b1f55f9486d5857ba4a9ae26" +dependencies = [ + "js-sys", + "libc", + "libloading", + "memfd", + "memmap2", + "serde", + "subsecond-types", + "thiserror 2.0.17", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "subsecond-types" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07aa455c66ddfdbb51507537402b961e027846468954ef8d974bce65dff9eb0" +dependencies = [ + "serde", +] + [[package]] name = "subtle" version = "2.6.1" @@ -8036,6 +8106,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "url" version = "2.5.7" @@ -8183,6 +8259,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "vswhom" version = "0.1.0" diff --git a/crates/iced-video/examples/minimal.rs b/crates/iced-video/examples/minimal.rs index 561d32b..4cb196f 100644 --- a/crates/iced-video/examples/minimal.rs +++ b/crates/iced-video/examples/minimal.rs @@ -11,9 +11,12 @@ pub fn main() -> iced::Result { .with(tracing_subscriber::EnvFilter::from_default_env()) .init(); iced::application(State::new, update, view) - .subscription(|state| match &state.video { - Some(video) => video.subscription_with(state, keyboard_event), - None => keyboard_event(state), + .subscription(|state| { + // Foo + match &state.video { + Some(video) => video.subscription_with(state, keyboard_event), + None => keyboard_event(state), + } }) .run() } diff --git a/ui-iced/Cargo.toml b/ui-iced/Cargo.toml index 08a9cb9..263f9ac 100644 --- a/ui-iced/Cargo.toml +++ b/ui-iced/Cargo.toml @@ -9,14 +9,15 @@ api = { version = "0.1.0", path = "../api" } blurhash = "0.2.3" bytes = "1.11.0" gpui_util = "0.2.2" -iced = { workspace = true, default-features = true, features = [ +iced = { workspace = true, features = [ "advanced", "canvas", "image", "sipper", "tokio", "debug", -] } + "hot", +], default-features = true } iced-video = { workspace = true } diff --git a/ui-iced/src/lib.rs b/ui-iced/src/lib.rs index c0acaca..e202f73 100644 --- a/ui-iced/src/lib.rs +++ b/ui-iced/src/lib.rs @@ -140,7 +140,7 @@ struct State { screen: Screen, settings: settings::SettingsState, is_authenticated: bool, - video: Option>, + video: Option>>, } impl State { @@ -187,9 +187,8 @@ pub enum Message { } fn update(state: &mut State, message: Message) -> Task { - // if let Some(client) = state.jellyfin_client.clone() { match message { - Message::Settings(msg) => settings::update(&mut state.settings, msg), + Message::Settings(msg) => settings::update(state, msg), Message::OpenItem(id) => { if let Some(client) = state.jellyfin_client.clone() { use api::jellyfin::BaseItemKind::*; diff --git a/ui-iced/src/settings.rs b/ui-iced/src/settings.rs index db73d92..1db6d23 100644 --- a/ui-iced/src/settings.rs +++ b/ui-iced/src/settings.rs @@ -1,16 +1,24 @@ use crate::*; use iced::Element; +// mod widget; pub fn settings(state: &State) -> Element<'_, Message> { - empty() + screens::settings(state) } -pub fn update(_state: &mut SettingsState, message: SettingsMessage) -> Task { +pub fn update(state: &mut State, message: SettingsMessage) -> Task { match message { - SettingsMessage::Open => {} - SettingsMessage::Close => {} + SettingsMessage::Open => { + tracing::trace!("Opening settings"); + state.screen = Screen::Settings; + } + SettingsMessage::Close => { + tracing::trace!("Closing settings"); + state.screen = Screen::Home; + } SettingsMessage::Select(screen) => { tracing::trace!("Switching settings screen to {:?}", screen); + state.settings.screen = screen; } } Task::none() @@ -70,13 +78,80 @@ pub struct ServerForm { mod screens { use super::*; + pub fn settings(state: &State) -> Element<'_, Message> { + row([settings_list(state), settings_screen(state)]).into() + } + + pub fn settings_screen(state: &State) -> Element<'_, Message> { + container(match state.settings.screen { + SettingsScreen::Main => main(state), + SettingsScreen::Servers => server(state), + SettingsScreen::Users => user(state), + }) + .width(Length::FillPortion(10)) + .into() + } + + pub fn settings_list(state: &State) -> Element<'_, Message> { + scrollable( + column( + [ + button(center_text("Main")).on_press(Message::Settings( + SettingsMessage::Select(SettingsScreen::Main), + )), + button(center_text("Servers")).on_press(Message::Settings( + SettingsMessage::Select(SettingsScreen::Servers), + )), + button(center_text("Users")).on_press(Message::Settings( + SettingsMessage::Select(SettingsScreen::Users), + )), + ] + .map(|p| p.clip(true).width(Length::Fill).into()), + ) + .width(Length::FillPortion(2)) + // .max_width(Length::FillPortion(3)) + .spacing(10) + .padding(10), + ) + .into() + } + pub fn main(state: &State) -> Element<'_, Message> { - empty() + // placeholder for now + container( + Column::new() + .push(text("Main Settings")) + .push(toggler(true).label("Foobar")) + .spacing(20) + .padding(20), + ) + .into() } pub fn server(state: &State) -> Element<'_, Message> { - empty() + container( + Column::new() + .push(text("Server Settings")) + .push(toggler(false).label("Enable Server")) + .spacing(20) + .padding(20), + ) + .into() } pub fn user(state: &State) -> Element<'_, Message> { - empty() + container( + Column::new() + .push(text("User Settings")) + .push(toggler(true).label("Enable User")) + .spacing(20) + .padding(20), + ) + .into() } } + +pub fn center_text(content: &str) -> Element<'_, Message> { + text(content) + .align_x(Alignment::Center) + .width(Length::Fill) + .into() +} diff --git a/ui-iced/src/video.rs b/ui-iced/src/video.rs index 8374c4a..b7e1f28 100644 --- a/ui-iced/src/video.rs +++ b/ui-iced/src/video.rs @@ -3,7 +3,7 @@ use super::*; pub enum VideoMessage { EndOfStream, Open(url::Url), - Loaded(VideoHandle), + Loaded(VideoHandle), Pause, Play, Seek(f64), @@ -24,7 +24,9 @@ pub fn update(state: &mut State, message: VideoMessage) -> Task { }) } VideoMessage::Loaded(video) => { - state.video = Some(Arc::new(video)); + state.video = Some(Arc::new( + video.on_end_of_stream(Message::Video(VideoMessage::EndOfStream)), + )); Task::done(VideoMessage::Play).map(Message::Video) } VideoMessage::Pause => { @@ -62,13 +64,12 @@ pub fn update(state: &mut State, message: VideoMessage) -> Task { } } -pub fn player(video: &VideoHandle) -> Element<'_, Message> { +pub fn player(video: &VideoHandle) -> Element<'_, Message> { container( Video::new(video) .width(Length::Fill) .height(Length::Fill) - .content_fit(iced::ContentFit::Contain) - .on_end_of_stream(Message::Video(VideoMessage::EndOfStream)), + .content_fit(iced::ContentFit::Contain), ) .style(|_| container::background(iced::Color::BLACK)) .width(Length::Fill)