Emit periodic events from the backend and listen to them in Gleam

This commit is contained in:
Wesley Moore 2024-02-18 16:59:48 +10:00
parent 3cd65e1094
commit 1ddd93a108
No known key found for this signature in database
7 changed files with 100 additions and 11 deletions

View File

@ -1,3 +1,3 @@
fn main() {
tauri_build::build()
tauri_build::build()
}

View File

@ -1,6 +1,6 @@
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@ -1,14 +1,45 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use tauri::EventTarget;
use tauri::Manager;
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
tauri::Builder::default()
.setup(|app| {
let app = app.handle().clone();
std::thread::spawn(move || {
loop {
// app.emit_all("event-name", Payload { message: "Tauri is awesome!".into() }).unwrap();
let now = SystemTime::now();
let duration = now.duration_since(UNIX_EPOCH).unwrap();
app.emit_to(EventTarget::any(), "tick", duration.as_secs())
.unwrap();
std::thread::sleep(Duration::from_secs(1));
}
});
Ok(())
})
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
format!("Hello, {}!", name)
}
#[tauri::command]
fn clock(app: tauri::AppHandle) {
std::thread::spawn(move || {
loop {
let now = SystemTime::now();
let duration = now.duration_since(UNIX_EPOCH).unwrap();
app.emit_to(EventTarget::any(), "tick", duration.as_secs())
.unwrap();
std::thread::sleep(Duration::from_secs(1));
}
});
}

View File

@ -1,4 +1,5 @@
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { Ok, Error } from "../../build/dev/javascript/videopls/gleam.mjs"; // FIXME: Is this the right way to do this?
export async function greet(name) {
@ -8,3 +9,12 @@ export async function greet(name) {
return new Error(error.toString());
}
}
export async function listenForTick(handler) {
console.log("listenForTick");
await listen('tick', (event) => {
console.log(event.payload);
handler(event.payload);
});
}

7
src/ffi/js_extra.js Normal file
View File

@ -0,0 +1,7 @@
export function from_unix(timestamp) {
return new Date(timestamp * 1000);
}
export function date_to_string(date) {
return date.toString();
}

View File

@ -15,11 +15,11 @@ pub fn main() {
}
type Model {
Model(count: Int, greeting: String, name: String)
Model(count: Int, greeting: String, name: String, time: Int)
}
fn init(_) -> #(Model, Effect(Msg)) {
#(Model(0, "", ""), effect.none())
#(Model(0, "", "", 0), bind_clock())
}
pub type Msg {
@ -28,6 +28,7 @@ pub type Msg {
Greet
GotGreeting(String)
UpdateName(String)
Tick(Int)
}
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
@ -40,6 +41,7 @@ fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
effect.none(),
)
UpdateName(name) -> #(Model(..model, name: name), effect.none())
Tick(time) -> #(Model(..model, time: time), effect.none())
}
}
@ -61,17 +63,50 @@ fn do_get_greeting(name: String, dispatch: fn(Msg) -> Nil) -> Nil {
Nil
}
fn bind_clock() -> Effect(Msg) {
effect.from(fn(dispatch) {
listen_for_tick(fn(time) {
tick(time)
|> dispatch
})
Nil
})
}
@external(javascript, "./ffi/commands.js", "greet")
pub fn greet(name: String) -> Promise(Result(String, String))
type UnlistenFn =
fn() -> Nil
@external(javascript, "./ffi/commands.js", "listenForTick")
pub fn listen_for_tick(handler: fn(Int) -> Nil) -> Promise(UnlistenFn)
pub type Date
@external(javascript, "./ffi/js_extra.js", "from_unix")
pub fn new_date(timestamp: Int) -> Date
@external(javascript, "./ffi/js_extra.js", "date_to_string")
pub fn date_to_string(date: Date) -> String
fn update_name(text: String) -> Msg {
UpdateName(text)
}
fn tick(time: Int) -> Msg {
Tick(time)
}
// -- VIEW
fn view(model: Model) -> Element(Msg) {
let count = int.to_string(model.count)
let time =
model.time
|> new_date
|> date_to_string
html.div([], [
html.h1([], [element.text("Gleam + Vite + Tauri")]),
@ -92,5 +127,8 @@ fn view(model: Model) -> Element(Msg) {
html.button([event.on_click(Increment)], [element.text("+")]),
html.button([event.on_click(Greet)], [element.text("Greet")]),
]),
html.div([attr.class("clock text-center")], [
element.text("Clock: " <> time),
]),
])
}

View File

@ -67,6 +67,9 @@ h1 {
.field {
margin-top: 0.5em;
}
.clock {
margin-top: 2em;
}
.text-center {
text-align: center;
}