mirror of
https://github.com/RWejlgaard/org.git
synced 2026-09-02 01:15:35 +00:00
feat: add DONE state option and done marker to settings
This commit is contained in:
parent
517b60ecd9
commit
5d8e64f8a1
4 changed files with 74 additions and 4 deletions
|
|
@ -498,6 +498,18 @@ func (c *Config) AddState(name, color string) {
|
||||||
c.States.States = append(c.States.States, StateConfig{Name: name, Color: color})
|
c.States.States = append(c.States.States, StateConfig{Name: name, Color: color})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDoneState adds (or upgrades) a state and marks it as a done state.
|
||||||
|
func (c *Config) AddDoneState(name, color string) {
|
||||||
|
for i := range c.States.States {
|
||||||
|
if c.States.States[i].Name == name {
|
||||||
|
c.States.States[i].Color = color
|
||||||
|
c.States.States[i].Done = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.States.States = append(c.States.States, StateConfig{Name: name, Color: color, Done: true})
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveState removes a state from the configuration
|
// RemoveState removes a state from the configuration
|
||||||
func (c *Config) RemoveState(name string) {
|
func (c *Config) RemoveState(name string) {
|
||||||
for i, state := range c.States.States {
|
for i, state := range c.States.States {
|
||||||
|
|
|
||||||
|
|
@ -49,3 +49,25 @@ func TestFillDefaultsLeavesExplicitDoneFlagsAlone(t *testing.T) {
|
||||||
t.Error("last state (TODO) must NOT be auto-flagged when a done state already exists")
|
t.Error("last state (TODO) must NOT be auto-flagged when a done state already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddDoneState(t *testing.T) {
|
||||||
|
c := &Config{}
|
||||||
|
c.AddDoneState("CANCELLED", "240")
|
||||||
|
|
||||||
|
if len(c.States.States) != 1 {
|
||||||
|
t.Fatalf("expected 1 state, got %d", len(c.States.States))
|
||||||
|
}
|
||||||
|
s := c.States.States[0]
|
||||||
|
if s.Name != "CANCELLED" || s.Color != "240" || !s.Done {
|
||||||
|
t.Fatalf("unexpected state: %+v", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding an existing name upgrades it to done.
|
||||||
|
c.AddState("REVIEW", "99")
|
||||||
|
c.AddDoneState("REVIEW", "99")
|
||||||
|
for _, st := range c.States.States {
|
||||||
|
if st.Name == "REVIEW" && !st.Done {
|
||||||
|
t.Fatal("expected REVIEW upgraded to done")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ type uiModel struct {
|
||||||
captureCursor int // Store cursor position when entering capture mode
|
captureCursor int // Store cursor position when entering capture mode
|
||||||
datepicker datepicker.Model
|
datepicker datepicker.Model
|
||||||
dateTextFocused bool // within set-date modes: text field focused vs. calendar
|
dateTextFocused bool // within set-date modes: text field focused vs. calendar
|
||||||
|
addingDoneState bool // within add-state flow: create a done state
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitialModel(orgFile *model.OrgFile, cfg *config.Config, captureMode bool, captureText string) uiModel {
|
func InitialModel(orgFile *model.OrgFile, cfg *config.Config, captureMode bool, captureText string) uiModel {
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,12 @@ func (m *uiModel) updateSettings(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
case settingsSectionTags:
|
case settingsSectionTags:
|
||||||
m.addNewTag()
|
m.addNewTag()
|
||||||
case settingsSectionStates:
|
case settingsSectionStates:
|
||||||
|
// Rows: [0]=default state, [1..N]=states, [N+1]=add state, [N+2]=add DONE state.
|
||||||
|
if m.settingsCursor == len(m.config.States.States)+2 {
|
||||||
|
m.addNewDoneState()
|
||||||
|
} else {
|
||||||
m.addNewState()
|
m.addNewState()
|
||||||
|
}
|
||||||
case settingsSectionKeybindings:
|
case settingsSectionKeybindings:
|
||||||
// Cannot add keybindings yet
|
// Cannot add keybindings yet
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +141,7 @@ func (m *uiModel) getSettingsItemCount() int {
|
||||||
case settingsSectionTags:
|
case settingsSectionTags:
|
||||||
return len(m.config.Tags.Tags) + 1 // +1 for "Add new tag" option
|
return len(m.config.Tags.Tags) + 1 // +1 for "Add new tag" option
|
||||||
case settingsSectionStates:
|
case settingsSectionStates:
|
||||||
return len(m.config.States.States) + 2 // +1 for "Default new task state" setting, +1 for "Add new state" option
|
return len(m.config.States.States) + 3 // default state + "Add new state" + "Add new DONE state"
|
||||||
case settingsSectionKeybindings:
|
case settingsSectionKeybindings:
|
||||||
return len(m.config.GetAllKeybindings())
|
return len(m.config.GetAllKeybindings())
|
||||||
default:
|
default:
|
||||||
|
|
@ -474,6 +479,7 @@ func (m *uiModel) addNewTag() {
|
||||||
|
|
||||||
// addNewState adds a new state
|
// addNewState adds a new state
|
||||||
func (m *uiModel) addNewState() {
|
func (m *uiModel) addNewState() {
|
||||||
|
m.addingDoneState = false
|
||||||
m.textinput.SetValue("")
|
m.textinput.SetValue("")
|
||||||
m.textinput.Placeholder = "Enter state name"
|
m.textinput.Placeholder = "Enter state name"
|
||||||
m.textinput.Focus()
|
m.textinput.Focus()
|
||||||
|
|
@ -483,6 +489,16 @@ func (m *uiModel) addNewState() {
|
||||||
m.mode = modeSettingsAddState
|
m.mode = modeSettingsAddState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addNewDoneState adds a new state that is marked as done.
|
||||||
|
func (m *uiModel) addNewDoneState() {
|
||||||
|
m.addingDoneState = true
|
||||||
|
m.textinput.SetValue("")
|
||||||
|
m.textinput.Placeholder = "Enter DONE state name"
|
||||||
|
m.textinput.Focus()
|
||||||
|
m.textinput.Blur()
|
||||||
|
m.mode = modeSettingsAddState
|
||||||
|
}
|
||||||
|
|
||||||
// viewSettings renders the settings view
|
// viewSettings renders the settings view
|
||||||
func (m *uiModel) viewSettings() string {
|
func (m *uiModel) viewSettings() string {
|
||||||
var content strings.Builder
|
var content strings.Builder
|
||||||
|
|
@ -697,7 +713,7 @@ func (m *uiModel) viewSettingsStates() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
endIdx := m.settingsScroll + availableHeight
|
endIdx := m.settingsScroll + availableHeight
|
||||||
totalItems := len(m.config.States.States) + 2 // +1 for default state, +1 for "Add new state"
|
totalItems := len(m.config.States.States) + 3 // +1 for default state, +1 for "Add new state", +1 for "Add new DONE state"
|
||||||
|
|
||||||
// First show the default new task state setting (item 0)
|
// First show the default new task state setting (item 0)
|
||||||
if 0 >= m.settingsScroll && 0 < endIdx {
|
if 0 >= m.settingsScroll && 0 < endIdx {
|
||||||
|
|
@ -741,6 +757,9 @@ func (m *uiModel) viewSettingsStates() string {
|
||||||
stateStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(state.Color))
|
stateStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(state.Color))
|
||||||
line += stateStyle.Render(state.Name)
|
line += stateStyle.Render(state.Name)
|
||||||
line += fmt.Sprintf(" (color: %s)", state.Color)
|
line += fmt.Sprintf(" (color: %s)", state.Color)
|
||||||
|
if state.Done {
|
||||||
|
line += m.styles.statusStyle.Render(" ✓done")
|
||||||
|
}
|
||||||
|
|
||||||
content.WriteString(line + "\n")
|
content.WriteString(line + "\n")
|
||||||
}
|
}
|
||||||
|
|
@ -756,6 +775,17 @@ func (m *uiModel) viewSettingsStates() string {
|
||||||
content.WriteString(m.styles.statusStyle.Render("+ Add new state (press 'c')") + "\n")
|
content.WriteString(m.styles.statusStyle.Render("+ Add new state (press 'c')") + "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add new DONE state option
|
||||||
|
addDoneIdx := len(m.config.States.States) + 2
|
||||||
|
if addDoneIdx >= m.settingsScroll && addDoneIdx < endIdx {
|
||||||
|
if m.settingsCursor == addDoneIdx && !m.textinput.Focused() {
|
||||||
|
content.WriteString("▶ ")
|
||||||
|
} else {
|
||||||
|
content.WriteString(" ")
|
||||||
|
}
|
||||||
|
content.WriteString(m.styles.statusStyle.Render("+ Add new DONE state (press 'c')") + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Add scroll indicator if needed
|
// Add scroll indicator if needed
|
||||||
if totalItems > availableHeight {
|
if totalItems > availableHeight {
|
||||||
scrollInfo := fmt.Sprintf("\n[Showing %d-%d of %d]",
|
scrollInfo := fmt.Sprintf("\n[Showing %d-%d of %d]",
|
||||||
|
|
@ -916,7 +946,11 @@ func (m *uiModel) updateSettingsAddState(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
stateName := m.textinput.Value()
|
stateName := m.textinput.Value()
|
||||||
if stateName != "" {
|
if stateName != "" {
|
||||||
// Default color
|
// Default color
|
||||||
|
if m.addingDoneState {
|
||||||
|
m.config.AddDoneState(stateName, "99")
|
||||||
|
} else {
|
||||||
m.config.AddState(stateName, "99")
|
m.config.AddState(stateName, "99")
|
||||||
|
}
|
||||||
// Auto-save
|
// Auto-save
|
||||||
if err := m.config.Save(); err != nil {
|
if err := m.config.Save(); err != nil {
|
||||||
m.setStatus(fmt.Sprintf("Error saving: %v", err))
|
m.setStatus(fmt.Sprintf("Error saving: %v", err))
|
||||||
|
|
@ -924,6 +958,7 @@ func (m *uiModel) updateSettingsAddState(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
m.setStatus(fmt.Sprintf("Added state '%s' (saved)", stateName))
|
m.setStatus(fmt.Sprintf("Added state '%s' (saved)", stateName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m.addingDoneState = false
|
||||||
m.textinput.Blur()
|
m.textinput.Blur()
|
||||||
m.mode = modeSettings
|
m.mode = modeSettings
|
||||||
return m, nil
|
return m, nil
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue