mirror of
https://github.com/RWejlgaard/org.git
synced 2026-05-06 04:34:45 +00:00
123 lines
2.9 KiB
Go
123 lines
2.9 KiB
Go
package model
|
|
|
|
import "time"
|
|
|
|
// Item represents a single org-mode item (heading)
|
|
type Item struct {
|
|
Level int // Heading level (number of *)
|
|
State TodoState // TODO, PROG, BLOCK, DONE, or empty
|
|
Title string // The main title text
|
|
Scheduled *time.Time
|
|
Deadline *time.Time
|
|
Notes []string // Notes/content under the heading
|
|
Children []*Item // Sub-items
|
|
Folded bool // Whether the item is folded (hides notes and children)
|
|
ClockEntries []ClockEntry // Clock in/out entries
|
|
}
|
|
|
|
// OrgFile represents a parsed org-mode file
|
|
type OrgFile struct {
|
|
Path string
|
|
Items []*Item
|
|
}
|
|
|
|
// ToggleFold toggles the folded state of an item
|
|
func (item *Item) ToggleFold() {
|
|
item.Folded = !item.Folded
|
|
}
|
|
|
|
// CycleState cycles through todo states
|
|
func (item *Item) CycleState() {
|
|
switch item.State {
|
|
case StateNone:
|
|
item.State = StateTODO
|
|
case StateTODO:
|
|
item.State = StatePROG
|
|
case StatePROG:
|
|
item.State = StateBLOCK
|
|
case StateBLOCK:
|
|
item.State = StateDONE
|
|
case StateDONE:
|
|
item.State = StateNone
|
|
}
|
|
}
|
|
|
|
// ClockIn starts a new clock entry
|
|
func (item *Item) ClockIn() bool {
|
|
// Check if already clocked in
|
|
if item.IsClockedIn() {
|
|
return false
|
|
}
|
|
|
|
entry := ClockEntry{
|
|
Start: time.Now(),
|
|
End: nil,
|
|
}
|
|
item.ClockEntries = append(item.ClockEntries, entry)
|
|
return true
|
|
}
|
|
|
|
// ClockOut ends the current clock entry
|
|
func (item *Item) ClockOut() bool {
|
|
// Find the most recent open clock entry
|
|
for i := len(item.ClockEntries) - 1; i >= 0; i-- {
|
|
if item.ClockEntries[i].End == nil {
|
|
now := time.Now()
|
|
item.ClockEntries[i].End = &now
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsClockedIn returns true if there's an active clock entry
|
|
func (item *Item) IsClockedIn() bool {
|
|
for _, entry := range item.ClockEntries {
|
|
if entry.End == nil {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetCurrentClockDuration returns the duration of the current clock entry
|
|
func (item *Item) GetCurrentClockDuration() time.Duration {
|
|
for _, entry := range item.ClockEntries {
|
|
if entry.End == nil {
|
|
return time.Since(entry.Start)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// GetTotalClockDuration returns the total duration of all clock entries
|
|
func (item *Item) GetTotalClockDuration() time.Duration {
|
|
var total time.Duration
|
|
for _, entry := range item.ClockEntries {
|
|
if entry.End != nil {
|
|
// Completed clock entry
|
|
total += entry.End.Sub(entry.Start)
|
|
} else {
|
|
// Currently clocked in
|
|
total += time.Since(entry.Start)
|
|
}
|
|
}
|
|
return total
|
|
}
|
|
|
|
// GetAllItems returns a flattened list of all items (for UI display)
|
|
// Respects folding - folded items don't show their children
|
|
func (of *OrgFile) GetAllItems() []*Item {
|
|
var items []*Item
|
|
var flatten func([]*Item)
|
|
flatten = func(list []*Item) {
|
|
for _, item := range list {
|
|
items = append(items, item)
|
|
if !item.Folded {
|
|
flatten(item.Children)
|
|
}
|
|
}
|
|
}
|
|
flatten(of.Items)
|
|
return items
|
|
}
|