Files
wrapped/pkg/ui/report_screen.go
2026-05-01 14:10:22 -06:00

184 lines
4.5 KiB
Go

package ui
import (
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/atridad/wrapped-cli/pkg/models"
)
type ReportScreen struct {
stats *models.UserStats
page int
maxPages int
exportFile string
}
func NewReportScreen(stats *models.UserStats) *ReportScreen {
exportFile, _ := ExportReport(stats)
return &ReportScreen{
stats: stats,
page: 0,
maxPages: 3,
exportFile: exportFile,
}
}
func (rs *ReportScreen) Init() tea.Cmd {
return nil
}
func (rs *ReportScreen) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return rs, tea.Quit
case "right", "l", "n":
if rs.page < rs.maxPages-1 {
rs.page++
}
case "left", "h", "p":
if rs.page > 0 {
rs.page--
}
}
}
return rs, nil
}
func (rs *ReportScreen) View() string {
header := lipgloss.NewStyle().
Foreground(lipgloss.Color("212")).
Bold(true).
Render(fmt.Sprintf("Gitea Wrapped %d", 2026)) + "\n"
var content string
switch rs.page {
case 0:
content = rs.renderOverviewPage()
case 1:
content = rs.renderLanguagesPage()
case 2:
content = rs.renderActivityPage()
}
footer := lipgloss.NewStyle().
Foreground(lipgloss.Color("8")).
Render(fmt.Sprintf("Page %d/%d | ← → to navigate | q to quit", rs.page+1, rs.maxPages))
report := header + "\n" + content + "\n\n" + footer
if rs.exportFile != "" {
report += "\n" + lipgloss.NewStyle().
Foreground(lipgloss.Color("10")).
Render(fmt.Sprintf("✓ Report saved: %s", rs.exportFile))
}
return report
}
func (rs *ReportScreen) renderOverviewPage() string {
var s strings.Builder
s.WriteString(lipgloss.NewStyle().
Foreground(lipgloss.Color("14")).
Bold(true).
Render("Your 2026 Overview") + "\n\n")
s.WriteString(fmt.Sprintf("Username: %s\n", rs.stats.Username))
s.WriteString(fmt.Sprintf("Total Commits: %d\n", rs.stats.TotalCommits))
s.WriteString(fmt.Sprintf("Total Repositories: %d\n", rs.stats.TotalRepositories))
s.WriteString(fmt.Sprintf("Average Commits/Day: %.2f\n", rs.stats.AverageCommitsPerDay))
s.WriteString(fmt.Sprintf("Most Active Day: %s\n", rs.stats.MostActiveDay))
s.WriteString(fmt.Sprintf("Most Active Month: %s\n", rs.stats.MostActiveMonth))
s.WriteString("\nTop Repositories:\n")
for i, repo := range rs.stats.TopRepositories {
if i >= 5 {
break
}
s.WriteString(fmt.Sprintf(" %d. %s\n", i+1, repo.Name))
}
return s.String()
}
func (rs *ReportScreen) renderLanguagesPage() string {
var s strings.Builder
s.WriteString(lipgloss.NewStyle().
Foreground(lipgloss.Color("14")).
Bold(true).
Render("Languages You Love") + "\n\n")
if len(rs.stats.Languages) == 0 {
s.WriteString("No language data available.\n")
return s.String()
}
maxLength := 30
maxCount := 0
for _, lang := range rs.stats.Languages {
if lang.Count > maxCount {
maxCount = lang.Count
}
}
for i, lang := range rs.stats.Languages {
if i >= 10 {
break
}
barLength := int(float64(lang.Count) / float64(maxCount) * float64(maxLength))
bar := strings.Repeat("█", barLength) + strings.Repeat("░", maxLength-barLength)
s.WriteString(fmt.Sprintf("%-12s %s %d (%.1f%%)\n", lang.Language, bar, lang.Count, lang.Percent))
}
return s.String()
}
func (rs *ReportScreen) renderActivityPage() string {
var s strings.Builder
s.WriteString(lipgloss.NewStyle().
Foreground(lipgloss.Color("14")).
Bold(true).
Render("Your Activity Patterns") + "\n\n")
s.WriteString("Most Active Days of the Week:\n")
if len(rs.stats.CommitsByWeekday) > 0 {
maxCount := rs.stats.CommitsByWeekday[0].Count
for i, day := range rs.stats.CommitsByWeekday {
if i >= 7 {
break
}
barLength := int(float64(day.Count) / float64(maxCount) * 20)
bar := strings.Repeat("█", barLength) + strings.Repeat("░", 20-barLength)
s.WriteString(fmt.Sprintf("%-12s %s %d\n", day.Day, bar, day.Count))
}
} else {
s.WriteString("No weekday data available.\n")
}
s.WriteString("\nMost Active Months:\n")
if len(rs.stats.CommitsByMonth) > 0 {
maxCount := rs.stats.CommitsByMonth[0].Count
for i, month := range rs.stats.CommitsByMonth {
if i >= 12 {
break
}
barLength := int(float64(month.Count) / float64(maxCount) * 20)
bar := strings.Repeat("█", barLength) + strings.Repeat("░", 20-barLength)
monthStr := month.Date.Format("Jan 2006")
s.WriteString(fmt.Sprintf("%-12s %s %d\n", monthStr, bar, month.Count))
}
} else {
s.WriteString("No monthly data available.\n")
}
return s.String()
}