init
This commit is contained in:
commit
915a7316c7
3 changed files with 153 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "relmfetch"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.42"
|
||||||
|
gtk = "0.14.0"
|
||||||
|
relm = "0.22.0"
|
||||||
|
relm-derive = "0.22.0"
|
||||||
|
reqwest = "0.11.4"
|
||||||
|
tokio = { version = "1.8.2", features = ["macros", "rt-multi-thread", "sync"] }
|
137
src/main.rs
Normal file
137
src/main.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
use gtk::prelude::*;
|
||||||
|
use gtk::Inhibit;
|
||||||
|
use gtk::Orientation;
|
||||||
|
use relm::{Channel, Relm, Sender, Widget};
|
||||||
|
use relm_derive::{widget, Msg};
|
||||||
|
use reqwest::Client;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let win_handle = tokio::spawn(async { Win::run(tx) });
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
while let Some(s) = rx.recv().await {
|
||||||
|
println!("Got msg {:?}", &s);
|
||||||
|
s.sender.send(Msg::Working(true))?;
|
||||||
|
match send_request(&client, s.url).await {
|
||||||
|
Ok(r) => {
|
||||||
|
s.sender.send(Msg::UpdateText(r))?;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
s.sender.send(Msg::UpdateText(format!("Error!\n{:?}", e)))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.sender.send(Msg::Working(false))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
win_handle.await??;
|
||||||
|
println!("window finished");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_request(client: &Client, url: String) -> anyhow::Result<String> {
|
||||||
|
Ok(String::from_utf8(
|
||||||
|
client.get(url).send().await?.bytes().await?.to_vec(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Model {
|
||||||
|
tx: UnboundedSender<RuntimeMsg>,
|
||||||
|
_channel: Channel<Msg>,
|
||||||
|
sender: Sender<Msg>,
|
||||||
|
working: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RuntimeMsg {
|
||||||
|
url: String,
|
||||||
|
sender: Sender<Msg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for RuntimeMsg {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("RuntimeMsg")
|
||||||
|
.field("url", &self.url)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Msg)]
|
||||||
|
pub enum Msg {
|
||||||
|
Quit,
|
||||||
|
Clicked,
|
||||||
|
UpdateText(String),
|
||||||
|
Working(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[widget]
|
||||||
|
impl Widget for Win {
|
||||||
|
fn model(relm: &Relm<Self>, tx: UnboundedSender<RuntimeMsg>) -> Model {
|
||||||
|
let stream = relm.stream().clone();
|
||||||
|
let (channel, sender) = Channel::new(move |msg| {
|
||||||
|
stream.emit(msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
Model {
|
||||||
|
_channel: channel,
|
||||||
|
working: false,
|
||||||
|
sender,
|
||||||
|
tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, event: Msg) {
|
||||||
|
match event {
|
||||||
|
Msg::Quit => gtk::main_quit(),
|
||||||
|
Msg::Clicked => {
|
||||||
|
let msg = RuntimeMsg {
|
||||||
|
url: self.widgets.input.text().to_string(),
|
||||||
|
sender: self.model.sender.clone(),
|
||||||
|
};
|
||||||
|
self.model.tx.send(msg).unwrap();
|
||||||
|
}
|
||||||
|
Msg::UpdateText(s) => {
|
||||||
|
if let Some(buf) = self.widgets.textview.buffer() {
|
||||||
|
buf.set_text(&s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Msg::Working(w) => self.model.working = w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view! {
|
||||||
|
gtk::Window {
|
||||||
|
gtk::Box {
|
||||||
|
orientation: Orientation::Vertical,
|
||||||
|
|
||||||
|
#[name = "input"]
|
||||||
|
gtk::Entry {},
|
||||||
|
|
||||||
|
gtk::Box {
|
||||||
|
orientation: Orientation::Horizontal,
|
||||||
|
gtk::Button {
|
||||||
|
label: "Test",
|
||||||
|
hexpand: true,
|
||||||
|
clicked => Msg::Clicked,
|
||||||
|
},
|
||||||
|
gtk::Spinner {
|
||||||
|
active: self.model.working,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gtk::ScrolledWindow {
|
||||||
|
hexpand: true,
|
||||||
|
vexpand: true,
|
||||||
|
|
||||||
|
#[name = "textview"]
|
||||||
|
gtk::TextView {
|
||||||
|
editable: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete_event(_, _) => (Msg::Quit, Inhibit(false)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue