package main import ( "fmt" "strconv" "strings" ) type Lane struct { Title string `json:"LaneTitle"` Stories []Story `json:"Stories"` Current int `json:"CurrentStory"` // Index of current story storyOff int // offset for the lane slice } func (l *Lane) CreateStory(name string, b *Board) { if name == "" { name = GetEditableLine("Story Title: ", "") if name == "" { b.SetMessage("Cancelled story creation", true) return } } l.Stories = append(l.Stories, MakeStory(name)) if l.Current < 0 { l.Current = 0 } unsavedChanges = true b.SetMessage("Story created", false) } // Zeroes out the offset and current values func (l *Lane) ResetLoadPositions() { if len(l.Stories) > 0 { l.Current = 0 } else { l.Current = -1 } l.storyOff = 0 } func (l Lane) Header(width int, selected bool) string { marker := " " color := style.Lane if selected { marker = "*" color = style.LaneSelected } if len(l.Title) > width { return fmt.Sprintf("%s\033[1;7m%*.*s%s%s", style.Lane, width, width, l.Title[:width-1], marker, styleOff) } else { width := width - 2 leftPad := (width - len(l.Title)) / 2 rightPad := width - len(l.Title) - leftPad return fmt.Sprintf("%s %s\033[1;7m%*.*s%s%s%*.*s\033[27m%s %s", style.Lane, color, leftPad-1, leftPad-1, "", l.Title, marker, rightPad, rightPad, "", style.Lane, styleOff) } } func (l Lane) StringSlice(width int, selected bool) []string { out := make([]string, 0, len(l.Stories) * 3 + 1) for i := l.storyOff; i < len(l.Stories); i++ { // Top spacer out = append(out, fmt.Sprintf("%s%*.*s%s", style.Lane, width, width, " ", styleOff)) // First card row title := l.Stories[i].Title if len(title) > width-4 { title = title[:width-5] + "…" } leadIn := " " if selected && l.Current == i { leadIn = "\033[1m➜ " } out = append(out, fmt.Sprintf("%s %s%s%-*.*s%s %s", style.Lane, style.Input, leadIn, width-4, width-4, title, style.Lane, styleOff)) // Second card row pts := strconv.Itoa(l.Stories[i].Points) if pts == "0" || pts[0] == '-' { pts = "" } users := l.Stories[i].GetUserAbbrString() if len(users) > width-4 { users = users[:width-5] + "…" } out = append(out, fmt.Sprintf("%s %s %-*.*s\033[7m%*s\033[27m%s %s", style.Lane, style.Input, width-7, width-7, users, 3, pts, style.Lane, styleOff)) } if len(out) > 0 { out = append(out, fmt.Sprintf("%s%*.*s%s", style.Lane, width, width, " ", styleOff)) } return out } func (l *Lane) DeleteStory(b *Board) { if len(l.Stories) < 1 { b.SetMessage("There are no stories to delete in this lane", true) return } cont, err := GetConfirmation("Are you sure you want to delete this story? Type 'yes' to delete: ") if err != nil { b.SetMessage(err.Error(), true) return } if !cont { b.SetMessage("Deletion canceled", true) return } if l.Current == len(l.Stories)-1 { l.Stories = l.Stories[:len(l.Stories)-1] } else { l.Stories = append(l.Stories[:l.Current], l.Stories[l.Current+1:]...) } if l.Current > len(l.Stories)-1 { l.Current -= 1 } b.StoryOpen = false unsavedChanges = true b.SetMessage("Story deleted", false) } func (l *Lane) Update(args []string, b *Board) { location := strings.ToLower(args[0]) switch location { case "title", "t", "name", "n": title := GetEditableLine("New lane title: ", l.Title) if title == "" { b.SetMessage("Canceled lane title update", true) break } l.Title = title unsavedChanges = true b.SetMessage("Lane title updated", false) default: b.SetMessage(fmt.Sprintf("Unknown lane location %q", args[0]), true) } } func MakeLane(title string) Lane { return Lane{title, make([]Story,0,5), -1, 0} }