Implement image viewer example
This commit is contained in:
parent
505588d585
commit
cdd34e1e4b
5 changed files with 245 additions and 18 deletions
202
examples/image.rs
Normal file
202
examples/image.rs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
use iced::{
|
||||
button, image, Align, Application, Background, Button, Color, Column,
|
||||
Command, Container, Element, HorizontalAlignment, Image, Length, Row,
|
||||
Settings, Text,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
pub fn main() {
|
||||
Example::run(Settings::default())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Example {
|
||||
cats_button: button::State,
|
||||
dogs_button: button::State,
|
||||
image: Option<image::Handle>,
|
||||
state: State,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Idle,
|
||||
Loading(Pet),
|
||||
Error(LoadError),
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> State {
|
||||
State::Idle
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
PetChosen(Pet),
|
||||
ImageLoaded(Result<image::Handle, LoadError>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Pet {
|
||||
Cat,
|
||||
Dog,
|
||||
}
|
||||
|
||||
impl Application for Example {
|
||||
type Message = Message;
|
||||
|
||||
fn new() -> (Self, Command<Message>) {
|
||||
(Self::default(), Command::none())
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
String::from("Image viewer - Iced")
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) -> Command<Message> {
|
||||
match message {
|
||||
Message::PetChosen(pet) => match self.state {
|
||||
State::Loading(_) => Command::none(),
|
||||
_ => {
|
||||
self.state = State::Loading(pet);
|
||||
|
||||
Command::perform(get_pet_image(pet), Message::ImageLoaded)
|
||||
}
|
||||
},
|
||||
Message::ImageLoaded(Ok(image)) => {
|
||||
self.image = Some(image);
|
||||
self.state = State::Idle;
|
||||
|
||||
Command::none()
|
||||
}
|
||||
Message::ImageLoaded(Err(error)) => {
|
||||
self.state = State::Error(error);
|
||||
|
||||
Command::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Element<Message> {
|
||||
let Example {
|
||||
cats_button,
|
||||
dogs_button,
|
||||
state,
|
||||
image,
|
||||
} = self;
|
||||
|
||||
let choose: Element<_> = match state {
|
||||
State::Loading(pet) => Text::new(format!(
|
||||
"Getting your {} ready...",
|
||||
match pet {
|
||||
Pet::Cat => "cat",
|
||||
Pet::Dog => "dog",
|
||||
}
|
||||
))
|
||||
.width(Length::Shrink)
|
||||
.color([0.4, 0.4, 0.4])
|
||||
.into(),
|
||||
_ => Row::new()
|
||||
.width(Length::Shrink)
|
||||
.spacing(20)
|
||||
.push(
|
||||
button(
|
||||
cats_button,
|
||||
"Cats",
|
||||
Color::from_rgb8(0x89, 0x80, 0xF5),
|
||||
)
|
||||
.on_press(Message::PetChosen(Pet::Cat)),
|
||||
)
|
||||
.push(
|
||||
button(
|
||||
dogs_button,
|
||||
"Dogs",
|
||||
Color::from_rgb8(0x21, 0xD1, 0x9F),
|
||||
)
|
||||
.on_press(Message::PetChosen(Pet::Dog)),
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
|
||||
let content = Column::new()
|
||||
.width(Length::Shrink)
|
||||
.padding(20)
|
||||
.spacing(20)
|
||||
.align_items(Align::Center)
|
||||
.push(
|
||||
Text::new("What do you want to see?")
|
||||
.width(Length::Shrink)
|
||||
.horizontal_alignment(HorizontalAlignment::Center)
|
||||
.size(40),
|
||||
)
|
||||
.push(choose);
|
||||
|
||||
let content = if let Some(image) = image {
|
||||
content.push(Image::new(image.clone()).height(Length::Fill))
|
||||
} else {
|
||||
content
|
||||
};
|
||||
|
||||
Container::new(content)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn button<'a, Message>(
|
||||
state: &'a mut button::State,
|
||||
label: &str,
|
||||
color: Color,
|
||||
) -> Button<'a, Message> {
|
||||
Button::new(
|
||||
state,
|
||||
Text::new(label)
|
||||
.horizontal_alignment(HorizontalAlignment::Center)
|
||||
.color(Color::WHITE)
|
||||
.size(30),
|
||||
)
|
||||
.padding(10)
|
||||
.min_width(100)
|
||||
.border_radius(10)
|
||||
.background(Background::Color(color))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SearchResult {
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum LoadError {
|
||||
RequestError,
|
||||
}
|
||||
|
||||
async fn get_pet_image(pet: Pet) -> Result<image::Handle, LoadError> {
|
||||
use std::io::Read;
|
||||
|
||||
let search = match pet {
|
||||
Pet::Cat => "https://api.thecatapi.com/v1/images/search?limit=1&mime_types=jpg,png",
|
||||
Pet::Dog => "https://api.thedogapi.com/v1/images/search?limit=1&mime_types=jpg,png",
|
||||
};
|
||||
|
||||
let results: Vec<SearchResult> = reqwest::get(search)?.json()?;
|
||||
let url = &results.first().unwrap().url;
|
||||
|
||||
let mut image = reqwest::get(url)?;
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
image
|
||||
.read_to_end(&mut bytes)
|
||||
.map_err(|_| LoadError::RequestError)?;
|
||||
|
||||
Ok(image::Handle::from_bytes(bytes))
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for LoadError {
|
||||
fn from(error: reqwest::Error) -> LoadError {
|
||||
dbg!(&error);
|
||||
LoadError::RequestError
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue