Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access proxy #1969

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/proxy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "proxy"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
iced = { path = "../.." }
notify = "6.0.1"
futures = "0.3.28"
38 changes: 38 additions & 0 deletions examples/proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
this example show how having Proxy could be useful.


the important code part are in here:

```
let mut watcher = RecommendedWatcher::new(
move |res: Result<Event, notify::Error>| {
proxy.send(AppMsg::Event(res.unwrap()))
},
Config::default(),
)
.unwrap();

```

`notify::RecommendedWatcher` have his own runtime to watch event on fs.

Currently, the only way to use it in Iced is by using subscription. This is not easy to use and can even lead to issues.

imagine you want to see what files are in a dir, and also be notified when fs events occurs in it.

### with Subscription
```
sender.send(Action::Watch(path)) // sender is send by using subscription::channel

// ... time ... (another process)
// anything on the fs could happend (lead to error)

fetch_dir(path)
```

### with proxy
```
// we can have the watcher inside our struct
watcher.watch(path)
fetch_dir(path)
```
43 changes: 43 additions & 0 deletions examples/proxy/src/explorer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use notify::{Config, Event, EventKind, INotifyWatcher, RecommendedWatcher, Watcher};

Check failure on line 1 in examples/proxy/src/explorer.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/explorer.rs

pub struct Explorer {
pub nb_deleted: i32,
#[allow(dead_code)]
watcher: INotifyWatcher,
}

impl Explorer {
pub fn new(path: PathBuf, proxy: Proxy<AppMsg>) -> Option<Self> {
if !path.is_dir() {
println!("path is not a dir");
return None;
}

let mut watcher = RecommendedWatcher::new(
move |res: Result<Event, notify::Error>| {
proxy.send(AppMsg::Event(res.unwrap()))
},
Config::default(),
)
.unwrap();

watcher
.watch(&path, notify::RecursiveMode::NonRecursive)
.unwrap();

println!("watching {}", path.to_string_lossy());

let explorer = Explorer {
nb_deleted: 0,
watcher,
};

Some(explorer)
}

pub fn process_event(&mut self, event: Event) {
if let EventKind::Remove(_) = event.kind {
self.nb_deleted += 1;
}
}
}
115 changes: 115 additions & 0 deletions examples/proxy/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use std::path::PathBuf;

Check failure on line 2 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs
use explorer::Explorer;
use iced::{
proxy,
executor,
widget::{Column, Text, TextInput},
Application, Command, Length, Settings,
};
use notify::Event;

mod explorer;

fn main() {
State::run(Settings::default()).unwrap()
}

enum State {
Loading,
Loaded(App),
}
struct App {

Check failure on line 22 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs
path: String,
explorer: Option<Explorer>,
proxy: proxy::Proxy
}

impl App {
fn new(proxy: proxy::Proxy) -> Self {
App {

Check failure on line 30 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs
path: String::new(),
explorer: None,
proxy
}
}
}

#[derive(Debug, Clone)]
enum AppMsg {
OnInput(String),
OnSubmit,
ProxyReceived(proxy::Proxy),
Event(Event),
}

impl Application for State {
type Executor = executor::Default;
type Message = AppMsg;
type Theme = iced::Theme;
type Flags = ();

Check failure on line 50 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs

fn new(_flags: Self::Flags) -> (Self, iced::Command<Self::Message>) {
(
State::Loading,
proxy::fetch_proxy(Message::ProxyReceived)
)
}

fn title(&self) -> String {
String::from("App")

Check failure on line 60 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs
}

fn update(&mut self, message: Self::Message) -> iced::Command<Self::Message> {
match self {
State::Loading => {
if let AppMsg::ProxyReceived(proxy) = message {
*self = State::Loaded(App::new(proxy))
}
}
State::Loaded(app) => match message {
AppMsg::OnInput(input) => {
app.path = input;

Check failure on line 72 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs
}
AppMsg::OnSubmit => {
app.explorer = Explorer::new(PathBuf::from(app.path.clone()), app.proxy.clone());
}
AppMsg::Event(e) => {
if let Some(explorer) = &mut app.explorer {
explorer.process_event(e);
}
}
_ => {}
},
}

Command::none()

Check failure on line 86 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs
}

fn view(&self) -> iced::Element<'_, Self::Message, iced::Renderer<Self::Theme>> {
match self {
State::Loading => Text::new("loading").into(),
State::Loaded(app) => {
let input = TextInput::new("path", &app.path)
.on_input(AppMsg::OnInput)
.on_submit(AppMsg::OnSubmit)
.into();

let mut childs = Vec::new();

childs.push(input);

Check failure on line 100 in examples/proxy/src/main.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/examples/proxy/src/main.rs

if let Some(explorer) = &app.explorer {
let text = Text::new(explorer.nb_deleted.to_string()).into();
childs.push(text);
}

Column::with_children(childs)
.width(Length::Fill)
.height(Length::Fill)
.align_items(iced::Alignment::Center)
.into()
}
}
}
}
5 changes: 5 additions & 0 deletions runtime/src/command/action.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::clipboard;
use crate::core::widget;
use crate::font;
use crate::proxy;
use crate::system;
use crate::window;

Expand Down Expand Up @@ -38,6 +39,8 @@
/// The message to produce when the font has been loaded.
tagger: Box<dyn Fn(Result<(), font::Error>) -> T>,
},
///
Proxy(proxy::Action<T>),
}

impl<T> Action<T> {
Expand Down Expand Up @@ -66,6 +69,7 @@
bytes,
tagger: Box::new(move |result| f(tagger(result))),
},
Self::Proxy(proxy) => Action::Proxy(proxy.map(f)),
}
}
}
Expand All @@ -78,9 +82,10 @@
write!(f, "Action::Clipboard({action:?})")
}
Self::Window(action) => write!(f, "Action::Window({action:?})"),
Self::System(action) => write!(f, "Action::System({action:?})"),

Check failure on line 85 in runtime/src/command/action.rs

View workflow job for this annotation

GitHub Actions / all

Diff in /home/runner/work/iced/iced/runtime/src/command/action.rs
Self::Widget(_action) => write!(f, "Action::Widget"),
Self::LoadFont { .. } => write!(f, "Action::LoadFont"),
Self::Proxy(_) => write!(f, "Action::GetProxy")
}
}
}
2 changes: 2 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub mod program;
pub mod system;
pub mod user_interface;
pub mod window;
/// Get proxy
pub mod proxy;

// We disable debug capabilities on release builds unless the `debug` feature
// is explicitly enabled.
Expand Down
48 changes: 48 additions & 0 deletions runtime/src/proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::fmt;

use iced_futures::MaybeSend;


/// Get proxy
pub enum Action<T> {
/// Query proxy
QueryProxy(Box<dyn Closure<T>>)
}

///
pub trait Closure<T>: Fn(Box<dyn Proxy<T>>) -> T + MaybeSend {}


impl<T, O> Closure<O> for T
where T: Fn(Box<dyn Proxy<O>>) -> O + MaybeSend {}

impl<T> Action<T> {
/// Maps the output of a system [`Action`] using the provided closure.
pub fn map<A>(
self,
f: impl Fn(T) -> A + 'static + MaybeSend + Sync,
) -> Action<A>
where
T: 'static,
{
match self {
Self::QueryProxy(o) => {
Action::QueryProxy(Box::new(move |s| f(o(s))))

Check failure on line 30 in runtime/src/proxy.rs

View workflow job for this annotation

GitHub Actions / all

mismatched types

Check failure on line 30 in runtime/src/proxy.rs

View workflow job for this annotation

GitHub Actions / web

mismatched types

Check failure on line 30 in runtime/src/proxy.rs

View workflow job for this annotation

GitHub Actions / native (ubuntu-latest, stable)

mismatched types

Check failure on line 30 in runtime/src/proxy.rs

View workflow job for this annotation

GitHub Actions / native (macOS-latest, beta)

mismatched types
}
}
}
}


///
pub trait Proxy<T> {

}

impl<T> fmt::Debug for Action<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::QueryProxy(_) => write!(f, "Action::QueryProxy"),
}
}
}
11 changes: 11 additions & 0 deletions winit/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,17 @@ pub fn run_command<A, C, E>(
.send_event(tagger(Ok(())))
.expect("Send message to event loop");
}
command::Action::Proxy(action) => {
match action {
iced_runtime::proxy::Action::QueryProxy(f) => {
let proxy_cloned = proxy.clone();

proxy
.send_event(f(proxy_cloned))
.expect("Send message to event loop");
}
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub mod system;

mod error;
mod position;
mod proxy;
pub mod proxy;

#[cfg(feature = "application")]
pub use application::Application;
Expand Down
17 changes: 17 additions & 0 deletions winit/src/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
use iced_runtime::{proxy::{self, Action}, Command, command};

use crate::futures::futures::{
channel::mpsc,
task::{Context, Poll},
Sink,
};
use std::pin::Pin;


/// Query for available system information.
pub fn fetch_proxy<Message>(
f: impl Fn(Box<dyn proxy::Proxy>) -> Message + Send + 'static,
) -> Command<Message> {
Command::single(command::Action::Proxy(Action::QueryProxy(
Box::new(f),
)))
}

impl proxy::Proxy<Message: 'static> for winit::event_loop::EventLoopProxy<Message> {

}


/// An event loop proxy that implements `Sink`.
#[derive(Debug)]
pub struct Proxy<Message: 'static> {
Expand Down
Loading