Skip to content

Commit

Permalink
feat: channel info view
Browse files Browse the repository at this point in the history
  • Loading branch information
ardevd committed Jan 5, 2024
1 parent 952516a commit f5ca182
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 22 deletions.
16 changes: 10 additions & 6 deletions internal/lnd/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

// A wrapper around lndclient's ChannelInfo combined with a node Alias
type Channel struct {
Info lndclient.ChannelInfo
Info lndclient.ChannelInfo
Alias string
}

Expand All @@ -19,6 +19,10 @@ func (c Channel) FilterValue() string {

// bubbletea interface function
func (c Channel) Title() string {
if !c.Info.Active {
return c.Alias + " (OFFLINE)"
}

return c.Alias
}

Expand All @@ -28,8 +32,8 @@ func (c Channel) Description() string {
localBalance := c.Info.LocalBalance.ToBTC()
localBalancePercentage := localBalance / c.Info.Capacity.ToBTC()
prog := progress.New(progress.WithoutPercentage())
return satsToShortString(c.Info.LocalBalance.ToUnit(btcutil.AmountSatoshi)) +
" " + prog.ViewAs(localBalancePercentage) + " " +
satsToShortString(c.Info.RemoteBalance.ToUnit(btcutil.AmountSatoshi))
}

return satsToShortString(c.Info.LocalBalance.ToUnit(btcutil.AmountSatoshi)) +
" " + prog.ViewAs(localBalancePercentage) + " " +
satsToShortString(c.Info.RemoteBalance.ToUnit(btcutil.AmountSatoshi))
}
33 changes: 33 additions & 0 deletions internal/tui/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package tui

import (
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
)

// Base model that handles logic common to all views

type BaseModel struct{}

func NewBaseModel() *BaseModel {
return &BaseModel{}
}

func (m BaseModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, Keymap.Quit):
return m, tea.Quit
}
}
return m, nil
}

func (m BaseModel) Init() tea.Cmd {
return nil
}

func (m BaseModel) View() string {
return ""
}
82 changes: 82 additions & 0 deletions internal/tui/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package tui

import (
"context"
"fmt"

"github.com/ardevd/flash/internal/lnd"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/lightninglabs/lndclient"
)

// Model for the Channel view
type ChannelModel struct {
styles *Styles
channel lnd.Channel
lndService *lndclient.GrpcLndServices
ctx context.Context
dashboard *DashboardModel
base BaseModel
}

func NewChannelModel(service *lndclient.GrpcLndServices, channel lnd.Channel, dashboard *DashboardModel) *ChannelModel {
m := ChannelModel{lndService: service, ctx: context.Background(), channel: channel, base: *NewBaseModel(), dashboard: dashboard}
m.styles = GetDefaultStyles()
return &m
}

func (m *ChannelModel) initData(width, height int) {
// TODO: Init list data

}

func (m ChannelModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Base model logic
model, cmd := m.base.Update(msg)
if cmd != nil {
return model, cmd
}

switch msg := msg.(type) {
case tea.WindowSizeMsg:
windowSizeMsg = msg

v, h := m.styles.BorderedStyle.GetFrameSize()
m.initData(windowSizeMsg.Width-h, windowSizeMsg.Height-v)

}
return m, cmd
}

func (m ChannelModel) Init() tea.Cmd {
return nil
}

func (m ChannelModel) getChannelStateView() string {
active := m.channel.Info.Active
var stateText string
if active {
stateText = m.styles.PositiveString("ONLINE") + "\n" + m.channel.Info.Uptime.String()
} else {
stateText = m.styles.NegativeString("OFFLINE\n")
}

return stateText + "\n" + m.styles.SubKeyword("Pending HTLCs: ") + fmt.Sprintf("%d", m.channel.Info.NumPendingHtlcs)

}

func (m ChannelModel) View() string {
s := m.styles
channelInfoView := lipgloss.JoinVertical(lipgloss.Left, s.BorderedStyle.Render(
s.Keyword(m.channel.Alias)+
"\n"+s.SubKeyword("pubkey:")+m.channel.Info.PubKeyBytes.String()+
"\n"+s.SubKeyword("chanpoint: ")+m.channel.Info.ChannelPoint))

channelStateView := lipgloss.JoinVertical(lipgloss.Center, s.BorderedStyle.Render(m.getChannelStateView()))

topView := lipgloss.JoinHorizontal(lipgloss.Left, channelInfoView, channelStateView)

return lipgloss.JoinVertical(lipgloss.Left,
topView)
}
24 changes: 15 additions & 9 deletions internal/tui/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var formSelection string
func InitDashboard(service *lndclient.GrpcLndServices, nodeData lnd.NodeData) *DashboardModel {
m := DashboardModel{lndService: service, ctx: context.Background(), nodeData: nodeData}
m.styles = GetDefaultStyles()
m.base = *NewBaseModel()
return &m
}

