14 Commits

Author SHA1 Message Date
PxlLoewe
2c2eca6084 Revert "Revert "PR v2.0.7"" 2026-01-15 23:45:06 +01:00
PxlLoewe
0429d8b770 Merge pull request #148 from VAR-Virtual-Air-Rescue/revert-147-staging
Revert "PR v2.0.7"
2026-01-15 23:35:32 +01:00
PxlLoewe
7175f6571e Revert "PR v2.0.7" 2026-01-15 23:35:14 +01:00
PxlLoewe
614b92325e Merge pull request #147 from VAR-Virtual-Air-Rescue/staging
@everyone | Wir haben eine kurze Downtime überwunden und stellen euch heute v2.0.7 vor.

In der Vergangenheit haben wir viel an der Dispositionsseite gearbeitet. Das ändert sich heute. Wir aktualisieren die Bedieneinheit für Piloten auf eine neue Softwareversion, die dem Sepura SCG22 nachempfunden ist und so tatsächlich in vielen Hubschraubern verbaut ist.

### Neue Features:
- Ladescreen beim Einschalten
- Wechseln der Rufgruppe direkt im Gerät
- Status senden/empfangen
- SDS-Text bzw. senden/empfangen
- Nachtmodus ab 22:00 Uhr
- Popup bei Funkverkehr auf der Rufgruppe

