Fork channel

Create a new channel as a copy of main.

Rename channel

Rename main to:

Delete channel

Delete main? This cannot be undone.

classify_bookmarks.go
package calls

import (
	"skraak/datafile"
)

// getFilterLabel returns the label matching the current filter, or first label if no filter.
func (s *ClassifyState) getFilterLabel(seg *datafile.Segment) *datafile.Label {
	if s.Config.Filter == "" {
		if len(seg.Labels) > 0 {
			return seg.Labels[0]
		}
		return nil
	}
	for _, label := range seg.Labels {
		if label.Filter == s.Config.Filter {
			return label
		}
	}
	return nil
}

// getOrCreateFilterLabel gets existing label or creates new one for the current filter.
func (s *ClassifyState) getOrCreateFilterLabel(seg *datafile.Segment) *datafile.Label {
	label := s.getFilterLabel(seg)
	if label != nil {
		return label
	}
	// Create new label
	label = &datafile.Label{
		Species:   "Don't Know",
		Certainty: 0,
		Filter:    s.Config.Filter,
	}
	seg.Labels = append(seg.Labels, label)
	s.Dirty = true
	return label
}

// HasBookmark returns true if current segment has a bookmark on the filter label.
func (s *ClassifyState) HasBookmark() bool {
	seg := s.CurrentSegment()
	if seg == nil {
		return false
	}
	label := s.getFilterLabel(seg)
	return label != nil && label.Bookmark
}

// ToggleBookmark toggles the bookmark on the current segment's filter label.
func (s *ClassifyState) ToggleBookmark() {
	seg := s.CurrentSegment()
	if seg == nil {
		return
	}

	df := s.CurrentFile()
	if df == nil {
		return
	}

	// Set reviewer
	df.Meta.Reviewer = s.Config.Reviewer

	label := s.getOrCreateFilterLabel(seg)
	label.Bookmark = !label.Bookmark
	s.Dirty = true
}

// NextBookmark navigates to the next bookmark, wrapping around if needed.
// Returns false if no bookmarks found (back at start position).
func (s *ClassifyState) NextBookmark() bool {
	startFile := s.FileIdx
	startSeg := s.SegmentIdx
	first := true

	for {
		// Advance to next segment
		if !s.NextSegment() {
			// Wrap to start of folder
			s.FileIdx = 0
			s.SegmentIdx = 0
		}

		// Check if we've looped back to start
		if !first && s.FileIdx == startFile && s.SegmentIdx == startSeg {
			return false // full circle, no bookmark found
		}
		first = false

		// Check if current segment has bookmark
		if s.hasFilterBookmark() {
			return true
		}
	}
}

// PrevBookmark navigates to the previous bookmark, wrapping around if needed.
// Returns false if no bookmarks found (back at start position).
func (s *ClassifyState) PrevBookmark() bool {
	startFile := s.FileIdx
	startSeg := s.SegmentIdx
	first := true

	for {
		// Move to previous segment
		if !s.PrevSegment() {
			// Wrap to end of folder
			s.FileIdx = len(s.DataFiles) - 1
			segs := s.filteredSegs[s.FileIdx]
			s.SegmentIdx = max(len(segs)-1, 0)
		}

		// Check if we've looped back to start
		if !first && s.FileIdx == startFile && s.SegmentIdx == startSeg {
			return false // full circle, no bookmark found
		}
		first = false

		// Check if current segment has bookmark
		if s.hasFilterBookmark() {
			return true
		}
	}
}

// hasFilterBookmark checks if current segment has bookmark on filter-matching label.
func (s *ClassifyState) hasFilterBookmark() bool {
	seg := s.CurrentSegment()
	if seg == nil {
		return false
	}
	label := s.getFilterLabel(seg)
	return label != nil && label.Bookmark
}