prime8dev

prime8dev
git clone https://git.prime8.dev/prime8dev.git
Log | Files | Refs | README | LICENSE

boot.go (2869B)


      1 package tui
      2 
      3 import (
      4 	"time"
      5 
      6 	tea "github.com/charmbracelet/bubbletea"
      7 )
      8 
      9 const (
     10 	bootChars          = "\u2593\u2592\u2591\u2588\u2584\u2580\u25a0\u25a1\u25aa\u25ab\u25cf\u25cb\u25c6\u25c7"
     11 	bootStartDelay     = 100 * time.Millisecond
     12 	bootScrambleDur    = 400 * time.Millisecond
     13 	bootScrambleTick   = 30 * time.Millisecond
     14 	bootHoldDur        = 450 * time.Millisecond
     15 	bootFadeDur        = 300 * time.Millisecond
     16 	bootTitleRevealEnd = bootStartDelay + bootScrambleDur
     17 	bootSubRevealEnd   = bootTitleRevealEnd + bootScrambleDur
     18 	bootHoldEnd        = bootSubRevealEnd + bootHoldDur
     19 	bootAnimationTotal = bootHoldEnd + bootFadeDur
     20 )
     21 
     22 var bootRuneSet = []rune(bootChars)
     23 
     24 type bootTickMsg time.Time
     25 
     26 func bootTickCmd() tea.Cmd {
     27 	return tea.Tick(bootScrambleTick, func(t time.Time) tea.Msg {
     28 		return bootTickMsg(t)
     29 	})
     30 }
     31 
     32 func (m *portfolioModel) syncBootFrame(now time.Time) {
     33 	if !m.bootActive {
     34 		return
     35 	}
     36 
     37 	elapsed := now.Sub(m.bootStartedAt)
     38 	if elapsed < 0 {
     39 		elapsed = 0
     40 	}
     41 
     42 	switch {
     43 	case elapsed < bootStartDelay:
     44 		m.bootFadeProgress = 0
     45 		m.bootTitleFrame = m.scrambleBootText(m.bootTitle)
     46 		m.bootSubtitleFrame = m.scrambleBootText(m.bootSubtitle)
     47 	case elapsed < bootTitleRevealEnd:
     48 		m.bootFadeProgress = 0
     49 		p := float64(elapsed-bootStartDelay) / float64(bootScrambleDur)
     50 		m.bootTitleFrame = m.revealBootText(m.bootTitle, p)
     51 		m.bootSubtitleFrame = m.scrambleBootText(m.bootSubtitle)
     52 	case elapsed < bootSubRevealEnd:
     53 		m.bootFadeProgress = 0
     54 		p := float64(elapsed-bootTitleRevealEnd) / float64(bootScrambleDur)
     55 		m.bootTitleFrame = m.bootTitle
     56 		m.bootSubtitleFrame = m.revealBootText(m.bootSubtitle, p)
     57 	case elapsed < bootHoldEnd:
     58 		m.bootFadeProgress = 0
     59 		m.bootTitleFrame = m.bootTitle
     60 		m.bootSubtitleFrame = m.bootSubtitle
     61 	case elapsed < bootAnimationTotal:
     62 		m.bootFadeProgress = float64(elapsed-bootHoldEnd) / float64(bootFadeDur)
     63 		m.bootTitleFrame = m.bootTitle
     64 		m.bootSubtitleFrame = m.bootSubtitle
     65 	default:
     66 		m.bootFadeProgress = 1
     67 		m.bootTitleFrame = m.bootTitle
     68 		m.bootSubtitleFrame = m.bootSubtitle
     69 		m.bootActive = false
     70 	}
     71 }
     72 
     73 func (m *portfolioModel) scrambleBootText(target string) string {
     74 	length := len([]rune(target))
     75 	if length == 0 {
     76 		return ""
     77 	}
     78 	out := make([]rune, length)
     79 	for i := 0; i < length; i++ {
     80 		out[i] = bootRuneSet[m.bootRand.Intn(len(bootRuneSet))]
     81 	}
     82 	return string(out)
     83 }
     84 
     85 func (m *portfolioModel) revealBootText(target string, progress float64) string {
     86 	r := []rune(target)
     87 	if len(r) == 0 {
     88 		return ""
     89 	}
     90 
     91 	if progress < 0 {
     92 		progress = 0
     93 	} else if progress > 1 {
     94 		progress = 1
     95 	}
     96 
     97 	revealCount := int(progress * float64(len(r)))
     98 	if revealCount > len(r) {
     99 		revealCount = len(r)
    100 	}
    101 
    102 	out := make([]rune, 0, len(r))
    103 	out = append(out, r[:revealCount]...)
    104 	for i := revealCount; i < len(r); i++ {
    105 		out = append(out, bootRuneSet[m.bootRand.Intn(len(bootRuneSet))])
    106 	}
    107 
    108 	return string(out)
    109 }