1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
import {
ButtonItem,
PanelSection,
PanelSectionRow,
Navigation,
staticClasses,
Dropdown,
DropdownOption
} from "@decky/ui";
import {
addEventListener,
removeEventListener,
callable,
definePlugin,
toaster,
// routerHook
} from "@decky/api"
import { useState } from "react";
import { FaShip } from "react-icons/fa";
// import logo from "../assets/logo.png";
// This function calls the python function "add", which takes in two numbers and returns their sum (as a number)
// Note the type annotations:
// the first one: [first: number, second: number] is for the arguments
// the second one: number is for the return value
const add = callable<[first: number, second: number], number>("add");
// This function calls the python function "start_timer", which takes in no arguments and returns nothing.
// It starts a (python) timer which eventually emits the event 'timer_event'
const startTimer = callable<[], void>("start_timer");
const dropdownOptions: DropdownOption[] = [
{ label: "1", data: 1 },
{ label: "2", data: 2 },
{ label: "3", data: 3 },
];
function Content() {
const [result, setResult] = useState<number | undefined>();
const [selectedOption, setSelectedOption] = useState<number | undefined>();
const onClick = async () => {
const result = await add(Math.random(), Math.random());
setResult(result);
};
return (
<PanelSection title="Panel Section">
<PanelSectionRow>
<ButtonItem
layout="below"
onClick={onClick}
>
{result ?? "Add two numbers via Python"}
</ButtonItem>
</PanelSectionRow>
<PanelSectionRow>
<ButtonItem
layout="below"
onClick={() => startTimer()}
>
{"Start Python timer"}
</ButtonItem>
</PanelSectionRow>
<PanelSectionRow>
<Dropdown
rgOptions={dropdownOptions}
selectedOption={selectedOption}
onChange={(option) => setSelectedOption(option.data)}
/>
</PanelSectionRow>
{/* <PanelSectionRow>
<div style={{ display: "flex", justifyContent: "center" }}>
<img src={logo} />
</div>
</PanelSectionRow> */}
{/*<PanelSectionRow>
<ButtonItem
layout="below"
onClick={() => {
Navigation.Navigate("/decky-plugin-test");
Navigation.CloseSideMenus();
}}
>
Router
</ButtonItem>
</PanelSectionRow>*/}
</PanelSection>
);
};
export default definePlugin(() => {
console.log("Template plugin initializing, this is called once on frontend startup")
// serverApi.routerHook.addRoute("/decky-plugin-test", DeckyPluginRouterTest, {
// exact: true,
// });
// Add an event listener to the "timer_event" event from the backend
const listener = addEventListener<[
test1: string,
test2: boolean,
test3: number
]>("timer_event", (test1, test2, test3) => {
console.log("Template got timer_event with:", test1, test2, test3)
toaster.toast({
title: "template got timer_event",
body: `${test1}, ${test2}, ${test3}`
});
});
return {
// The name shown in various decky menus
name: "Test Plugin",
// The element displayed at the top of your plugin's menu
titleView: <div className={staticClasses.Title}>Decky Example Plugin</div>,
// The content of your plugin's menu
content: <Content />,
// The icon displayed in the plugin list
icon: <FaShip />,
// The function triggered when your plugin unloads
onDismount() {
console.log("Unloading")
removeEventListener("timer_event", listener);
// serverApi.routerHook.removeRoute("/decky-plugin-test");
},
};
});
|