Skip to content

Commit d30d15d

Browse files
feat(desktop): add NetworkContext powered by plugins/network events (#2079)
* feat(desktop): add NetworkContext powered by plugins/network events - Add JS bindings for network plugin (events.networkStatusEvent) - Create NetworkProvider and useNetwork hook in apps/desktop - Add package.json and tsconfig.json for @hypr/plugin-network Co-Authored-By: yujonglee <yujonglee.dev@gmail.com> * fix: add @hypr/plugin-network to desktop dependencies Co-Authored-By: yujonglee <yujonglee.dev@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent f171414 commit d30d15d

File tree

7 files changed

+269
-14
lines changed

7 files changed

+269
-14
lines changed

apps/desktop/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@hypr/plugin-listener2": "workspace:*",
4242
"@hypr/plugin-local-stt": "workspace:*",
4343
"@hypr/plugin-misc": "workspace:*",
44+
"@hypr/plugin-network": "workspace:*",
4445
"@hypr/plugin-notification": "workspace:*",
4546
"@hypr/plugin-permissions": "workspace:*",
4647
"@hypr/plugin-template": "workspace:*",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { createContext, useContext, useEffect, useState } from "react";
2+
3+
import { events } from "@hypr/plugin-network";
4+
5+
interface NetworkContextValue {
6+
isOnline: boolean;
7+
}
8+
9+
const NetworkContext = createContext<NetworkContextValue | null>(null);
10+
11+
export function NetworkProvider({ children }: { children: React.ReactNode }) {
12+
const [isOnline, setIsOnline] = useState(true);
13+
14+
useEffect(() => {
15+
let unlisten: (() => void) | undefined;
16+
let cancelled = false;
17+
18+
events.networkStatusEvent
19+
.listen(({ payload }) => {
20+
setIsOnline(payload.is_online);
21+
})
22+
.then((fn) => {
23+
if (cancelled) {
24+
fn();
25+
} else {
26+
unlisten = fn;
27+
}
28+
})
29+
.catch((err) => {
30+
console.error("Failed to setup network status event listener:", err);
31+
});
32+
33+
return () => {
34+
cancelled = true;
35+
unlisten?.();
36+
};
37+
}, []);
38+
39+
return (
40+
<NetworkContext.Provider value={{ isOnline }}>
41+
{children}
42+
</NetworkContext.Provider>
43+
);
44+
}
45+
46+
export function useNetwork(): NetworkContextValue {
47+
const context = useContext(NetworkContext);
48+
if (!context) {
49+
throw new Error("useNetwork must be used within a NetworkProvider");
50+
}
51+
return context;
52+
}

plugins/network/js/bindings.gen.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// @ts-nocheck
2+
3+
4+
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
5+
6+
/** user-defined commands **/
7+
8+
9+
export const commands = {
10+
11+
}
12+
13+
/** user-defined events **/
14+
15+
16+
export const events = __makeEvents__<{
17+
networkStatusEvent: NetworkStatusEvent
18+
}>({
19+
networkStatusEvent: "plugin:network:network-status-event"
20+
})
21+
22+
/** user-defined constants **/
23+
24+
25+
26+
/** user-defined types **/
27+
28+
export type NetworkStatusEvent = { is_online: boolean }
29+
30+
/** tauri-specta globals **/
31+
32+
import {
33+
invoke as TAURI_INVOKE,
34+
Channel as TAURI_CHANNEL,
35+
} from "@tauri-apps/api/core";
36+
import * as TAURI_API_EVENT from "@tauri-apps/api/event";
37+
import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow";
38+
39+
type __EventObj__<T> = {
40+
listen: (
41+
cb: TAURI_API_EVENT.EventCallback<T>,
42+
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
43+
once: (
44+
cb: TAURI_API_EVENT.EventCallback<T>,
45+
) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
46+
emit: null extends T
47+
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
48+
: (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
49+
};
50+
51+
export type Result<T, E> =
52+
| { status: "ok"; data: T }
53+
| { status: "error"; error: E };
54+
55+
function __makeEvents__<T extends Record<string, any>>(
56+
mappings: Record<keyof T, string>,
57+
) {
58+
return new Proxy(
59+
{} as unknown as {
60+
[K in keyof T]: __EventObj__<T[K]> & {
61+
(handle: __WebviewWindow__): __EventObj__<T[K]>;
62+
};
63+
},
64+
{
65+
get: (_, event) => {
66+
const name = mappings[event as keyof T];
67+
68+
return new Proxy((() => {}) as any, {
69+
apply: (_, __, [window]: [__WebviewWindow__]) => ({
70+
listen: (arg: any) => window.listen(name, arg),
71+
once: (arg: any) => window.once(name, arg),
72+
emit: (arg: any) => window.emit(name, arg),
73+
}),
74+
get: (_, command: keyof __EventObj__<any>) => {
75+
switch (command) {
76+
case "listen":
77+
return (arg: any) => TAURI_API_EVENT.listen(name, arg);
78+
case "once":
79+
return (arg: any) => TAURI_API_EVENT.once(name, arg);
80+
case "emit":
81+
return (arg: any) => TAURI_API_EVENT.emit(name, arg);
82+
}
83+
},
84+
});
85+
},
86+
},
87+
);
88+
}

plugins/network/js/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./bindings.gen";

plugins/network/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "@hypr/plugin-network",
3+
"private": true,
4+
"main": "./js/index.ts",
5+
"scripts": {
6+
"codegen": "cargo test -p tauri-plugin-network"
7+
},
8+
"dependencies": {
9+
"@tauri-apps/api": "^2.9.0"
10+
}
11+
}

plugins/network/tsconfig.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extends": "../tsconfig.base.json",
3+
"include": ["./js/*.ts"],
4+
"exclude": ["node_modules"]
5+
}

0 commit comments

Comments
 (0)