mirror of
https://codeberg.org/PLG-Development/PLG-MuDiCS
synced 2026-07-06 00:47:09 +00:00
chore(display): improve display startup behavior with qr-code
This commit is contained in:
+39
-1
@@ -5,8 +5,10 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -17,6 +19,7 @@ import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/micmonay/keybd_event"
|
||||
"github.com/skip2/go-qrcode"
|
||||
|
||||
"plg-mudics/display/pkg"
|
||||
)
|
||||
@@ -44,6 +47,7 @@ func StartWebServer(v string, port string) {
|
||||
e.GET("/splash", func(ctx echo.Context) error {
|
||||
return ctx.HTML(http.StatusOK, shared.SplashScreenTemplate)
|
||||
})
|
||||
e.GET("/qr", qrRoute)
|
||||
|
||||
staticGroup := e.Group("/static")
|
||||
staticGroup.Use(middleware.StaticWithConfig(middleware.StaticConfig{
|
||||
@@ -97,8 +101,9 @@ func sseRoute(ctx echo.Context) error {
|
||||
if err != nil {
|
||||
slog.Error("Failed to get device MAC address", "error", err)
|
||||
}
|
||||
showQR := !isPortFree(8080)
|
||||
var status bytes.Buffer
|
||||
deviceInfoTemplate(ip, mac).Render(context.Background(), &status)
|
||||
deviceInfoTemplate(ip, mac, showQR).Render(context.Background(), &status)
|
||||
connectedEvent := Event{
|
||||
Data: status.Bytes(),
|
||||
}
|
||||
@@ -127,6 +132,29 @@ func sseRoute(ctx echo.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
func qrRoute(c echo.Context) error {
|
||||
data := c.QueryParam("data")
|
||||
if data == "" {
|
||||
return c.String(http.StatusBadRequest, "missing data")
|
||||
}
|
||||
|
||||
qr, err := qrcode.New(data, qrcode.Medium)
|
||||
if err != nil {
|
||||
return c.String(http.StatusInternalServerError, "could not generate qr")
|
||||
}
|
||||
|
||||
qr.DisableBorder = true
|
||||
qr.ForegroundColor = color.RGBA{R: 0x1c, G: 0x19, B: 0x17, A: 0xff}
|
||||
qr.BackgroundColor = color.RGBA{R: 0xe7, G: 0xe5, B: 0xe4, A: 0xff}
|
||||
|
||||
png, err := qr.PNG(-1)
|
||||
if err != nil {
|
||||
return c.String(http.StatusInternalServerError, "could not encode png")
|
||||
}
|
||||
|
||||
return c.Blob(http.StatusOK, "image/png", png)
|
||||
}
|
||||
|
||||
func extractFilePathMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(ctx echo.Context) error {
|
||||
pathParam := ctx.Param("path")
|
||||
@@ -354,3 +382,13 @@ func resetView() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isPortFree(port int) bool {
|
||||
addr := fmt.Sprintf("127.0.0.1:%d", port)
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_ = l.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
+94
-68
@@ -1,85 +1,111 @@
|
||||
package web
|
||||
|
||||
templ indexTemplate() {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>PLG Connect Display</title>
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<script src="/static/htmx-ext-sse.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--background-color: hsl(256, 10%, 10%);
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center; /* centers horizontally */
|
||||
align-items: center; /* centers vertically */
|
||||
width: 100vw; /* Viewport width */
|
||||
height: 100vh; /* Viewport height */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-color);
|
||||
color: hsl(256, 90%, 95%);
|
||||
}
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PLG Connect Display</title>
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<script src="/static/htmx-ext-sse.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--background-color: black;
|
||||
--foreground-color: oklch(92.3% 0.003 48.717)
|
||||
}
|
||||
|
||||
video, img, iframe {
|
||||
width: 100vw; /* Viewport width */
|
||||
height: 100vh; /* Viewport height */
|
||||
object-fit: contain;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
/* centers horizontally */
|
||||
align-items: center;
|
||||
/* centers vertically */
|
||||
width: 100vw;
|
||||
/* Viewport width */
|
||||
height: 100vh;
|
||||
/* Viewport height */
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-color);
|
||||
color: var(--foreground-color);
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 6rem;
|
||||
line-height: 1;
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
text-wrap: balance;
|
||||
max-width: 90vw;
|
||||
word-break: break-word;
|
||||
display: block;
|
||||
video,
|
||||
img,
|
||||
iframe {
|
||||
width: 100vw;
|
||||
/* Viewport width */
|
||||
height: 100vh;
|
||||
/* Viewport height */
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 6rem;
|
||||
line-height: 1;
|
||||
text-wrap: balance;
|
||||
max-width: 90vw;
|
||||
word-break: break-word;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.code === 'Space') {
|
||||
event.preventDefault();
|
||||
var video = document.querySelector('video');
|
||||
if (video) {
|
||||
if (video.paused) {
|
||||
video.play();
|
||||
} else {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.code === 'Space') {
|
||||
event.preventDefault();
|
||||
var video = document.querySelector('video');
|
||||
if (video) {
|
||||
if (video.paused) {
|
||||
video.play();
|
||||
} else {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<bod>
|
||||
<div hx-get="/splash" hx-trigger="load"></div>
|
||||
<main hx-ext="sse" sse-connect="/sse" sse-swap="message"></main>
|
||||
</bod>
|
||||
</html>
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<bod>
|
||||
<div hx-get="/splash" hx-trigger="load"></div>
|
||||
<main hx-ext="sse" sse-connect="/sse" sse-swap="message"></main>
|
||||
</bod>
|
||||
|
||||
</html>
|
||||
}
|
||||
|
||||
templ videoTemplate(path string) {
|
||||
<video autoplay>
|
||||
<source src={ "/api/file/" + path } type="video/mp4"/>
|
||||
</video>
|
||||
<video autoplay>
|
||||
<source src={ "/api/file/" + path } type="video/mp4" />
|
||||
</video>
|
||||
}
|
||||
|
||||
templ imageTemplate(path string) {
|
||||
<img src={ "/api/file/" + path }/>
|
||||
<img src={ "/api/file/" + path } />
|
||||
}
|
||||
|
||||
templ deviceInfoTemplate(ip string, mac string) {
|
||||
<p>
|
||||
templ deviceInfoTemplate(ip string, mac string, showQR bool) {
|
||||
<div style="width: 100vw; height: 100vh; display: flex; flex-direction: row; justify-content: space-between;">
|
||||
<div style="display: flex; flex-direction: column; gap: 1rem; justify-content: end; padding: 2rem; font-size: 4rem;">
|
||||
{ ip }
|
||||
<br/>
|
||||
<span style="text-transform: uppercase;">{ mac }</span>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
if showQR {
|
||||
<div style="display: flex; justify-content: end; align-items: end; padding: 2rem;">
|
||||
<div style="padding: 1rem; background-color: var(--foreground-color); border-radius: 1rem;">
|
||||
<img style="height: 30vh; width: auto; image-rendering: pixelated; image-rendering: crisp-edges;" src={"/qr?data=http://" + ip + ":8080" } alt="QR-Code" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<style>
|
||||
:root {
|
||||
--splash-bg: transparent !important;
|
||||
--splash-fade-out-state: paused !important;
|
||||
--background-color: oklch(21.6% 0.006 56.043);
|
||||
}
|
||||
</style>
|
||||
}
|
||||
Reference in New Issue
Block a user