diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/image.rs | 202 | ||||
| -rw-r--r-- | examples/pokedex.rs | 231 | 
2 files changed, 231 insertions, 202 deletions
| diff --git a/examples/image.rs b/examples/image.rs deleted file mode 100644 index a64c0782..00000000 --- a/examples/image.rs +++ /dev/null @@ -1,202 +0,0 @@ -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 -    } -} diff --git a/examples/pokedex.rs b/examples/pokedex.rs new file mode 100644 index 00000000..8e0af7b2 --- /dev/null +++ b/examples/pokedex.rs @@ -0,0 +1,231 @@ +use iced::{ +    button, image, Align, Application, Background, Button, Color, Column, +    Command, Container, Element, Image, Length, Row, Settings, Text, +}; + +pub fn main() { +    Pokedex::run(Settings::default()) +} + +#[derive(Debug)] +enum Pokedex { +    Loading, +    Loaded { +        pokemon: Pokemon, +        search: button::State, +    }, +    Errored { +        error: Error, +        try_again: button::State, +    }, +} + +#[derive(Debug, Clone)] +enum Message { +    PokemonFound(Result<Pokemon, Error>), +    Search, +} + +impl Application for Pokedex { +    type Message = Message; + +    fn new() -> (Pokedex, Command<Message>) { +        ( +            Pokedex::Loading, +            Command::perform(Pokemon::search(), Message::PokemonFound), +        ) +    } + +    fn title(&self) -> String { +        let subtitle = match self { +            Pokedex::Loading => "Loading", +            Pokedex::Loaded { pokemon, .. } => &pokemon.name, +            Pokedex::Errored { .. } => "Whoops!", +        }; + +        format!("{} - Pokédex", subtitle) +    } + +    fn update(&mut self, message: Message) -> Command<Message> { +        match message { +            Message::PokemonFound(Ok(pokemon)) => { +                *self = Pokedex::Loaded { +                    pokemon, +                    search: button::State::new(), +                }; + +                Command::none() +            } +            Message::PokemonFound(Err(error)) => { +                *self = Pokedex::Errored { +                    error, +                    try_again: button::State::new(), +                }; + +                Command::none() +            } +            Message::Search => match self { +                Pokedex::Loading => Command::none(), +                _ => { +                    *self = Pokedex::Loading; + +                    Command::perform(Pokemon::search(), Message::PokemonFound) +                } +            }, +        } +    } + +    fn view(&mut self) -> Element<Message> { +        let content = match self { +            Pokedex::Loading => Column::new().width(Length::Shrink).push( +                Text::new("Searching for Pokémon...") +                    .width(Length::Shrink) +                    .size(40), +            ), +            Pokedex::Loaded { pokemon, search } => Column::new() +                .max_width(500) +                .spacing(20) +                .align_items(Align::End) +                .push(pokemon.view()) +                .push( +                    button(search, "Keep searching!").on_press(Message::Search), +                ), +            Pokedex::Errored { try_again, .. } => Column::new() +                .width(Length::Shrink) +                .spacing(20) +                .align_items(Align::End) +                .push( +                    Text::new("Whoops! Something went wrong...") +                        .width(Length::Shrink) +                        .size(40), +                ) +                .push(button(try_again, "Try again").on_press(Message::Search)), +        }; + +        Container::new(content) +            .width(Length::Fill) +            .height(Length::Fill) +            .center_x() +            .center_y() +            .into() +    } +} + +#[derive(Debug, Clone)] +struct Pokemon { +    number: u16, +    name: String, +    description: String, +    image: image::Handle, +} + +impl Pokemon { +    const TOTAL: u16 = 807; + +    fn view(&self) -> Element<Message> { +        Row::new() +            .spacing(20) +            .align_items(Align::Center) +            .push(Image::new(self.image.clone())) +            .push( +                Column::new() +                    .spacing(20) +                    .push( +                        Row::new() +                            .align_items(Align::Center) +                            .spacing(20) +                            .push(Text::new(&self.name).size(30)) +                            .push( +                                Text::new(format!("#{}", self.number)) +                                    .width(Length::Shrink) +                                    .size(20) +                                    .color([0.5, 0.5, 0.5]), +                            ), +                    ) +                    .push(Text::new(&self.description)), +            ) +            .into() +    } + +    async fn search() -> Result<Pokemon, Error> { +        use rand::Rng; +        use serde::Deserialize; +        use std::io::Read; + +        #[derive(Debug, Deserialize)] +        struct Entry { +            id: u32, +            name: String, +            flavor_text_entries: Vec<FlavorText>, +        } + +        #[derive(Debug, Deserialize)] +        struct FlavorText { +            flavor_text: String, +            language: Language, +        } + +        #[derive(Debug, Deserialize)] +        struct Language { +            name: String, +        } + +        let id = { +            let mut rng = rand::thread_rng(); + +            rng.gen_range(0, Pokemon::TOTAL) +        }; + +        let url = format!("https://pokeapi.co/api/v2/pokemon-species/{}", id); +        let sprite = format!("https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png", id); + +        let entry: Entry = reqwest::get(&url)?.json()?; + +        let description = entry +            .flavor_text_entries +            .iter() +            .filter(|text| text.language.name == "en") +            .next() +            .ok_or(Error::LanguageError)?; + +        let mut sprite = reqwest::get(&sprite)?; +        let mut bytes = Vec::new(); + +        sprite +            .read_to_end(&mut bytes) +            .map_err(|_| Error::ImageError)?; + +        Ok(Pokemon { +            number: id, +            name: entry.name.to_uppercase(), +            description: description +                .flavor_text +                .chars() +                .map(|c| if c.is_control() { ' ' } else { c }) +                .collect(), +            image: image::Handle::from_memory(bytes), +        }) +    } +} + +#[derive(Debug, Clone)] +enum Error { +    APIError, +    ImageError, +    LanguageError, +} + +impl From<reqwest::Error> for Error { +    fn from(error: reqwest::Error) -> Error { +        dbg!(&error); + +        Error::APIError +    } +} + +fn button<'a>(state: &'a mut button::State, text: &str) -> Button<'a, Message> { +    Button::new(state, Text::new(text).color(Color::WHITE)) +        .background(Background::Color([0.11, 0.42, 0.87].into())) +        .border_radius(10) +        .padding(10) +} | 
