diff options
| author | 2020-03-23 21:36:26 +0100 | |
|---|---|---|
| committer | 2020-03-23 21:36:26 +0100 | |
| commit | 784b8ee74c15f682b5bab74ac7d475fbed20e937 (patch) | |
| tree | 3802215b31cdc71749ae7ae6eda948fffa1b2fba /examples/download_progress/src/download.rs | |
| parent | 092e9fb4cc3edcf2083b4464d24d50c82a1163d2 (diff) | |
| parent | 8e0dcd212d71ff334aa590ee3b565da7b8d24713 (diff) | |
| download | iced-784b8ee74c15f682b5bab74ac7d475fbed20e937.tar.gz iced-784b8ee74c15f682b5bab74ac7d475fbed20e937.tar.bz2 iced-784b8ee74c15f682b5bab74ac7d475fbed20e937.zip | |
Merge pull request #232 from Songtronix/songtronix/add-download-example
Add example for download with progress tracking
Diffstat (limited to 'examples/download_progress/src/download.rs')
| -rw-r--r-- | examples/download_progress/src/download.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/examples/download_progress/src/download.rs b/examples/download_progress/src/download.rs new file mode 100644 index 00000000..96e1dc28 --- /dev/null +++ b/examples/download_progress/src/download.rs @@ -0,0 +1,110 @@ +use iced_futures::futures; + +// Just a little utility function +pub fn file<T: ToString>(url: T) -> iced::Subscription<Progress> { + iced::Subscription::from_recipe(Download { + url: url.to_string(), + }) +} + +pub struct Download { + url: String, +} + +// Make sure iced can use our download stream +impl<H, I> iced_native::subscription::Recipe<H, I> for Download +where + H: std::hash::Hasher, +{ + type Output = Progress; + + fn hash(&self, state: &mut H) { + use std::hash::Hash; + std::any::TypeId::of::<Self>().hash(state); + } + + fn stream( + self: Box<Self>, + _input: futures::stream::BoxStream<'static, I>, + ) -> futures::stream::BoxStream<'static, Self::Output> { + Box::pin(futures::stream::unfold( + State::Ready(self.url), + |state| async move { + match state { + State::Ready(url) => { + let response = reqwest::get(&url).await; + + match response { + Ok(response) => { + if let Some(total) = response.content_length() { + Some(( + Progress::Started, + State::Downloading { + response, + total, + downloaded: 0, + }, + )) + } else { + Some((Progress::Errored, State::Finished)) + } + } + Err(_) => { + Some((Progress::Errored, State::Finished)) + } + } + } + State::Downloading { + mut response, + total, + downloaded, + } => match response.chunk().await { + Ok(Some(chunk)) => { + let downloaded = downloaded + chunk.len() as u64; + + let percentage = + (downloaded as f32 / total as f32) * 100.0; + + Some(( + Progress::Advanced(percentage), + State::Downloading { + response, + total, + downloaded, + }, + )) + } + Ok(None) => Some((Progress::Finished, State::Finished)), + Err(_) => Some((Progress::Errored, State::Finished)), + }, + State::Finished => { + // We do not let the stream die, as it would start a + // new download repeatedly if the user is not careful + // in case of errors. + let _: () = iced::futures::future::pending().await; + + None + } + } + }, + )) + } +} + +#[derive(Debug, Clone)] +pub enum Progress { + Started, + Advanced(f32), + Finished, + Errored, +} + +pub enum State { + Ready(String), + Downloading { + response: reqwest::Response, + total: u64, + downloaded: u64, + }, + Finished, +} |
