Files

130 lines
3.3 KiB
Go

package screens
import (
"fmt"
"strings"
"github.com/calmcacil/wg-admin/internal/tui/components"
"github.com/calmcacil/wg-admin/internal/tui/theme"
"github.com/calmcacil/wg-admin/internal/wireguard"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/mdp/qrterminal/v3"
)
// QRScreen displays a QR code for a WireGuard client configuration
type QRScreen struct {
clientName string
configContent string
qrCode string
inlineMode bool
width, height int
errorMsg string
}
// NewQRScreen creates a new QR screen for displaying client config QR codes
func NewQRScreen(clientName string) *QRScreen {
return &QRScreen{
clientName: clientName,
inlineMode: true, // Start in inline mode
}
}
// Init initializes the QR screen
func (s *QRScreen) Init() tea.Cmd {
return s.loadConfig
}
// Update handles messages for the QR screen
func (s *QRScreen) Update(msg tea.Msg) (Screen, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "escape":
// Return to list screen (parent should handle this)
return nil, nil
case "f":
// Toggle between inline and fullscreen mode
s.inlineMode = !s.inlineMode
s.generateQRCode()
}
case tea.WindowSizeMsg:
// Handle terminal resize
s.width = msg.Width
s.height = msg.Height
s.generateQRCode()
case configLoadedMsg:
s.configContent = msg.content
s.generateQRCode()
case ErrMsg:
s.errorMsg = msg.Err.Error()
}
return s, nil
}
// View renders the QR screen
func (s *QRScreen) View() string {
// Breadcrumb: Clients > Client > QR Code
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{{Label: "Clients", ID: "list"}, {Label: s.clientName, ID: "detail"}, {Label: "QR Code", ID: "qr"}})
if s.errorMsg != "" {
return s.renderError()
}
if s.qrCode == "" {
return "Loading QR code..."
}
return breadcrumb + "\n" + s.renderQR()
}
// loadConfig loads the client configuration
func (s *QRScreen) loadConfig() tea.Msg {
content, err := wireguard.GetClientConfigContent(s.clientName)
if err != nil {
return ErrMsg{Err: err}
}
return configLoadedMsg{content: content}
}
// generateQRCode generates the QR code based on current mode and terminal size
func (s *QRScreen) generateQRCode() {
if s.configContent == "" {
return
}
// Generate QR code and capture output
var builder strings.Builder
// Generate ANSI QR code using half-block characters
qrterminal.GenerateHalfBlock(s.configContent, qrterminal.L, &builder)
s.qrCode = builder.String()
}
// renderQR renders the QR code with styling
func (s *QRScreen) renderQR() string {
styleQR := lipgloss.NewStyle().
MarginLeft(2)
title := theme.StyleTitle.MarginBottom(1).Render(fmt.Sprintf("QR Code: %s", s.clientName))
help := "Press [f] to toggle fullscreen • Press [q/Escape] to return"
return title + "\n\n" + styleQR.Render(s.qrCode) + "\n" + theme.StyleMuted.MarginTop(1).Render(help)
}
// renderError renders an error message
func (s *QRScreen) renderError() string {
title := theme.StyleError.Bold(true).Render("Error")
message := s.errorMsg
help := "Press [q/Escape] to return"
return title + "\n\n" + message + "\n" + theme.StyleMuted.MarginTop(1).Render(help)
}
// Messages
// configLoadedMsg is sent when the client configuration is loaded
type configLoadedMsg struct {
content string
}