113 lines
2.1 KiB
Go
113 lines
2.1 KiB
Go
package internal
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/charmbracelet/bubbles/list"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
const (
|
|
tickDuration = 1 * time.Second
|
|
)
|
|
|
|
var docStyle = lipgloss.NewStyle().Margin(1, 2)
|
|
|
|
type item struct {
|
|
title string
|
|
description string
|
|
}
|
|
|
|
func (i item) Title() string {
|
|
return i.title
|
|
}
|
|
func (i item) Description() string {
|
|
return i.description
|
|
}
|
|
func (i item) FilterValue() string {
|
|
return i.title
|
|
}
|
|
|
|
type refreshOTPsMsg struct {
|
|
t time.Time
|
|
}
|
|
|
|
type UI struct {
|
|
list list.Model
|
|
entries []Entry
|
|
}
|
|
|
|
func NewUI(entries []Entry) UI {
|
|
ui := UI{
|
|
list: list.New(entriesToItems(entries, time.Now()), list.NewDefaultDelegate(), 0, 0),
|
|
entries: entries,
|
|
}
|
|
ui.list.Title = "GoOTP"
|
|
ui.list.SetShowPagination(false)
|
|
return ui
|
|
}
|
|
|
|
func (ui UI) Init() tea.Cmd {
|
|
return ui.tick()
|
|
}
|
|
|
|
func (ui UI) Update(teaMsg tea.Msg) (tea.Model, tea.Cmd) {
|
|
var cmd tea.Cmd
|
|
switch msg := teaMsg.(type) {
|
|
case tea.KeyMsg:
|
|
if msg.String() == "ctrl+c" {
|
|
return ui, tea.Quit
|
|
}
|
|
case tea.WindowSizeMsg:
|
|
h, v := docStyle.GetFrameSize()
|
|
ui.list.SetSize(msg.Width-h, msg.Height-v)
|
|
case refreshOTPsMsg:
|
|
cmd = tea.Batch(
|
|
ui.list.SetItems(entriesToItems(ui.entries, msg.t)),
|
|
ui.tick(),
|
|
)
|
|
}
|
|
|
|
var listCmd tea.Cmd
|
|
ui.list, listCmd = ui.list.Update(teaMsg)
|
|
return ui, tea.Batch(cmd, listCmd)
|
|
}
|
|
|
|
func (ui UI) View() string {
|
|
return docStyle.Render(ui.list.View())
|
|
}
|
|
|
|
func (ui UI) tick() tea.Cmd {
|
|
return tea.Tick(tickDuration, func(t time.Time) tea.Msg {
|
|
return refreshOTPsMsg{t: t}
|
|
})
|
|
}
|
|
|
|
func entriesToItems(entries []Entry, t time.Time) []list.Item {
|
|
items := make([]list.Item, len(entries))
|
|
for i, e := range entries {
|
|
items[i] = item{
|
|
title: buildItemTitle(e.Issuer, e.Label),
|
|
description: buildItemDescription(e, t),
|
|
}
|
|
}
|
|
return items
|
|
}
|
|
|
|
func buildItemTitle(issuer, label string) string {
|
|
if issuer != "" {
|
|
return issuer + " - " + label
|
|
}
|
|
return label
|
|
}
|
|
|
|
func buildItemDescription(e Entry, t time.Time) string {
|
|
otp, remaining, err := generateOTP(e, t)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return fmt.Sprintf("%s - %d", otp, remaining)
|
|
}
|