package main import ( "context" "os" "path/filepath" ) type App struct { ctx context.Context config Config configPath string } func NewApp() *App { return &App{} } func (a *App) startup(ctx context.Context) { a.ctx = ctx a.loadConfig() } func (a *App) loadConfig() { exe, _ := os.Executable() dir := filepath.Dir(exe) candidates := []string{ filepath.Join(dir, "config.json"), "config.json", } for _, path := range candidates { cfg, err := LoadConfig(path) if err == nil { a.config = cfg a.configPath = path return } } a.configPath = "config.json" a.config = Config{ Instrument: "guitar", Tuning: []string{"E", "A", "D", "G", "B", "E"}, Frets: 4, MaxFingers: 4, } } 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) }