197 lines
4.7 KiB
Go
197 lines
4.7 KiB
Go
package page
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-gl/gl/v3.3-core/gl"
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
"rhemawavetech.com/rhemawave/internal/colors"
|
|
"rhemawavetech.com/rhemawave/internal/db"
|
|
"rhemawavetech.com/rhemawave/internal/fontManager"
|
|
"rhemawavetech.com/rhemawave/internal/shaderManager"
|
|
)
|
|
|
|
type updateCheckState int
|
|
|
|
const (
|
|
updateCheckStateChecking updateCheckState = iota
|
|
updateCheckStateDone
|
|
)
|
|
|
|
type UpdateCheckPage struct {
|
|
Base
|
|
textShader *shaderManager.Shader
|
|
|
|
state updateCheckState
|
|
|
|
// "Checking for Updates." / ".." / "..."
|
|
checkingTextures [3]StringItem
|
|
|
|
// "No updates available" and "Press F3 to return"
|
|
doneMessage StringItem
|
|
doneHint StringItem
|
|
|
|
// Error message if service failed to start
|
|
errorMessage StringItem
|
|
hasError bool
|
|
|
|
pollTimer float32
|
|
dotIndex int
|
|
dotTimer float32
|
|
}
|
|
|
|
func (p *UpdateCheckPage) Init(app ApplicationInterface) error {
|
|
if err := p.Base.Init(app); err != nil {
|
|
return fmt.Errorf("failed base page initialization: %w", err)
|
|
}
|
|
|
|
fm := fontManager.Get()
|
|
sm := shaderManager.Get()
|
|
|
|
font, ok := fm.GetFont("Roboto-Regular")
|
|
if !ok {
|
|
return fmt.Errorf("failed to get font")
|
|
}
|
|
|
|
p.textShader, ok = sm.Get("text")
|
|
if !ok {
|
|
return fmt.Errorf("failed to get text shader")
|
|
}
|
|
|
|
// Get scale
|
|
baseFontSizeStr, err := db.GetConfigValue("init_font_size")
|
|
if err != nil {
|
|
return fmt.Errorf("retrieving init_font_size from db: %w", err)
|
|
}
|
|
baseFontSize, err := strconv.Atoi(baseFontSizeStr)
|
|
if err != nil {
|
|
return fmt.Errorf("parsing init_font_size: %w", err)
|
|
}
|
|
scale := float32(48) / float32(baseFontSize)
|
|
|
|
// Create checking textures with animated dots
|
|
dots := []string{"Checking for Updates.", "Checking for Updates..", "Checking for Updates..."}
|
|
for i, text := range dots {
|
|
item, err := NewStringItem(text, font, colors.White)
|
|
if err != nil {
|
|
return fmt.Errorf("creating checking texture %d: %w", i, err)
|
|
}
|
|
item.Scale(scale)
|
|
p.checkingTextures[i] = item
|
|
}
|
|
|
|
// Create done textures
|
|
hintScale := float32(32) / float32(baseFontSize)
|
|
|
|
p.doneMessage, err = NewStringItem("No updates available", font, colors.White)
|
|
if err != nil {
|
|
return fmt.Errorf("creating done message: %w", err)
|
|
}
|
|
p.doneMessage.Scale(scale)
|
|
|
|
p.doneHint, err = NewStringItem("Press F3 to return", font, colors.White)
|
|
if err != nil {
|
|
return fmt.Errorf("creating done hint: %w", err)
|
|
}
|
|
p.doneHint.Scale(hintScale)
|
|
|
|
// Start the update service
|
|
p.state = updateCheckStateChecking
|
|
if err := exec.Command("systemctl", "start", "rhemawave-update.service").Run(); err != nil {
|
|
p.errorMessage, _ = NewStringItem("Update service unavailable", font, colors.White)
|
|
p.errorMessage.Scale(scale)
|
|
p.hasError = true
|
|
p.state = updateCheckStateDone
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *UpdateCheckPage) Update(dt float32) error {
|
|
if p.state != updateCheckStateChecking {
|
|
return nil
|
|
}
|
|
|
|
// Animate dots
|
|
p.dotTimer += dt
|
|
if p.dotTimer >= 0.5 {
|
|
p.dotTimer -= 0.5
|
|
p.dotIndex = (p.dotIndex + 1) % 3
|
|
}
|
|
|
|
// Poll service status every 2 seconds
|
|
p.pollTimer += dt
|
|
if p.pollTimer >= 2.0 {
|
|
p.pollTimer -= 2.0
|
|
|
|
output, _ := exec.Command("systemctl", "is-active", "rhemawave-update.service").Output()
|
|
status := strings.TrimSpace(string(output))
|
|
if status != "active" && status != "activating" {
|
|
p.state = updateCheckStateDone
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *UpdateCheckPage) HandleEvent(event *sdl.Event) error {
|
|
if p.state != updateCheckStateDone {
|
|
return nil
|
|
}
|
|
|
|
switch e := (*event).(type) {
|
|
case *sdl.KeyboardEvent:
|
|
if e.Type != sdl.KEYDOWN {
|
|
return nil
|
|
}
|
|
switch e.Keysym.Sym {
|
|
case sdl.K_F3, sdl.K_BACKSPACE:
|
|
p.App.UnwindToPage(&Settings{})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *UpdateCheckPage) Render() error {
|
|
switch p.state {
|
|
case updateCheckStateChecking:
|
|
item := p.checkingTextures[p.dotIndex]
|
|
item.X = p.ScreenCenterX - item.W/2
|
|
item.Y = p.ScreenCenterY - item.H/2
|
|
p.RenderTexture(p.textShader, item.ID, item.Position(), item.RawDimensions(), item.Color)
|
|
|
|
case updateCheckStateDone:
|
|
var msg *StringItem
|
|
if p.hasError {
|
|
msg = &p.errorMessage
|
|
} else {
|
|
msg = &p.doneMessage
|
|
}
|
|
|
|
msg.X = p.ScreenCenterX - msg.W/2
|
|
msg.Y = p.ScreenCenterY + msg.H/2
|
|
p.RenderTexture(p.textShader, msg.ID, msg.Position(), msg.RawDimensions(), msg.Color)
|
|
|
|
p.doneHint.X = p.ScreenCenterX - p.doneHint.W/2
|
|
p.doneHint.Y = msg.Y - p.doneHint.H - 20
|
|
p.RenderTexture(p.textShader, p.doneHint.ID, p.doneHint.Position(), p.doneHint.RawDimensions(), p.doneHint.Color)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *UpdateCheckPage) Destroy() error {
|
|
for i := range p.checkingTextures {
|
|
gl.DeleteTextures(1, &p.checkingTextures[i].ID)
|
|
}
|
|
gl.DeleteTextures(1, &p.doneMessage.ID)
|
|
gl.DeleteTextures(1, &p.doneHint.ID)
|
|
if p.hasError {
|
|
gl.DeleteTextures(1, &p.errorMessage.ID)
|
|
}
|
|
return nil
|
|
}
|