package main import ( "context" "os" "path/filepath" ) type App struct { ctx context.Context config Config configPath string scoreSets ScoreSetsData scoreSetsPath string } func NewApp() *App { return &App{} } func (a *App) startup(ctx context.Context) { a.ctx = ctx a.loadConfig() a.loadScoreSets() } func dataDir() string { home, _ := os.UserHomeDir() dir := filepath.Join(home, "web-tuner") os.MkdirAll(dir, 0755) return dir } func (a *App) loadConfig() { a.configPath = filepath.Join(dataDir(), "config.json") cfg, err := LoadConfig(a.configPath) if err == nil { if cfg.RangeDown == 0 && cfg.RangeUp == 0 { cfg.RangeDown = 7 cfg.RangeUp = 7 } a.config = cfg return } a.config = Config{ Instrument: "guitar", Tuning: []string{"E", "A", "D", "G", "B", "E"}, Frets: 4, MaxFingers: 4, RangeDown: 7, RangeUp: 7, } } func (a *App) loadScoreSets() { a.scoreSetsPath = filepath.Join(dataDir(), "scoresets.json") data, err := LoadScoreSets(a.scoreSetsPath) if err == nil { a.scoreSets = data return } a.scoreSets = DefaultScoreSetsData() } func (a *App) GetScoreSets() ScoreSetsData { return a.scoreSets } func (a *App) SaveScoreSets(data ScoreSetsData) error { if len(data.Sets) == 0 { data = DefaultScoreSetsData() } if data.Selected < 0 || data.Selected >= len(data.Sets) { data.Selected = 0 } a.scoreSets = data return SaveScoreSets(a.scoreSetsPath, data) } func (a *App) GetConfig() Config { return a.config } func (a *App) FindChordFingerings() []ChordResult { return findChordFingerings(a.config) } func (a *App) GetChordDefinitions() map[string]ChordCategory { return GetChordDefinitions() } func (a *App) GenerateIntervalPairs() []IntervalData { return generateIntervalPairs(a.config) } func (a *App) UpdateConfig(cfg Config) ([]ChordResult, error) { if err := ValidateConfig(cfg); err != nil { return nil, err } a.config = cfg return findChordFingerings(a.config), nil } func (a *App) SaveConfig() error { return SaveConfig(a.configPath, a.config) } func (a *App) ResetConfig() Config { a.loadConfig() return a.config } func (a *App) GetChordAliases() map[string]string { return GetChordAliases() } func (a *App) ResolveChordName(name string) string { return ResolveChordName(name) } func (a *App) GetDefaultShapes() []ShapeDefinition { return DefaultShapes() } func (a *App) FindShapeTunings(query ShapeQuery, companions []ShapeDefinition) ([]TuningCandidate, error) { return findTuningsForShape(query, companions) } func (a *App) IdentifyShape(frets []int) string { return identifyShape(frets, a.config) } func (a *App) FindDensityTunings(query ShapeQuery) ([]DensityCandidate, error) { return findDensityTunings(query, a.config.Frets, a.config.MaxFingers) }