Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/server/handlers_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ func (s *Server) handleCreateDevicePost(w http.ResponseWriter, r *http.Request)
http.Redirect(w, r, "/", http.StatusSeeOther)
}

func (s *Server) handleDeviceTV(w http.ResponseWriter, r *http.Request) {
user := GetUser(r)
localizer := s.getLocalizer(r)
device := GetDevice(r) // Middleware provides this

s.renderTemplate(w, r, "device_tv", TemplateData{
User: user,
Localizer: localizer,
Device: device,
})
}

func (s *Server) handleUpdateDeviceGet(w http.ResponseWriter, r *http.Request) {
user := GetUser(r)
device := GetDevice(r)
Comment on lines 239 to 241
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The device object passed to handleDeviceTV via the RequireDevice middleware should already have its Apps preloaded. The s.DB.Preload("Apps").First(device, "id = ?", device.ID) call here is redundant and performs an unnecessary database query, impacting efficiency. You can remove this block as the device.Apps field should already be populated.

Expand Down
4 changes: 4 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ var templateFiles = map[string]string{
"uploadapp": "manager/uploadapp.html",
"firmware": "manager/firmware.html",
"update": "manager/update.html",
"device_tv": "manager/device_tv.html",
}

func NewServer(db *gorm.DB, cfg *config.Settings) *Server {
Expand Down Expand Up @@ -281,6 +282,9 @@ func (s *Server) routes() {

s.Router.HandleFunc("POST /devices/{id}/update_firmware_settings", s.RequireLogin(s.RequireDevice(s.handleUpdateFirmwareSettings)))

// Add this line for the TV View endpoint
s.Router.HandleFunc("GET /devices/{id}/tv", s.RequireLogin(s.RequireDevice(s.handleDeviceTV)))

// Websocket routes
s.SetupWebsocketRoutes()

Expand Down
145 changes: 145 additions & 0 deletions web/templates/manager/device_tv.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
{{define "device_tv"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Device.Name }} - TV Mode</title>
<script>
// Wait for the HTML to be fully loaded
document.addEventListener('DOMContentLoaded', () => {
const btn = document.getElementById('fullscreen-btn');

if (btn) {
btn.addEventListener('click', () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(err => {
console.error(`Error: ${err.message}`);
});
btn.innerHTML = '<i class="fa-solid fa-compress"></i> Exit';
} else {
document.exitFullscreen();
btn.innerHTML = '<i class="fa-solid fa-expand"></i> Fullscreen';
}
});
}

// Keep the interval here as well
setInterval(() => {
const images = document.querySelectorAll('.app-card img');
images.forEach(img => {
const url = new URL(img.src);
url.searchParams.set('t', Date.now());
img.src = url.toString();
});
}, 60000);
});
</script>
<style>
body, html {
background-color: black !important;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using !important in CSS is generally discouraged as it can lead to specificity wars and make stylesheets harder to maintain and debug. Consider refactoring your CSS to achieve the desired styling without relying on !important by adjusting selector specificity or order.

Suggested change
background-color: black !important;
background-color: black;

color: white;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
/* Changed to auto so you can scroll if apps overflow,
but we hide the scrollbar visuals below */
overflow-y: auto;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}

/* Hide scrollbar for Chrome, Safari and Opera */
body::-webkit-scrollbar {
display: none;
}

.tv-container {
display: flex;
flex-direction: column;
min-height: 100vh; /* Changed to min-height to allow page to grow */
padding: 30px;
box-sizing: border-box;
}

.device-header {
font-size: 2.5rem;
font-weight: bold;
margin-top: 30px; /* Changed from margin-bottom to margin-top */
border-top: 2px solid #333; /* Changed from border-bottom to border-top */
padding-top: 15px; /* Changed from padding-bottom to padding-top */
display: flex;
justify-content: space-between;
align-items: center;
}

.app-grid {
display: grid;
/* Changed to auto-fit and increased min-width to 350px
so apps look better on large screens */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This grid-template-columns declaration is duplicated on line 89. Please remove one of the redundant declarations to keep the CSS clean and avoid confusion.

grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 30px;
flex-grow: 1;
align-content: center;
}

.app-card img {
width: 100%;
height: auto;
aspect-ratio: 64/32;
object-fit: contain;
image-rendering: pixelated;
/* Ensures pixels stay sharp regardless of scaling */
}

.status-pill {
font-size: 1rem;
background: #2e7d32;
padding: 5px 15px;
border-radius: 20px;
}

/* Style for your new Fullscreen button to match the theme */
#fullscreen-btn {
cursor: pointer;
transition: opacity 0.2s;
}
#fullscreen-btn:hover {
opacity: 0.8;
}
</style>
</head>
<body>
<div class="tv-container">
<div class="app-grid">
{{ range .Device.Apps }}
{{ if .Enabled }}
<div class="app-card"
style="background: none;
border: none;
padding: 10px">
<img src="/devices/{{ $.Device.ID }}/installations/{{ .Iname }}/preview"
style="width: 100%;
aspect-ratio: 64/32;
image-rendering: pixelated;
display: block">
</div>
{{ end }}
{{ end }}
</div>
<div class="device-header">
<div>
{{ .Device.Name }} <span class="status-pill">Live Monitor</span>
</div>
<button id="fullscreen-btn"
class="w3-button w3-teal w3-round"
style="font-size: 1rem">
<i class="fa-solid fa-expand"></i> Fullscreen
</button>
</div>
</div>
</body>
</html>
{{end}}
6 changes: 6 additions & 0 deletions web/templates/partials/device_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ <h1>
style="min-width: 100px"
href="/devices/{{ .Item.ID }}/firmware"><i class="fa-solid fa-microchip" aria-hidden="true"></i> {{ t .Localizer "Firmware" }}</a>
{{ end }}
<a class="w3-button w3-teal w3-round"
style="min-width: 100px"
href="/devices/{{ .Item.ID }}/tv"
target="_blank">
<i class="fa-solid fa-tv" aria-hidden="true"></i> {{ t .Localizer "TV Mode" }}
</a>
</td>
</tr>
{{ end }}
Expand Down