refactor: remove cached AppConfig pointer and read configuration directly from DB

Replace in-memory atomic AppConfig caching with direct DB queries via db.GetConfig
across application and page layers. This simplifies state management and ensures
all components always operate on the latest persisted configuration.

Key changes:
- Remove Application.Config atomic cache and refreshCache mechanism
- Eliminate PageCtx.CfgPtr and pass DB handle instead
- Replace all cfg reads with db.GetConfig(app.DB)
- Update mixer, audio, UI pages, and initialization paths accordingly
- Explicitly set AppConfig table name to avoid GORM pluralization issues
- Reduce DB connection pooling (SetMaxIdleConns(1))
- Standardize application font to SpaceMonoNerdFont-Regular
- Lower default audio volume (1.0 → 0.2)
- Add Unicode checkmark glyph to font map

Behavioral impact:
- Configuration is no longer cached in memory
- Every config access now hits the DB (more consistent, slightly more overhead)
This commit is contained in:
NeilClack
2026-06-26 22:51:32 -05:00
parent 6fd5ec919c
commit 2735af5fbb
15 changed files with 239 additions and 138 deletions
-28
View File
@@ -1,28 +0,0 @@
# Changelog
## [Unreleased]
### Added
- Added proclamation sync when entering "proclamations" settings page
### Changed
- Changed audio devices page to be strictly an audio on/off toggle
- Changed settings menu items to be left-aligned with eachother
- Changed settings entry organization
### Deprecated
### Removed
- Removed list of audio devices from audio device page
### Fixed
- Fixed audio device not being initialized on first entry to F2 screen
### Security
---
+33 -24
View File
@@ -4,7 +4,6 @@ import (
"errors"
"os"
"path/filepath"
"sync/atomic"
"time"
"github.com/go-gl/gl/v3.3-core/gl"
@@ -51,7 +50,6 @@ type Application struct {
pendingAction func()
running bool
DB *gorm.DB
Config atomic.Pointer[db.AppConfig]
PageRouter *page.Router
state State
}
@@ -112,7 +110,7 @@ func Run() {
// Populate the initial Config cache OR create defaults
firstRun := false
result = DB.First(&initialConfig)
result = DB.Unscoped().First(&initialConfig)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
logger.Info("First run detected: Creating default configuration...")
@@ -148,8 +146,6 @@ func Run() {
app.state = FIRST_RUN
}
app.refreshCache()
w, h := app.initializeSDLAndOpenGL()
defer app.cleanup()
@@ -159,12 +155,10 @@ func Run() {
downloadProgressChan := make(chan download.DownloadStatus, 1000)
app.PageRouter = page.NewRouter(page.PageCtx{
CfgPtr: app.Config.Load(),
DbPtr: app.DB,
W: w,
H: h,
MessageChannel: downloadProgressChan,
RefreshConfig: app.refreshCache,
})
// Sync the proclamations from the API to the Database
@@ -188,7 +182,12 @@ func Run() {
"PinealGland.wav",
}
go download.DownloadAudioFiles(app.PageRouter.Context.MessageChannel, audioFileNames, filepath.Join(app.PageRouter.Context.CfgPtr.AssetsDir, "audio"))
config, err := db.GetConfig(app.DB)
if err != nil {
panic(err)
}
go download.DownloadAudioFiles(app.PageRouter.Context.MessageChannel, audioFileNames, filepath.Join(config.AssetsDir, "audio"))
app.runEventLoop()
}
@@ -221,7 +220,12 @@ func (app *Application) checkState() {
}
// Then check for an email address
if app.Config.Load().EmailAddress == "" {
config, err := db.GetConfig(app.DB)
if err != nil {
panic(err)
}
if config.EmailAddress == "" {
if app.state != NEEDS_EMAIL_ADDRESS {
app.PageRouter.NavigateTo(page.EMAIL_ADDRESS)
app.state = NEEDS_EMAIL_ADDRESS
@@ -230,7 +234,11 @@ func (app *Application) checkState() {
}
// Then check for a license key
if app.Config.Load().LicenseKey == "" {
config, err = db.GetConfig(app.DB)
if err != nil {
panic(err)
}
if config.LicenseKey == "" {
if app.state != NEEDS_LICENSE_KEY {
app.PageRouter.NavigateTo(page.LICENSE_KEY)
app.state = NEEDS_LICENSE_KEY
@@ -242,14 +250,6 @@ func (app *Application) checkState() {
app.PageRouter.NavigateTo(page.HOME)
}
func (app *Application) refreshCache() {
var freshConfig db.AppConfig
if result := app.DB.First(&freshConfig); result.Error != nil {
logger.Error("failed to fetch configuration from the database: %v", result.Error)
}
app.Config.Store(&freshConfig)
}
func (app *Application) initializeSDLAndOpenGL() (W, H int32) {
logger.Info("Initializing SDL")
if err := sdl.Init(sdl.INIT_VIDEO | sdl.INIT_AUDIO); err != nil {
@@ -324,29 +324,38 @@ func (app *Application) initializeSDLAndOpenGL() (W, H int32) {
func (app *Application) initializeManagers() {
logger.Info("Initializing ShaderManager")
shaderDir := filepath.Join(app.Config.Load().AssetsDir, "shaders")
config, err := db.GetConfig(app.DB)
if err != nil {
panic(err)
}
shaderDir := filepath.Join(config.AssetsDir, "shaders")
logger.Info("Loading shaders from %s", shaderDir)
if err := shaderManager.InitShaderManager(shaderDir); err != nil {
logger.Fatal("ShaderManager initialization failed: %v", err)
}
logger.Info("Initializing FontManager")
if err := fontManager.InitFontManager(app.Config.Load()); err != nil {
if err := fontManager.InitFontManager(config); err != nil {
logger.Fatal("FontManager initialization failed: %v", err)
}
}
func (app *Application) initializeAudio() {
logger.Info("Initializing audio")
if err := mixer.Init(app.Config.Load(), app.refreshCache); err != nil {
logger.Error("Unable to initialize audio device '%s': %v", app.Config.Load().SelectedAudioDevice, err)
config, err := db.GetConfig(app.DB)
if err != nil {
panic(err)
}
if err := mixer.Init(config, app.refreshCache); err != nil {
logger.Error("Unable to initialize audio device '%s': %v", config.SelectedAudioDevice, err)
logger.Error("Audio will be unavailable until a device is configured")
} else {
logger.Info("Audio initialized with device: '%s'", app.Config.Load().SelectedAudioDevice)
logger.Info("Audio initialized with device: '%s'", config.SelectedAudioDevice)
}
}
func (app *Application) refreshCache() {}
func (app *Application) cleanup() {
logger.Info("Cleaning up")
+2 -1
View File
@@ -57,7 +57,7 @@ func InitFontManager(cfg *db.AppConfig) error {
// --- NEW: Create the scrambled font after loading normal fonts ---
// We will use "DejaVuSans" as the base. If you use a different default font,
// change this string.
baseFontForScramble := "Roboto-Regular"
baseFontForScramble := "SpaceMonoNerdFont-Regular"
if _, ok := fm.Fonts[baseFontForScramble]; ok {
if err := fm.CreateScrambledFont(baseFontForScramble, "Scrambled"); err != nil {
// This is not a fatal error for the whole application, so we just log it.
@@ -526,6 +526,7 @@ func (fm *FontManager) createFontMap(font *FontEntry, scramble bool, baseFont *F
8482, // ™
232, // è
233, // é
10003, // checkmark
}
tempGlyphs := make([]TempGlyph, 0, len(chars))
var totalWidth, maxHeight int32
+1 -1
View File
@@ -70,7 +70,7 @@ func Init(cfg *db.AppConfig, onUpdate func()) error {
return err
}
SetAllSinkVolumes(1.0)
SetAllSinkVolumes(0.20)
inited = true
return nil
+41 -11
View File
@@ -100,7 +100,7 @@ func (p *AudioOptions) Init(ctx *PageCtx) error {
// Font
fm := fontManager.Get()
font, ok := fm.GetFont("Roboto-Regular")
font, ok := fm.GetFont("SpaceMonoNerdFont-Regular")
if !ok {
return fmt.Errorf("failed to get font: %w", sdl.GetError())
}
@@ -121,7 +121,12 @@ func (p *AudioOptions) Init(ctx *PageCtx) error {
return fmt.Errorf("base init failed: %w", err)
}
baseFontSize := p.Context.CfgPtr.StandardFontSize
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
baseFontSize := config.StandardFontSize
titleScale := float32(64) / float32(baseFontSize)
p.ItemScale = float32(32) / float32(baseFontSize)
@@ -211,7 +216,11 @@ func (p *AudioOptions) seedAudioFiles() error {
// ── Audio status toggle ───────────────────────────────────────────────────────
func (p *AudioOptions) CreateAudioStatusItem() error {
on := p.Context.CfgPtr.AudioEnabled
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
on := config.AudioEnabled
statusString := "Turn Audio On"
color := colors.Green
if on {
@@ -277,7 +286,11 @@ func (p *AudioOptions) CreateVolumePercentItem() error {
if p.volumePercent.ID != 0 {
gl.DeleteTextures(1, &p.volumePercent.ID)
}
pct := int(p.Context.CfgPtr.SavedVolume * 100)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
pct := int(config.SavedVolume * 100)
item, err := NewStringItem(fmt.Sprintf("%d%%", pct), p.font, colors.White)
if err != nil {
return fmt.Errorf("failed to create volume percent item: %v", err)
@@ -288,15 +301,19 @@ func (p *AudioOptions) CreateVolumePercentItem() error {
}
func (p *AudioOptions) UpdateVolume(level int) {
newVol := mixer.ConvertVolume(level) + p.Context.CfgPtr.SavedVolume
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
newVol := mixer.ConvertVolume(level) + config.SavedVolume
if newVol < 0.0 || newVol > 1.0 {
return
}
if newVol > .99 {
newVol = 1.0
}
p.Context.CfgPtr.SavedVolume = newVol
p.Context.DbPtr.Save(&p.Context.CfgPtr)
config.SavedVolume = newVol
p.Context.DbPtr.Save(&config)
if err := mixer.SetAllSinkVolumes(newVol); err != nil {
logger.Error("Error setting allSinkVolumes: %v", err)
}
@@ -311,6 +328,11 @@ func (p *AudioOptions) UpdateVolume(level int) {
// ── Layout ────────────────────────────────────────────────────────────────────
func (p *AudioOptions) layout() {
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
// Title
p.title.X = p.ScreenCenterX - p.title.W/2
p.title.Y = p.ScreenHeight - p.title.H - p.verticalMargin*2
@@ -320,7 +342,7 @@ func (p *AudioOptions) layout() {
p.prompt.Y = p.title.Y - p.verticalMargin - p.prompt.H
// Volume row
barH := int32(float32(p.Context.CfgPtr.StandardFontSize) * p.ItemScale)
barH := int32(float32(config.StandardFontSize) * p.ItemScale)
barW := int32(float32(p.ScreenWidth) * 0.30)
barX := p.ScreenCenterX - barW/2
barY := p.prompt.Y - p.verticalMargin*2 - barH
@@ -376,8 +398,12 @@ func (p *AudioOptions) updateCursorPosition() {
// ── Toggle ────────────────────────────────────────────────────────────────────
func (p *AudioOptions) ToggleAudio() {
p.Context.CfgPtr.AudioEnabled = !p.Context.CfgPtr.AudioEnabled
p.Context.DbPtr.Save(p.Context.CfgPtr)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
config.AudioEnabled = !config.AudioEnabled
p.Context.DbPtr.Save(config)
p.Context.RefreshConfig()
p.CreateAudioStatusItem()
p.layout()
@@ -447,7 +473,11 @@ func (p *AudioOptions) Update(dt float32) error {
// ── Render helpers ────────────────────────────────────────────────────────────
func (p *AudioOptions) renderVolumeBar() error {
vol := p.Context.CfgPtr.SavedVolume
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
vol := config.SavedVolume
fillW := float32(p.volumeBarW) * float32(vol)
if fillW > 0 {
+19 -7
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-gl/mathgl/mgl32"
"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"
)
@@ -59,7 +60,7 @@ func (p *EmailAddressPage) Init(ctx *PageCtx) error {
p.title = "Your Email Address"
applicationFont := "Roboto-Regular"
applicationFont := "SpaceMonoNerdFont-Regular"
fm := fontManager.Get()
textShader, ok := shaderManager.Get().Get("text")
@@ -81,7 +82,11 @@ func (p *EmailAddressPage) Init(ctx *PageCtx) error {
p.titleTextureHeight = titleHeight
// Load existing email address from database
emailAddress := ctx.CfgPtr.EmailAddress
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
emailAddress := config.EmailAddress
if emailAddress != "" {
p.inputText = emailAddress
@@ -154,9 +159,12 @@ func (p *EmailAddressPage) HandleEvent(event *sdl.Event) error {
sdl.StopTextInput()
// Save email address to database
p.Context.CfgPtr.EmailAddress = p.inputText
p.Context.DbPtr.Save(p.Context.CfgPtr)
p.Context.RefreshConfig()
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
config.EmailAddress = p.inputText
p.Context.DbPtr.Save(config)
if p.isFirstTimeSetup {
// First-time setup: navigate to License Key page
@@ -189,7 +197,7 @@ func (p *EmailAddressPage) HandleEvent(event *sdl.Event) error {
// Update updates animations and changing textures and other changes using `dt` which represents a time delta in float32.
func (p *EmailAddressPage) Update(dt float32) error {
// Get application font from database
applicationFont := "Roboto-Regular"
applicationFont := "SpaceMonoNerdFont-Regular"
fm := fontManager.Get()
sm := shaderManager.Get()
@@ -252,8 +260,12 @@ func (p *EmailAddressPage) Update(dt float32) error {
// Render performs page drawing logic.
func (p *EmailAddressPage) Render() error {
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
// Get base font size from database
baseFontSize := p.Context.CfgPtr.StandardFontSize
baseFontSize := config.StandardFontSize
sm := shaderManager.Get()
+13 -7
View File
@@ -7,6 +7,7 @@ import (
"github.com/go-gl/mathgl/mgl32"
"github.com/veandco/go-sdl2/sdl"
"rhemawavetech.com/rhemawave/internal/colors"
"rhemawavetech.com/rhemawave/internal/db"
"rhemawavetech.com/rhemawave/internal/download"
"rhemawavetech.com/rhemawave/internal/fontManager"
"rhemawavetech.com/rhemawave/internal/shaderManager"
@@ -45,7 +46,7 @@ func (p *Home) Init(ctx *PageCtx) error {
// Get font
p.fm = fontManager.Get()
font, ok := p.fm.GetFont("Roboto-Regular")
font, ok := p.fm.GetFont("SpaceMonoNerdFont-Regular")
if !ok {
return fmt.Errorf("unable to fetch font")
}
@@ -86,8 +87,13 @@ func (p *Home) Init(ctx *PageCtx) error {
return fmt.Errorf("unable to create initial message texture: %w", err)
}
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
// Create license info textures if data exists
if p.Context.CfgPtr.EmailAddress != "" || p.Context.CfgPtr.LicenseKey != "" {
if config.EmailAddress != "" || config.LicenseKey != "" {
p.hasLicenseInfo = true
// Create heading
@@ -97,8 +103,8 @@ func (p *Home) Init(ctx *PageCtx) error {
}
// Create email display if exists
if p.Context.CfgPtr.EmailAddress != "" {
emailText := fmt.Sprintf("Email: %s", p.Context.CfgPtr.EmailAddress)
if config.EmailAddress != "" {
emailText := fmt.Sprintf("Email: %s", config.EmailAddress)
p.emailDisplay, err = NewStringItem(emailText, font, colors.White)
if err != nil {
return fmt.Errorf("unable to create email display texture: %w", err)
@@ -106,8 +112,8 @@ func (p *Home) Init(ctx *PageCtx) error {
}
// Create license key display if exists
if p.Context.CfgPtr.LicenseKey != "" {
licenseKeyText := fmt.Sprintf("License Key: %s", p.Context.CfgPtr.LicenseKey)
if config.LicenseKey != "" {
licenseKeyText := fmt.Sprintf("License Key: %s", config.LicenseKey)
p.licenseKeyDisplay, err = NewStringItem(licenseKeyText, font, colors.White)
if err != nil {
return fmt.Errorf("unable to create license key display texture: %w", err)
@@ -116,7 +122,7 @@ func (p *Home) Init(ctx *PageCtx) error {
}
// Get base font size from database
baseFontSize := p.Context.CfgPtr.StandardFontSize
baseFontSize := config.StandardFontSize
p.baseFontSize = baseFontSize
// Scale the note text
+19 -7
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-gl/mathgl/mgl32"
"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/logger"
"rhemawavetech.com/rhemawave/internal/shaderManager"
@@ -55,7 +56,7 @@ func (p *LicenseKeyPage) Init(ctx *PageCtx) error {
p.title = "License Key"
// Get application font from database
applicationFont := "Roboto-Regular"
applicationFont := "SpaceMonoNerdFont-Regular"
fm := fontManager.Get()
textShader, ok := shaderManager.Get().Get("text")
@@ -77,7 +78,11 @@ func (p *LicenseKeyPage) Init(ctx *PageCtx) error {
p.titleTextureHeight = titleHeight
// Load existing license key from database
licenseKey := p.Context.CfgPtr.LicenseKey
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
licenseKey := config.LicenseKey
if licenseKey != "" {
p.inputText = licenseKey
@@ -188,9 +193,12 @@ func (p *LicenseKeyPage) HandleEvent(event *sdl.Event) error {
sdl.StopTextInput()
// Save license key to database
p.Context.CfgPtr.LicenseKey = p.inputText
p.Context.DbPtr.Save(p.Context.CfgPtr)
p.Context.RefreshConfig()
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
config.LicenseKey = p.inputText
p.Context.DbPtr.Save(config)
// Write license key to plain text file for the updater
if homeDir, err := os.UserHomeDir(); err == nil {
@@ -239,7 +247,7 @@ func (p *LicenseKeyPage) HandleEvent(event *sdl.Event) error {
// Update updates animations and changing textures and other changes using `dt` which represents a time delta in float32.
func (p *LicenseKeyPage) Update(dt float32) error {
// Get application font from database
applicationFont := "Roboto-Regular"
applicationFont := "SpaceMonoNerdFont-Regular"
fm := fontManager.Get()
sm := shaderManager.Get()
@@ -302,8 +310,12 @@ func (p *LicenseKeyPage) Update(dt float32) error {
// Render performs page drawing logic.
func (p *LicenseKeyPage) Render() error {
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
// Get base font size from database
baseFontSize := p.Context.CfgPtr.StandardFontSize
baseFontSize := config.StandardFontSize
sm := shaderManager.Get()
+6 -2
View File
@@ -79,7 +79,7 @@ func (p *LogViewerPage) Init(ctx *PageCtx) error {
p.lineColors = append(p.lineColors, color)
}
applicationFont := "Roboto-Regular"
applicationFont := "SpaceMonoNerdFont-Regular"
fm := fontManager.Get()
textShader, ok := shaderManager.Get().Get("text")
@@ -177,7 +177,11 @@ func (p *LogViewerPage) Update(dt float32) error {
}
func (p *LogViewerPage) Render() error {
baseFontSize := p.Context.CfgPtr.StandardFontSize
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
baseFontSize := config.StandardFontSize
sm := shaderManager.Get()
textShader, _ := sm.Get("text")
+24 -6
View File
@@ -105,7 +105,7 @@ func (p *ProclamationOptions) Init(ctx *PageCtx) error {
sync.SyncFrequencies(ctx.DbPtr)
fm := fontManager.Get()
font, _ := fm.GetFont("Roboto-Regular")
font, _ := fm.GetFont("SpaceMonoNerdFont-Regular")
p.font = font
sm := shaderManager.Get()
@@ -114,9 +114,14 @@ func (p *ProclamationOptions) Init(ctx *PageCtx) error {
p.Base.Init(ctx)
itemScale := float32(32) / float32(ctx.CfgPtr.StandardFontSize)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
itemScale := float32(32) / float32(config.StandardFontSize)
p.title, _ = NewStringItem("Proclamation Browser", p.font, colors.White)
p.title.Scale(float32(64) / float32(ctx.CfgPtr.StandardFontSize))
p.title.Scale(float32(64) / float32(config.StandardFontSize))
p.prompt, _ = NewStringItem("Type to Search Space to Select Enter to Save Escape to Exit", p.font, colors.White)
p.prompt.Scale(itemScale * 0.8)
@@ -183,7 +188,11 @@ func (p *ProclamationOptions) createFlatItem(name, id string, isCat bool, depth
if isCat && depth == 0 {
text = "[+] " + name
}
itemScale := float32(32) / float32(p.Context.CfgPtr.StandardFontSize)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
itemScale := float32(32) / float32(config.StandardFontSize)
lbl, _ := NewStringItem(text, p.font, colors.White)
lbl.Scale(itemScale)
return &FlatItem{
@@ -277,7 +286,12 @@ func (p *ProclamationOptions) toggleExpansion(index int) {
pureName := item.Label.content[4:]
gl.DeleteTextures(1, &item.Label.ID)
itemScale := float32(32) / float32(p.Context.CfgPtr.StandardFontSize)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
itemScale := float32(32) / float32(config.StandardFontSize)
if item.Expanded {
p.collapse(index)
item.Label, _ = NewStringItem("[+] "+pureName, p.font, colors.White)
@@ -401,7 +415,11 @@ func (p *ProclamationOptions) rebuildSearchLabel() {
if p.searchQuery == "" {
return
}
itemScale := float32(32) / float32(p.Context.CfgPtr.StandardFontSize)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
itemScale := float32(32) / float32(config.StandardFontSize)
p.searchInput, _ = NewStringItem("Search: "+p.searchQuery, p.font, colors.Yellow)
p.searchInput.Scale(itemScale * 1.1)
}
-2
View File
@@ -2,7 +2,6 @@ package page
import (
"gorm.io/gorm"
"rhemawavetech.com/rhemawave/internal/db"
"rhemawavetech.com/rhemawave/internal/download"
)
@@ -23,7 +22,6 @@ const (
)
type PageCtx struct {
CfgPtr *db.AppConfig
DbPtr *gorm.DB
W, H int32
MessageChannel chan download.DownloadStatus
+25 -10
View File
@@ -220,8 +220,11 @@ func (p *ScrollerPage) Init(ctx *PageCtx) error {
}
// Get line pattern from database
var err error
linePatternName := p.Context.CfgPtr.LinePattern
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
linePatternName := config.LinePattern
p.activePattern, err = linePattern.Get(linePatternName)
if err != nil {
@@ -241,7 +244,7 @@ func (p *ScrollerPage) Init(ctx *PageCtx) error {
p.colorPattern = colorPattern.NewColorPattern(baseColors)
// Font setup
p.fontScale = float32(32) / float32(p.Context.CfgPtr.StandardFontSize)
p.fontScale = float32(32) / float32(config.StandardFontSize)
nLines := int(float32(p.ScreenHeight) / 32.0)
p.lines = NewLineDeque(nLines * 2)
@@ -288,14 +291,14 @@ func (p *ScrollerPage) Init(ctx *PageCtx) error {
if err := p.Context.DbPtr.Where("Selected = ?", true).First(&selectedAudio).Error; err != nil {
selectedAudio = db.AudioFile{
Name: "OriginalAudio",
Path: filepath.Join(p.Context.CfgPtr.AssetsDir, "audio", "OriginalAudio.wav"),
Path: filepath.Join(config.AssetsDir, "audio", "OriginalAudio.wav"),
Selected: true,
Order: 0,
}
}
logger.Info("Playing %s", selectedAudio.Path)
if err := mixer.Play(selectedAudio.Path, true, p.Context.CfgPtr); err != nil {
if err := mixer.Play(selectedAudio.Path, true, config); err != nil {
logger.Error("Mixer returned an error: %v", err)
}
}
@@ -420,7 +423,11 @@ func (p *ScrollerPage) loadProclamations() error {
// audioPathForFrequency builds the on-disk path for a solfeggio frequency's
// audio file, e.g. 396 -> "<AssetsDir>/audio/396Hz.wav".
func (p *ScrollerPage) audioPathForFrequency(freq int) string {
return filepath.Join(p.Context.CfgPtr.AssetsDir, "audio", fmt.Sprintf("%dHz.wav", freq))
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
return filepath.Join(config.AssetsDir, "audio", fmt.Sprintf("%dHz.wav", freq))
}
// switchAudioForFrequency swaps the currently playing track to match freq.
@@ -449,9 +456,12 @@ func (p *ScrollerPage) switchAudioForFrequency(freq int) bool {
logger.Warning("No audio file for %dHz (%s), keeping current track", freq, path)
return false
}
mixer.Stop(3000, p.Context.CfgPtr)
if err := mixer.Play(path, true, p.Context.CfgPtr); err != nil {
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
mixer.Stop(3000, config)
if err := mixer.Play(path, true, config); err != nil {
logger.Error("Mixer returned an error: %v", err)
return false
}
@@ -722,7 +732,12 @@ func (p *ScrollerPage) Destroy() error {
return nil
}
mixer.Stop(3000, p.Context.CfgPtr)
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
mixer.Stop(3000, config)
// Delete each cached word texture exactly once.
for k, item := range p.wordTextureCache {
+7 -2
View File
@@ -6,6 +6,7 @@ import (
"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"
)
@@ -34,7 +35,7 @@ func (p *Settings) Init(ctx *PageCtx) error {
// Get font
fm := fontManager.Get()
font, ok := fm.GetFont("Roboto-Regular")
font, ok := fm.GetFont("SpaceMonoNerdFont-Regular")
if !ok {
return fmt.Errorf("failed to get font: %w", sdl.GetError())
}
@@ -127,7 +128,11 @@ func (p *Settings) Init(ctx *PageCtx) error {
// TODO: Add entry for "About"
// Get base font size from database
baseFontSize := p.Context.CfgPtr.StandardFontSize
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
baseFontSize := config.StandardFontSize
// Calculate scales
titleScale := float32(64) / float32(baseFontSize)
+29 -10
View File
@@ -8,6 +8,7 @@ import (
"github.com/go-gl/mathgl/mgl32"
"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/keybinds"
"rhemawavetech.com/rhemawave/internal/logger"
@@ -39,6 +40,7 @@ type WiFiSetupPage struct {
applicationFont *fontManager.FontEntry
// UI elements
BaseFontSize int
titleItem StringItem
scanningStatusItem StringItem
connectionStatusItem StringItem
@@ -75,9 +77,9 @@ func (p *WiFiSetupPage) Init(ctx *PageCtx) error {
}
fm := fontManager.Get()
font, ok := fm.GetFont("Roboto-Regular")
font, ok := fm.GetFont("SpaceMonoNerdFont-Regular")
if !ok {
return fmt.Errorf("could not find application font: Roboto-Regular")
return fmt.Errorf("could not find application font: SpaceMonoNerdFont-Regular")
}
p.applicationFont = font
@@ -92,6 +94,12 @@ func (p *WiFiSetupPage) Init(ctx *PageCtx) error {
return fmt.Errorf("failed to create scanning status item: %w", err)
}
config, err := db.GetConfig(p.Context.DbPtr)
if err != nil {
panic(err)
}
p.BaseFontSize = config.StandardFontSize
p.connectResultCh = make(chan error, 1)
p.ctx, p.cancel = context.WithCancel(context.Background())
@@ -310,7 +318,20 @@ func (p *WiFiSetupPage) rebuildNetworkList(nets []network.Network) {
label += " ★"
}
if n.Security != network.SecurityOpen {
label += " [" + string(n.Security) + "]"
var secStr string
switch n.Security {
case network.SecurityWEP:
secStr = "WEP"
case network.SecurityWPA:
secStr = "WPA"
case network.SecurityWPA2:
secStr = "WPA2"
case network.SecurityWPA3:
secStr = "WPA3"
default:
secStr = "Secured"
}
label += " [" + secStr + "]"
}
c := colors.White
@@ -417,8 +438,6 @@ func (p *WiFiSetupPage) rebuildPasswordErrorTexture() {
// ─── Render ───────────────────────────────────────────────────────────────────
func (p *WiFiSetupPage) Render() error {
baseFontSize := p.Context.CfgPtr.StandardFontSize
solidShader, _ := shaderManager.Get().Get("solid_color")
textShader, _ := shaderManager.Get().Get("text")
@@ -435,7 +454,7 @@ func (p *WiFiSetupPage) Render() error {
)
// Title — 48pt
titleScale := float32(48) / float32(baseFontSize)
titleScale := float32(48) / float32(p.BaseFontSize)
titleW := float32(p.titleItem.W) * titleScale
titleH := float32(p.titleItem.H) * titleScale
titleX := float32(p.ScreenCenterX) - titleW/2
@@ -449,7 +468,7 @@ func (p *WiFiSetupPage) Render() error {
// Status message — 30pt (was 24pt, now 1.25x)
statusY := titleY - titleH - vertMargin
if p.status == wifiStatusScanning {
scale := float32(30) / float32(baseFontSize)
scale := float32(30) / float32(p.BaseFontSize)
w := float32(p.scanningStatusItem.W) * scale
h := float32(p.scanningStatusItem.H) * scale
x := float32(p.ScreenCenterX) - w/2
@@ -459,7 +478,7 @@ func (p *WiFiSetupPage) Render() error {
white,
)
} else if p.connectionStatusItem.ID != 0 {
scale := float32(30) / float32(baseFontSize)
scale := float32(30) / float32(p.BaseFontSize)
w := float32(p.connectionStatusItem.W) * scale
h := float32(p.connectionStatusItem.H) * scale
x := float32(p.ScreenCenterX) - w/2
@@ -488,7 +507,7 @@ func (p *WiFiSetupPage) Render() error {
)
}
scale := float32(24) / float32(baseFontSize)
scale := float32(24) / float32(p.BaseFontSize)
tw := float32(item.Item.W) * scale
th := float32(item.Item.H) * scale
tx := listX + float32(listPad)
@@ -502,7 +521,7 @@ func (p *WiFiSetupPage) Render() error {
// Password dialog
if p.isEnteringPassword {
if err := p.renderPasswordDialog(solidShader, textShader, float32(baseFontSize)); err != nil {
if err := p.renderPasswordDialog(solidShader, textShader, float32(p.BaseFontSize)); err != nil {
return err
}
}
Binary file not shown.