summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-12-04 03:55:33 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-12-04 03:55:33 +0100
commit4293dcb2540144cc69a9f1370103bb780eca69f3 (patch)
treeb47a014a0f3b09f005c710fb4df6795e716931bc
parent1747eb2745d032275dff652aed2c4d8730d377e6 (diff)
downloadiced-4293dcb2540144cc69a9f1370103bb780eca69f3.tar.gz
iced-4293dcb2540144cc69a9f1370103bb780eca69f3.tar.bz2
iced-4293dcb2540144cc69a9f1370103bb780eca69f3.zip
Rename `image::Handle::from_bytes` to `from_memory`
Also, replace `image` example with a new `pokedex` example using the PokéAPI.
Diffstat (limited to '')
-rw-r--r--Cargo.toml1
-rw-r--r--examples/image.rs202
-rw-r--r--examples/pokedex.rs231
-rw-r--r--native/src/widget/image.rs5
4 files changed, 236 insertions, 203 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 71d3b3cd..888a1c07 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,6 +40,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
directories = "2.0"
reqwest = "0.9"
+rand = "0.7"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen = "0.2.51"
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)
+}
diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs
index 1b3964d7..0d73fdb0 100644
--- a/native/src/widget/image.rs
+++ b/native/src/widget/image.rs
@@ -126,8 +126,11 @@ impl Handle {
/// Creates an image [`Handle`] containing the image data directly.
///
+ /// This is useful if you already have your image loaded in-memory, maybe
+ /// because you downloaded or generated it procedurally.
+ ///
/// [`Handle`]: struct.Handle.html
- pub fn from_bytes(bytes: Vec<u8>) -> Handle {
+ pub fn from_memory(bytes: Vec<u8>) -> Handle {
Self::from_data(Data::Bytes(bytes))
}