tiki/model/header_config.go
2026-04-18 22:27:14 -04:00

141 lines
3.4 KiB
Go

package model
import (
"sync"
"github.com/boolean-maybe/tiki/store"
"github.com/gdamore/tcell/v2"
)
// HeaderAction is a controller-free DTO representing an action for the header.
// Used to avoid import cycles between model and controller packages.
type HeaderAction struct {
ID string
Key tcell.Key
Rune rune
Label string
Modifier tcell.ModMask
ShowInHeader bool
}
// StatValue represents a single stat entry for the statusline
type StatValue struct {
Value string
Priority int
}
// HeaderConfig manages header visibility and burndown state.
// View identity and actions are now in ViewContext.
// Thread-safe model that notifies listeners when state changes.
type HeaderConfig struct {
mu sync.RWMutex
burndown []store.BurndownPoint
// Visibility state
visible bool // current header visibility (may be overridden by fullscreen view)
userPreference bool // user's preferred visibility (persisted, used when not fullscreen)
// Listener management
listeners map[int]func()
nextListener int
}
// NewHeaderConfig creates a new header config with default state
func NewHeaderConfig() *HeaderConfig {
return &HeaderConfig{
visible: true,
userPreference: true,
listeners: make(map[int]func()),
nextListener: 1,
}
}
// SetBurndown updates the burndown chart data
func (hc *HeaderConfig) SetBurndown(points []store.BurndownPoint) {
hc.mu.Lock()
hc.burndown = points
hc.mu.Unlock()
hc.notifyListeners()
}
// GetBurndown returns the current burndown chart data
func (hc *HeaderConfig) GetBurndown() []store.BurndownPoint {
hc.mu.RLock()
defer hc.mu.RUnlock()
return hc.burndown
}
// SetVisible sets the current header visibility
func (hc *HeaderConfig) SetVisible(visible bool) {
hc.mu.Lock()
changed := hc.visible != visible
hc.visible = visible
hc.mu.Unlock()
if changed {
hc.notifyListeners()
}
}
// IsVisible returns whether the header is currently visible
func (hc *HeaderConfig) IsVisible() bool {
hc.mu.RLock()
defer hc.mu.RUnlock()
return hc.visible
}
// SetUserPreference sets the user's preferred visibility
func (hc *HeaderConfig) SetUserPreference(preference bool) {
hc.mu.Lock()
hc.userPreference = preference
hc.mu.Unlock()
}
// GetUserPreference returns the user's preferred visibility
func (hc *HeaderConfig) GetUserPreference() bool {
hc.mu.RLock()
defer hc.mu.RUnlock()
return hc.userPreference
}
// ToggleUserPreference toggles the user preference and updates visible state
func (hc *HeaderConfig) ToggleUserPreference() {
hc.mu.Lock()
hc.userPreference = !hc.userPreference
hc.visible = hc.userPreference
hc.mu.Unlock()
hc.notifyListeners()
}
// AddListener registers a callback for header config changes.
// Returns a listener ID that can be used to remove the listener.
func (hc *HeaderConfig) AddListener(listener func()) int {
hc.mu.Lock()
defer hc.mu.Unlock()
id := hc.nextListener
hc.nextListener++
hc.listeners[id] = listener
return id
}
// RemoveListener removes a previously registered listener by ID
func (hc *HeaderConfig) RemoveListener(id int) {
hc.mu.Lock()
defer hc.mu.Unlock()
delete(hc.listeners, id)
}
// notifyListeners calls all registered listeners
func (hc *HeaderConfig) notifyListeners() {
hc.mu.RLock()
listeners := make([]func(), 0, len(hc.listeners))
for _, listener := range hc.listeners {
listeners = append(listeners, listener)
}
hc.mu.RUnlock()
for _, listener := range listeners {
listener()
}
}