Expand All @@ -46,6 +47,12 @@ func (m *DashboardModel) initData(width, height int) {
}

func (m DashboardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Base model logic
model, cmd := m.base.Update(msg)
if cmd != nil {
return model, cmd
}

switch msg := msg.(type) {
case tea.WindowSizeMsg:
windowSizeMsg = msg
Expand All @@ -64,14 +71,12 @@ func (m DashboardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch m.focused {
case paymentTools, messageTools, channelTools:
return m.handleFormClick()
case channels:
return m.handleChannelClick()
}
case key.Matches(msg, Keymap.Quit):
m.quitting = true
return m, tea.Quit
}
}

var cmd tea.Cmd
switch m.focused {
case payments:
m.lists[m.focused], cmd = m.lists[m.focused].Update(msg)
Expand All @@ -97,10 +102,6 @@ func (m DashboardModel) Init() tea.Cmd {
func (m DashboardModel) View() string {
s := m.styles

if m.quitting {
return ""
}

if m.loaded {
channelsView := m.lists[channels].View()
paymentsView := m.lists[payments].View()
Expand Down Expand Up @@ -223,6 +224,11 @@ func (m *DashboardModel) generateMessageToolsForm() *huh.Form {
return huh.NewForm(huh.NewGroup(s))
}

func (m *DashboardModel) handleChannelClick() (tea.Model, tea.Cmd) {
selectedChannel := m.lists[m.focused].SelectedItem().(lnd.Channel)
return NewChannelModel(m.lndService, selectedChannel, m).Update(windowSizeMsg)
}

func (m *DashboardModel) handleFormClick() (tea.Model, tea.Cmd) {
i := m.getInvoiceModel()
return i.Update(windowSizeMsg)
Expand Down Expand Up @@ -274,5 +280,5 @@ type DashboardModel struct {
nodeData lnd.NodeData
ctx context.Context
loaded bool
quitting bool
base BaseModel
}
11 changes: 8 additions & 3 deletions internal/tui/invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type InvoiceModel struct {
ctx context.Context
invoiceState InvoiceState
dashboard *DashboardModel
base *BaseModel
}

// Variables for form value reference
Expand Down Expand Up @@ -89,8 +90,9 @@ func isFormReady(v bool) error {
// Invoice generation form
func NewInvoiceModel(context context.Context, service *lndclient.GrpcLndServices, state InvoiceState, dashboard *DashboardModel) InvoiceModel {
m := InvoiceModel{width: maxWidth, lndService: service, ctx: context, invoiceState: state, dashboard: dashboard}
m.base = NewBaseModel()
m.lg = lipgloss.DefaultRenderer()
m.styles = NewDialogStyles(m.lg)
m.styles = NewStyles(m.lg)
m.form = huh.NewForm(
huh.NewGroup(
huh.NewInput().
Expand Down Expand Up @@ -133,6 +135,11 @@ func (m InvoiceModel) backToDashboard() (tea.Model, tea.Cmd) {

// Handle update messages for the model
func (m InvoiceModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Base model logic
model, cmd := m.base.Update(msg)
if cmd != nil {
return model, cmd
}
switch msg := msg.(type) {
case tea.WindowSizeMsg:
windowSizeMsg = msg
Expand All @@ -145,8 +152,6 @@ func (m InvoiceModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

case tea.KeyMsg:
switch {
case key.Matches(msg, Keymap.Quit):
return m, tea.Quit
case key.Matches(msg, Keymap.Back):
return m.backToDashboard()
case key.Matches(msg, Keymap.Enter):
Expand Down
12 changes: 8 additions & 4 deletions internal/tui/styling.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ type Styles struct {
BorderedStyle,
FocusedStyle,
Help lipgloss.Style
Keyword func(string) string
SubKeyword func(string) string
Keyword,
SubKeyword,
NegativeString,
PositiveString func(string) string
}

func GetDefaultStyles() *Styles {
return NewDialogStyles( lipgloss.DefaultRenderer())
return NewStyles(lipgloss.DefaultRenderer())
}

func NewDialogStyles(lg *lipgloss.Renderer) *Styles {
func NewStyles(lg *lipgloss.Renderer) *Styles {
s := Styles{}
s.Base = lg.NewStyle().
Padding(1, 4, 0, 1)
Expand All @@ -51,6 +53,8 @@ func NewDialogStyles(lg *lipgloss.Renderer) *Styles {

s.Keyword = makeFgStyle("211")
s.SubKeyword = makeFgStyle("140")
s.NegativeString = makeFgStyle("125")
s.PositiveString = makeFgStyle("78")
s.BorderedStyle = lipgloss.NewStyle().
Padding(1, 2).
Border(lipgloss.RoundedBorder()).
Expand Down

0 comments on commit f5ca182

Please sign in to comment.