Join one FM-Funknetz talk group from a headset window.
The station reads ~/.funknetz.json, speaks protocol 2.0, and builds an unsigned funknetz.app. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
body {
|
||||
margin: 0;
|
||||
background: #101418;
|
||||
color: #f2f4f6;
|
||||
font: 16px/1.4 system-ui, sans-serif;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
#connection {
|
||||
margin: 0 0 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#detail {
|
||||
min-height: 1.4em;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 24px;
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
background: #2d6a4f;
|
||||
color: white;
|
||||
font: inherit;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
button.down {
|
||||
background: #9b2226;
|
||||
}
|
||||
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
const button = document.getElementById("ptt");
|
||||
|
||||
function api() {
|
||||
if (!window.go || !window.go.main || !window.go.main.App) {
|
||||
return null;
|
||||
}
|
||||
return window.go.main.App;
|
||||
}
|
||||
|
||||
function line(state) {
|
||||
if (state.detail && state.detail !== "Idle") {
|
||||
return state.detail;
|
||||
}
|
||||
if (state.talker) {
|
||||
return state.talker;
|
||||
}
|
||||
return "Idle";
|
||||
}
|
||||
|
||||
function render(state) {
|
||||
document.getElementById("connection").textContent = state.connection;
|
||||
document.getElementById("callsign").textContent = state.callsign;
|
||||
document.getElementById("talkgroup").textContent = String(state.talkGroup);
|
||||
document.getElementById("detail").textContent = line(state);
|
||||
button.classList.toggle("down", !!state.transmitting);
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
const app = api();
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
app.State().then(render).catch(function () {});
|
||||
}
|
||||
|
||||
button.addEventListener("pointerdown", function (event) {
|
||||
event.preventDefault();
|
||||
button.setPointerCapture(event.pointerId);
|
||||
const app = api();
|
||||
if (app) {
|
||||
app.HoldButton();
|
||||
}
|
||||
});
|
||||
|
||||
function releaseButton() {
|
||||
const app = api();
|
||||
if (app) {
|
||||
app.ReleaseButton();
|
||||
}
|
||||
}
|
||||
|
||||
button.addEventListener("pointerup", releaseButton);
|
||||
button.addEventListener("pointercancel", releaseButton);
|
||||
|
||||
let spaceHeld = false;
|
||||
|
||||
window.addEventListener("keydown", function (event) {
|
||||
if (event.code !== "Space") {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (event.repeat || spaceHeld) {
|
||||
return;
|
||||
}
|
||||
spaceHeld = true;
|
||||
const app = api();
|
||||
if (app) {
|
||||
app.HoldSpace();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("keyup", function (event) {
|
||||
if (event.code !== "Space") {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (!spaceHeld) {
|
||||
return;
|
||||
}
|
||||
spaceHeld = false;
|
||||
const app = api();
|
||||
if (app) {
|
||||
app.ReleaseSpace();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("blur", function () {
|
||||
spaceHeld = false;
|
||||
const app = api();
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
app.ReleaseButton();
|
||||
app.ReleaseSpace();
|
||||
});
|
||||
|
||||
setInterval(refresh, 100);
|
||||
refresh();
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>funknetz</title>
|
||||
<link rel="stylesheet" href="app.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<p id="connection">Disconnected</p>
|
||||
<p>Callsign <span id="callsign"></span></p>
|
||||
<p>Talk group <span id="talkgroup"></span></p>
|
||||
<p id="detail">Idle</p>
|
||||
<button id="ptt" type="button">Push to talk</button>
|
||||
</main>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user