summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--examples/events.rs91
-rw-r--r--examples/pokedex.rs23
-rw-r--r--examples/stopwatch.rs182
-rw-r--r--examples/todos.rs27
4 files changed, 298 insertions, 25 deletions
diff --git a/examples/events.rs b/examples/events.rs
new file mode 100644
index 00000000..7d83fbd8
--- /dev/null
+++ b/examples/events.rs
@@ -0,0 +1,91 @@
+use iced::{
+ Align, Application, Checkbox, Column, Command, Container, Element, Length,
+ Settings, Subscription, Text,
+};
+
+pub fn main() {
+ Events::run(Settings::default())
+}
+
+#[derive(Debug, Default)]
+struct Events {
+ last: Vec<iced_native::Event>,
+ enabled: bool,
+}
+
+#[derive(Debug, Clone)]
+enum Message {
+ EventOccurred(iced_native::Event),
+ Toggled(bool),
+}
+
+impl Application for Events {
+ type Message = Message;
+
+ fn new() -> (Events, Command<Message>) {
+ (Events::default(), Command::none())
+ }
+
+ fn title(&self) -> String {
+ String::from("Events - Iced")
+ }
+
+ fn update(&mut self, message: Message) -> Command<Message> {
+ match message {
+ Message::EventOccurred(event) => {
+ self.last.push(event);
+
+ if self.last.len() > 5 {
+ let _ = self.last.remove(0);
+ }
+ }
+ Message::Toggled(enabled) => {
+ self.enabled = enabled;
+ }
+ };
+
+ Command::none()
+ }
+
+ fn subscription(&self) -> Subscription<Message> {
+ if self.enabled {
+ iced_native::subscription::events().map(Message::EventOccurred)
+ } else {
+ Subscription::none()
+ }
+ }
+
+ fn view(&mut self) -> Element<Message> {
+ let events = self.last.iter().fold(
+ Column::new().width(Length::Shrink).spacing(10),
+ |column, event| {
+ column.push(
+ Text::new(format!("{:?}", event))
+ .size(40)
+ .width(Length::Shrink),
+ )
+ },
+ );
+
+ let toggle = Checkbox::new(
+ self.enabled,
+ "Listen to runtime events",
+ Message::Toggled,
+ )
+ .width(Length::Shrink);
+
+ let content = Column::new()
+ .width(Length::Shrink)
+ .align_items(Align::Center)
+ .spacing(20)
+ .push(events)
+ .push(toggle);
+
+ Container::new(content)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .into()
+ }
+}
diff --git a/examples/pokedex.rs b/examples/pokedex.rs
index b9daeabd..2d595ec4 100644
--- a/examples/pokedex.rs
+++ b/examples/pokedex.rs
@@ -150,7 +150,6 @@ impl Pokemon {
async fn search() -> Result<Pokemon, Error> {
use rand::Rng;
use serde::Deserialize;
- use std::io::Read;
#[derive(Debug, Deserialize)]
struct Entry {
@@ -179,7 +178,11 @@ impl Pokemon {
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 (entry, sprite): (Entry, _) = futures::future::try_join(
+ surf::get(&url).recv_json(),
+ surf::get(&sprite).recv_bytes(),
+ )
+ .await?;
let description = entry
.flavor_text_entries
@@ -188,13 +191,6 @@ impl Pokemon {
.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(),
@@ -203,7 +199,7 @@ impl Pokemon {
.chars()
.map(|c| if c.is_control() { ' ' } else { c })
.collect(),
- image: image::Handle::from_memory(bytes),
+ image: image::Handle::from_memory(sprite),
})
}
}
@@ -211,13 +207,12 @@ impl Pokemon {
#[derive(Debug, Clone)]
enum Error {
APIError,
- ImageError,
LanguageError,
}
-impl From<reqwest::Error> for Error {
- fn from(error: reqwest::Error) -> Error {
- dbg!(&error);
+impl From<surf::Exception> for Error {
+ fn from(exception: surf::Exception) -> Error {
+ dbg!(&exception);
Error::APIError
}
diff --git a/examples/stopwatch.rs b/examples/stopwatch.rs
new file mode 100644
index 00000000..7a7f0793
--- /dev/null
+++ b/examples/stopwatch.rs
@@ -0,0 +1,182 @@
+use iced::{
+ button, Align, Application, Background, Button, Color, Column, Command,
+ Container, Element, HorizontalAlignment, Length, Row, Settings,
+ Subscription, Text,
+};
+use std::time::{Duration, Instant};
+
+pub fn main() {
+ Stopwatch::run(Settings::default())
+}
+
+struct Stopwatch {
+ duration: Duration,
+ state: State,
+ toggle: button::State,
+ reset: button::State,
+}
+
+enum State {
+ Idle,
+ Ticking { last_tick: Instant },
+}
+
+#[derive(Debug, Clone)]
+enum Message {
+ Toggle,
+ Reset,
+ Tick(Instant),
+}
+
+impl Application for Stopwatch {
+ type Message = Message;
+
+ fn new() -> (Stopwatch, Command<Message>) {
+ (
+ Stopwatch {
+ duration: Duration::default(),
+ state: State::Idle,
+ toggle: button::State::new(),
+ reset: button::State::new(),
+ },
+ Command::none(),
+ )
+ }
+
+ fn title(&self) -> String {
+ String::from("Stopwatch - Iced")
+ }
+
+ fn update(&mut self, message: Message) -> Command<Message> {
+ match message {
+ Message::Toggle => match self.state {
+ State::Idle => {
+ self.state = State::Ticking {
+ last_tick: Instant::now(),
+ };
+ }
+ State::Ticking { .. } => {
+ self.state = State::Idle;
+ }
+ },
+ Message::Tick(now) => match &mut self.state {
+ State::Ticking { last_tick } => {
+ self.duration += now - *last_tick;
+ *last_tick = now;
+ }
+ _ => {}
+ },
+ Message::Reset => {
+ self.duration = Duration::default();
+ }
+ }
+
+ Command::none()
+ }
+
+ fn subscription(&self) -> Subscription<Message> {
+ match self.state {
+ State::Idle => Subscription::none(),
+ State::Ticking { .. } => {
+ time::every(Duration::from_millis(10)).map(Message::Tick)
+ }
+ }
+ }
+
+ fn view(&mut self) -> Element<Message> {
+ const MINUTE: u64 = 60;
+ const HOUR: u64 = 60 * MINUTE;
+
+ let seconds = self.duration.as_secs();
+
+ let duration = Text::new(format!(
+ "{:0>2}:{:0>2}:{:0>2}.{:0>2}",
+ seconds / HOUR,
+ (seconds % HOUR) / MINUTE,
+ seconds % MINUTE,
+ self.duration.subsec_millis() / 10,
+ ))
+ .width(Length::Shrink)
+ .size(40);
+
+ let button = |state, label, color: [f32; 3]| {
+ Button::new(
+ state,
+ Text::new(label)
+ .color(Color::WHITE)
+ .horizontal_alignment(HorizontalAlignment::Center),
+ )
+ .min_width(80)
+ .background(Background::Color(color.into()))
+ .border_radius(10)
+ .padding(10)
+ };
+
+ let toggle_button = {
+ let (label, color) = match self.state {
+ State::Idle => ("Start", [0.11, 0.42, 0.87]),
+ State::Ticking { .. } => ("Stop", [0.9, 0.4, 0.4]),
+ };
+
+ button(&mut self.toggle, label, color).on_press(Message::Toggle)
+ };
+
+ let reset_button = button(&mut self.reset, "Reset", [0.7, 0.7, 0.7])
+ .on_press(Message::Reset);
+
+ let controls = Row::new()
+ .width(Length::Shrink)
+ .spacing(20)
+ .push(toggle_button)
+ .push(reset_button);
+
+ let content = Column::new()
+ .width(Length::Shrink)
+ .align_items(Align::Center)
+ .spacing(20)
+ .push(duration)
+ .push(controls);
+
+ Container::new(content)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .into()
+ }
+}
+
+mod time {
+ pub fn every(
+ duration: std::time::Duration,
+ ) -> iced::Subscription<std::time::Instant> {
+ iced::Subscription::from_recipe(Every(duration))
+ }
+
+ struct Every(std::time::Duration);
+
+ impl<H, I> iced_native::subscription::Recipe<H, I> for Every
+ where
+ H: std::hash::Hasher,
+ {
+ type Output = std::time::Instant;
+
+ fn hash(&self, state: &mut H) {
+ use std::hash::Hash;
+
+ std::any::TypeId::of::<Self>().hash(state);
+ self.0.hash(state);
+ }
+
+ fn stream(
+ self: Box<Self>,
+ _input: I,
+ ) -> futures::stream::BoxStream<'static, Self::Output> {
+ use futures::stream::StreamExt;
+
+ async_std::stream::interval(self.0)
+ .map(|_| std::time::Instant::now())
+ .boxed()
+ }
+ }
+}
diff --git a/examples/todos.rs b/examples/todos.rs
index 5f435fdc..42e88f65 100644
--- a/examples/todos.rs
+++ b/examples/todos.rs
@@ -517,21 +517,23 @@ impl SavedState {
}
async fn load() -> Result<SavedState, LoadError> {
- use std::io::Read;
+ use async_std::prelude::*;
let mut contents = String::new();
- let mut file = std::fs::File::open(Self::path())
+ let mut file = async_std::fs::File::open(Self::path())
+ .await
.map_err(|_| LoadError::FileError)?;
file.read_to_string(&mut contents)
+ .await
.map_err(|_| LoadError::FileError)?;
serde_json::from_str(&contents).map_err(|_| LoadError::FormatError)
}
async fn save(self) -> Result<(), SaveError> {
- use std::io::Write;
+ use async_std::prelude::*;
let json = serde_json::to_string_pretty(&self)
.map_err(|_| SaveError::FormatError)?;
@@ -539,20 +541,23 @@ impl SavedState {
let path = Self::path();
if let Some(dir) = path.parent() {
- std::fs::create_dir_all(dir)
+ async_std::fs::create_dir_all(dir)
+ .await
.map_err(|_| SaveError::DirectoryError)?;
}
- let mut file =
- std::fs::File::create(path).map_err(|_| SaveError::FileError)?;
+ {
+ let mut file = async_std::fs::File::create(path)
+ .await
+ .map_err(|_| SaveError::FileError)?;
- file.write_all(json.as_bytes())
- .map_err(|_| SaveError::WriteError)?;
+ file.write_all(json.as_bytes())
+ .await
+ .map_err(|_| SaveError::WriteError)?;
+ }
// This is a simple way to save at most once every couple seconds
- // We will be able to get rid of it once we implement event
- // subscriptions
- std::thread::sleep(std::time::Duration::from_secs(2));
+ async_std::task::sleep(std::time::Duration::from_secs(2)).await;
Ok(())
}