Add Loading and Fallback States to Image Elements (via StyledImage) (#20371)
@iamnbutler edit:
This pull request enhances the image element by introducing the ability
to display loading and fallback states.
Changes:
- Implemented the loading and fallback states for image elements using
`.with_loading` and `.with_fallback` respectively.
- Introduced the `StyledImage` trait and `ImageStyle` to enable a fluent
API for changing image styles across image types (`Img`,
`Stateful<Img>`, etc).
Example Usage:
```rust
fn loading_element() -> impl IntoElement {
div().size_full().flex_none().p_0p5().rounded_sm().child(
div().size_full().with_animation(
"loading-bg",
Animation::new(Duration::from_secs(3))
.repeat()
.with_easing(pulsating_between(0.04, 0.24)),
move |this, delta| this.bg(black().opacity(delta)),
),
)
}
fn fallback_element() -> impl IntoElement {
let fallback_color: Hsla = black().opacity(0.5);
div().size_full().flex_none().p_0p5().child(
div()
.size_full()
.flex()
.items_center()
.justify_center()
.rounded_sm()
.text_sm()
.text_color(fallback_color)
.border_1()
.border_color(fallback_color)
.child("?"),
)
}
impl Render for ImageLoadingExample {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
img("some/image/path")
.id("image-1")
.with_fallback(|| Self::fallback_element().into_any_element())
.with_loading(|| Self::loading_element().into_any_element())
}
}
```
Note:
An `Img` must have an `id` to be able to add a loading state.
Release Notes:
- N/A
---------
Co-authored-by: nate <nate@zed.dev>
Co-authored-by: michael <michael@zed.dev>
Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Antonio Scandurra <me@as-cii.com>
2024-11-16 03:12:01 +00:00
|
|
|
use gpui::{div, img, prelude::*, App, AppContext, Render, ViewContext, WindowOptions};
|
2024-07-27 12:05:37 +00:00
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
struct GifViewer {
|
|
|
|
gif_path: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GifViewer {
|
|
|
|
fn new(gif_path: PathBuf) -> Self {
|
|
|
|
Self { gif_path }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Render for GifViewer {
|
|
|
|
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
|
|
|
div().size_full().child(
|
Add Loading and Fallback States to Image Elements (via StyledImage) (#20371)
@iamnbutler edit:
This pull request enhances the image element by introducing the ability
to display loading and fallback states.
Changes:
- Implemented the loading and fallback states for image elements using
`.with_loading` and `.with_fallback` respectively.
- Introduced the `StyledImage` trait and `ImageStyle` to enable a fluent
API for changing image styles across image types (`Img`,
`Stateful<Img>`, etc).
Example Usage:
```rust
fn loading_element() -> impl IntoElement {
div().size_full().flex_none().p_0p5().rounded_sm().child(
div().size_full().with_animation(
"loading-bg",
Animation::new(Duration::from_secs(3))
.repeat()
.with_easing(pulsating_between(0.04, 0.24)),
move |this, delta| this.bg(black().opacity(delta)),
),
)
}
fn fallback_element() -> impl IntoElement {
let fallback_color: Hsla = black().opacity(0.5);
div().size_full().flex_none().p_0p5().child(
div()
.size_full()
.flex()
.items_center()
.justify_center()
.rounded_sm()
.text_sm()
.text_color(fallback_color)
.border_1()
.border_color(fallback_color)
.child("?"),
)
}
impl Render for ImageLoadingExample {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
img("some/image/path")
.id("image-1")
.with_fallback(|| Self::fallback_element().into_any_element())
.with_loading(|| Self::loading_element().into_any_element())
}
}
```
Note:
An `Img` must have an `id` to be able to add a loading state.
Release Notes:
- N/A
---------
Co-authored-by: nate <nate@zed.dev>
Co-authored-by: michael <michael@zed.dev>
Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Antonio Scandurra <me@as-cii.com>
2024-11-16 03:12:01 +00:00
|
|
|
img(self.gif_path.clone())
|
2024-07-27 12:05:37 +00:00
|
|
|
.size_full()
|
|
|
|
.object_fit(gpui::ObjectFit::Contain)
|
|
|
|
.id("gif"),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
env_logger::init();
|
|
|
|
App::new().run(|cx: &mut AppContext| {
|
|
|
|
let cwd = std::env::current_dir().expect("Failed to get current working directory");
|
|
|
|
let gif_path = cwd.join("crates/gpui/examples/image/black-cat-typing.gif");
|
|
|
|
|
|
|
|
if !gif_path.exists() {
|
|
|
|
eprintln!("Image file not found at {:?}", gif_path);
|
|
|
|
eprintln!("Make sure you're running this example from the root of the gpui crate");
|
|
|
|
cx.quit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cx.open_window(
|
|
|
|
WindowOptions {
|
|
|
|
focus: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
|cx| cx.new_view(|_cx| GifViewer::new(gif_path)),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
cx.activate(true);
|
|
|
|
});
|
|
|
|
}
|