k9s/internal/model/flash.go

154 lines
3.0 KiB
Go

package model
import (
"context"
"fmt"
"time"
"github.com/rs/zerolog/log"
)
const (
// DefaultFlashDelay sets the flash clear delay.
DefaultFlashDelay = 3 * time.Second
// FlashInfo represents an info message.
FlashInfo FlashLevel = iota
// FlashWarn represents an warning message.
FlashWarn
// FlashErr represents an error message.
FlashErr
)
type LevelMessage struct {
Level FlashLevel
Text string
}
func newClearMessage() LevelMessage {
return LevelMessage{}
}
func (l LevelMessage) IsClear() bool {
return l.Text == ""
}
// FlashLevel represents flash message severity.
type FlashLevel int
// FlashChan represents a flash event channel.
type FlashChan chan LevelMessage
// FlashListener represents a text model listener.
type FlashListener interface {
// FlashChanged notifies the model changed.
FlashChanged(FlashLevel, string)
// FlashCleared notifies when the filter changed.
FlashCleared()
}
// Flash represents a flash message model.
type Flash struct {
msg LevelMessage
cancel context.CancelFunc
delay time.Duration
msgChan chan LevelMessage
}
func NewFlash(dur time.Duration) *Flash {
return &Flash{
delay: dur,
msgChan: make(FlashChan, 3),
}
}
// Channel returns the flash channel.
func (f *Flash) Channel() FlashChan {
return f.msgChan
}
// Info displays an info flash message.
func (f *Flash) Info(msg string) {
f.SetMessage(FlashInfo, msg)
}
// Infof displays a formatted info flash message.
func (f *Flash) Infof(fmat string, args ...interface{}) {
f.Info(fmt.Sprintf(fmat, args...))
}
// Warn displays a warning flash message.
func (f *Flash) Warn(msg string) {
log.Warn().Msg(msg)
f.SetMessage(FlashWarn, msg)
}
// Warnf displays a formatted warning flash message.
func (f *Flash) Warnf(fmat string, args ...interface{}) {
f.Warn(fmt.Sprintf(fmat, args...))
}
// Err displays an error flash message.
func (f *Flash) Err(err error) {
log.Error().Msg(err.Error())
f.SetMessage(FlashErr, err.Error())
}
// Errf displays a formatted error flash message.
func (f *Flash) Errf(fmat string, args ...interface{}) {
var err error
for _, a := range args {
switch e := a.(type) {
case error:
err = e
}
}
log.Error().Err(err).Msgf(fmat, args...)
f.SetMessage(FlashErr, fmt.Sprintf(fmat, args...))
}
// Clear clears the flash message.
func (f *Flash) Clear() {
f.fireCleared()
}
// SetMessage sets the flash level message.
func (f *Flash) SetMessage(level FlashLevel, msg string) {
if f.cancel != nil {
f.cancel()
f.cancel = nil
}
f.setLevelMessage(LevelMessage{Level: level, Text: msg})
f.fireFlashChanged()
var ctx context.Context
ctx, f.cancel = context.WithCancel(context.Background())
go f.refresh(ctx)
}
func (f *Flash) refresh(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case <-time.After(f.delay):
f.fireCleared()
return
}
}
}
func (f *Flash) setLevelMessage(msg LevelMessage) {
f.msg = msg
}
func (f *Flash) fireFlashChanged() {
f.msgChan <- f.msg
}
func (f *Flash) fireCleared() {
f.msgChan <- newClearMessage()
}