Eine entsprechende Dokumentation findet ihr[ in den Docs](https://docs.virtualairrescue.com/allgemein/var-systeme/leitstelle/pilot.html).

### Weiteres:
- kleinere Bugfixes
- Performanceupgrades durch verbessertes Backup-Handling
2026-01-15 22:59:21 +01:00
PxlLoewe
b5d67e55b4 night mode nur wenn das mrt an ist 2026-01-15 22:51:10 +01:00
PxlLoewe
ea9c2c0f38 added night iamge 2026-01-15 22:37:29 +01:00
PxlLoewe
72c214a189 fixed Sound nach Verbinden auf RG 2026-01-15 22:22:36 +01:00
PxlLoewe
022d20356c Merge branch 'staging' of https://github.com/VAR-Virtual-Air-Rescue/var-monorepo into staging 2026-01-15 22:08:07 +01:00
PxlLoewe
228b0617e6 Mrt Button bug 2026-01-15 22:06:39 +01:00
PxlLoewe
3413f74fcd Merge pull request #145 from VAR-Virtual-Air-Rescue/mrt-rework
repaired nextJS dockerfiles
2026-01-15 21:38:06 +01:00
PxlLoewe
bfe4d56cf7 Merge pull request #144 from VAR-Virtual-Air-Rescue/mrt-rework
Mrt rework
2026-01-15 21:14:59 +01:00
PxlLoewe
b1e508ef36 release v2.0.6
v2.0.6
2026-01-06 13:58:24 +01:00
PxlLoewe
6e8884f3fb Merge pull request #141 from VAR-Virtual-Air-Rescue/staging
v2.0.5
2025-12-27 16:23:33 +01:00
PxlLoewe
dde52bde39 Release v2.0.4
Release v2.0.4
2025-12-08 19:48:53 +01:00
7 changed files with 53 additions and 13 deletions

View File

@@ -1,13 +1,27 @@
import { useEffect } from "react"; // ...existing code...
import { useMrtStore } from "_store/pilot/MrtStore";
import Image from "next/image";
import DAY_BASE_IMG from "./images/Base_NoScreen_Day.png";
import NIGHT_BASE_IMG from "./images/Base_NoScreen_Night.png";
export const MrtBase = () => {
const { nightMode } = useMrtStore((state) => state);
const { nightMode, setNightMode, page } = useMrtStore((state) => state);
useEffect(() => {
const checkNightMode = () => {
const currentHour = new Date().getHours();
setNightMode(currentHour >= 22 || currentHour < 8);
};
checkNightMode(); // Initial check
const intervalId = setInterval(checkNightMode, 60000); // Check every minute
return () => clearInterval(intervalId); // Cleanup on unmount
}, [setNightMode]); // ...existing code...
return (
<Image
src={nightMode ? NIGHT_BASE_IMG : DAY_BASE_IMG}
src={nightMode && page !== "off" ? NIGHT_BASE_IMG : DAY_BASE_IMG}
alt=""
className="z-30 col-span-full row-span-full"
/>

View File

@@ -19,7 +19,14 @@ const MrtButton = ({ onClick, onHold, style }: MrtButtonProps) => {
const handleMouseDown = () => {
if (!onHold) return;
timeoutRef.current = setTimeout(onHold, 500);
timeoutRef.current = setTimeout(handleTimeoutExpired, 500);
};
const handleTimeoutExpired = () => {
timeoutRef.current = null;
if (onHold) {
onHold();
}
};
const handleMouseUp = () => {

View File

@@ -3,6 +3,7 @@
import { SetPageParams, useMrtStore } from "_store/pilot/MrtStore";
import Image, { StaticImageData } from "next/image";
import PAGE_HOME from "./images/PAGE_Home.png";
import PAGE_HOME_NO_GROUP from "./images/PAGE_Home_no_group.png";
import PAGE_Call from "./images/PAGE_Call.png";
import PAGE_Off from "./images/PAGE_Off.png";
import PAGE_STARTUP from "./images/PAGE_Startup.png";
@@ -22,7 +23,7 @@ export const MrtDisplay = () => {
const callEstablishedRef = useRef(false);
const session = useSession();
const { connectedAircraft, selectedStation } = usePilotConnectionStore((state) => state);
const { room, speakingParticipants, isTalking } = useAudioStore((state) => state);
const { room, speakingParticipants, isTalking, state } = useAudioStore((state) => state);
const [pageImage, setPageImage] = useState<{
src: StaticImageData;
name: SetPageParams["page"];
@@ -49,7 +50,6 @@ export const MrtDisplay = () => {
);
useEffect(() => {
console.log("speakingParticipants", speakingParticipants, isTalking, page);
if ((speakingParticipants.length > 0 || isTalking) && page === "home") {
setPage({
page: "voice-call",
@@ -157,7 +157,11 @@ export const MrtDisplay = () => {
switch (page) {
case "home":
setNextImage({ src: PAGE_HOME, name: "home" });
if (state == "connected") {
setNextImage({ src: PAGE_HOME, name: "home" });
} else {
setNextImage({ src: PAGE_HOME_NO_GROUP, name: "home" });
}
break;
case "voice-call":
setNextImage({ src: PAGE_Call, name: "voice-call" });
@@ -169,7 +173,7 @@ export const MrtDisplay = () => {
setNextImage({ src: PAGE_STARTUP, name: "startup" });
break;
}
}, [page]);
}, [page, state]);
const DisplayText = ({ pageName }: { pageName: SetPageParams["page"] }) => {
return (
@@ -204,10 +208,10 @@ export const MrtDisplay = () => {
{!connectedAircraft && <>Keine Verbindung</>}
</p>
<p className="absolute left-[22.7%] top-[37.8%] flex h-[5%] w-[34%] items-center text-xs">
{room?.name || "Keine RG gefunden"}
{state == "connected" ? room?.name : "Keine RG gewählt"}
</p>
<p className="absolute left-[28%] top-[44.5%] h-[8%] w-[34%] text-xs">
{ROOMS.find((r) => r.name === room?.name)?.id}
{state == "connected" && ROOMS.find((r) => r.name === room?.name)?.id}
</p>
</>
)}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

View File

@@ -1,7 +1,10 @@
"use client";
import { useAudioStore } from "_store/audioStore";
import { RoomEvent } from "livekit-client";
import { useEffect, useRef } from "react";
export const useSounds = () => {
const { room } = useAudioStore((state) => state);
const longBtnPressSoundRef = useRef<HTMLAudioElement>(null);
const statusSentSoundRef = useRef<HTMLAudioElement>(null);
const sdsReceivedSoundRef = useRef<HTMLAudioElement>(null);
@@ -14,6 +17,20 @@ export const useSounds = () => {
}
}, []);
useEffect(() => {
const handleRoomConnected = () => {
// Play a sound when connected to the room
// connectedSound.play();
statusSentSoundRef.current?.play();
console.log("Room connected - played sound");
};
room?.on(RoomEvent.Connected, handleRoomConnected);
return () => {
room?.off(RoomEvent.Connected, handleRoomConnected);
};
}, [room]);
return {
longBtnPressSoundRef,
statusSentSoundRef,

View File

@@ -76,7 +76,6 @@ export const ConnectionBtn = () => {
const session = useSession();
const uid = session.data?.user?.id;
if (!uid) return null;
console.log(bookings);
return (
<div className="rounded-box bg-base-200 flex items-center justify-center gap-2 p-1">
{connection.message.length > 0 && (

View File

@@ -25,8 +25,6 @@ import { ROOMS } from "_data/livekitRooms";
let interval: NodeJS.Timeout;
const connectedSound = new Audio("/sounds/403.wav");
type TalkState = {
addSpeakingParticipant: (participant: Participant) => void;
connect: (room: (typeof ROOMS)[number] | undefined, role: string) => void;
@@ -190,6 +188,7 @@ export const useAudioStore = create<TalkState>((set, get) => ({
if (!token) throw new Error("Fehlende Berechtigung");
const room = new Room({});
await room.prepareConnection(url, token);
const roomConnectedSound = new Audio("/sounds/403.wav");
room
// Connection events
.on(RoomEvent.Connected, async () => {
@@ -219,7 +218,7 @@ export const useAudioStore = create<TalkState>((set, get) => ({
source: Track.Source.Microphone,
});
await publishedTrack.mute();
connectedSound.play().catch((e) => console.error("Fehler beim Abspielen des Sounds", e));
roomConnectedSound.play();
set({ localRadioTrack: publishedTrack });
set({ state: "connected", room, isTalking: false, message: null });