Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleaner msg flow, better sizing #3

Merged
merged 3 commits into from
Jun 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 89 additions & 132 deletions ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import (
// TODO provide to models
var renderer *lipgloss.Renderer = lipgloss.DefaultRenderer()

var (
mainStyle = lipgloss.NewStyle().Margin(0).Padding(0).Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("#874BFD"))
)

func NewStyle() lipgloss.Style {
return renderer.NewStyle()
}
Expand All @@ -34,16 +38,6 @@ func navNameCmd(name string) tea.Cmd {
}
}

type FocusMsg struct {
Name string
}

func focusCmd(name string) tea.Cmd {
return func() tea.Msg {
return FocusMsg{Name: name}
}
}

type SelectCastMsg struct {
cast *api.Cast
}
Expand All @@ -55,7 +49,6 @@ type AppContext struct {
}

type App struct {
models map[string]tea.Model
ctx *AppContext
client *api.Client
cfg *config.Config
Expand All @@ -73,6 +66,11 @@ type App struct {
// signinPrompt *SigninPrompt
splash *SplashView
help *HelpView

feed *FeedView
channel *FeedView
profile *Profile
cast *CastView
}

func (a *App) PublicKey() string {
Expand Down Expand Up @@ -117,12 +115,20 @@ func NewApp(cfg *config.Config, ctx *AppContext) *App {
ctx = &AppContext{}
}
a := &App{
models: make(map[string]tea.Model),
showSidebar: true,
ctx: ctx,
client: api.NewClient(cfg),
cfg: cfg,
}
a.feed = NewFeedView(a, feedTypeFollowing)
a.focusedModel = a.feed

a.profile = NewProfile(a)

a.channel = NewFeedView(a, feedTypeChannel)

a.cast = NewCastView(a, nil)

a.sidebar = NewSidebar(a)
a.quickSelect = NewQuickSelect(a)
a.publish = NewPublishInput(a)
Expand All @@ -135,81 +141,76 @@ func NewApp(cfg *config.Config, ctx *AppContext) *App {
}
a.SetNavName("feed")

feed := NewFeedView(a)
a.Register("feed", feed)
a.SetFocus("feed")

castDetails := NewCastView(a, nil)
a.Register("cast", castDetails)

profile := NewProfile(a)
a.Register("profile", profile)
return a
}

func (a *App) GetModel(name string) tea.Model {
m, ok := a.models[name]
if !ok {
log.Println("model not found: ", name)
}
return m
}

func (a *App) Register(name string, model tea.Model) {
a.models[name] = model
}

func (a *App) SetNavName(name string) {
a.prevName = a.navname
a.navname = name
}

func (a *App) SetFocus(name string) tea.Cmd {
func (a *App) focusMain() {
if a.showQuickSelect {
a.showQuickSelect = false
}
if a.publish.Active() {
a.publish.SetActive(false)
a.publish.SetFocus(false)
}
if name == "" || name == a.focused {
return nil
}
// clear if we're back at feed
a.prev = ""
if name != "feed" {
a.prev = a.focused
}
m, ok := a.models[name]
if !ok {
log.Println("model not found: ", name)
}
a.focusedModel = m
a.focused = name
a.sidebar.SetActive(false)
if a.help.IsFull() {
a.help.SetFull(false)
}
}

func (a *App) FocusFeed() tea.Cmd {
a.focusMain()
a.SetNavName("feed")
a.focusedModel = a.feed
a.focused = "feed"
return nil
return m.Init()
}

func (a *App) FocusProfile() tea.Cmd {
a.focusMain()
a.SetNavName("profile")
a.focusedModel = a.profile
a.focused = "profile"
return a.profile.Init()
}

func (a *App) FocusChannel() tea.Cmd {
a.focusMain()
a.SetNavName("channel")
a.focusedModel = a.channel
a.focused = "channel"
return a.channel.Init()
}

func (a *App) FocusCast() tea.Cmd {
a.focusMain()
a.SetNavName("cast")
a.focusedModel = a.cast
a.focused = "cast"
return a.cast.Init()
}

func (a *App) GetFocused() tea.Model {
return a.focusedModel
}

func (a *App) FocusPrev() tea.Cmd {
if a.help.IsFull() {
a.help.SetFull(false)
}
prev := a.GetModel(a.prev)
if a.prev == "" || prev == nil {
return nil
}

if m := a.GetModel(a.prev); m != nil {
a.SetNavName(a.prevName)
return a.SetFocus(a.prev)
}
a.SetNavName("feed")
return a.SetFocus("feed")
switch a.prev {
case "feed":
return a.FocusFeed()
case "profile":
return a.FocusProfile()
case "channel":
return a.FocusChannel()
case "cast":
return a.FocusCast()
}
return a.FocusFeed()
}

func (a *App) Init() tea.Cmd {
Expand All @@ -222,16 +223,6 @@ func (a *App) Init() tea.Cmd {
return tea.Batch(cmds...)
}

func (a *App) propagateEvent(msg tea.Msg) tea.Cmd {
for name, m := range a.models {
if name == a.focused {
um, cmd := m.Update(msg)
a.models[name] = um
return cmd
}
}
return nil
}
func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

// log.Println("received msg type: ", reflect.TypeOf(msg))
Expand All @@ -247,11 +238,6 @@ func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case navNameMsg:
a.SetNavName(msg.name)
return a, nil
case FocusMsg:
cmd := a.SetFocus(msg.Name)
if cmd != nil {
return a, cmd
}
case *postResponseMsg:
_, cmd := a.publish.Update(msg)
return a, tea.Sequence(cmd, a.FocusPrev())
Expand All @@ -268,80 +254,61 @@ func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case *channelInfoMsg:
a.splash.SetInfo(msg.channel.Name)
case *api.FeedResponse:
// allow msg to pass through to profile's embedded feed
fm := a.GetFocused()
if a.focused == "profile" {
if p, ok := fm.(*Profile); ok {
p.feed.Clear()
}
_, cmd := fm.Update(msg)
return a, cmd
}
if a.focused == "feed" && a.prev == "feed" {
return a, nil
}
feed := a.GetModel("feed").(*FeedView)
feed.Clear()
focusCmd := a.SetFocus("feed")
// for first load
a.splash.SetInfo("loading channels...")
return a, tea.Batch(feed.setItems(msg.Casts), focusCmd)
case SelectProfileMsg:
focusCmd := a.SetFocus("profile")
cmd := a.GetModel("profile").(*Profile).SetFID(msg.fid)
return a, tea.Batch(focusCmd, cmd)
// pas through to feed or profile
// case SelectProfileMsg:
case SelectCastMsg:
nav := fmt.Sprintf("cast by @%s", msg.cast.Author.Username)
if msg.cast.ParentHash != "" {
nav = fmt.Sprintf("reply by @%s", msg.cast.Author.Username)
}

a.SetNavName(nav)
focusCmd := a.SetFocus("cast")
cmd := a.GetModel("cast").(*CastView).SetCast(msg.cast)
return a, tea.Sequence(cmd, focusCmd)
return a, tea.Sequence(
a.cast.SetCast(msg.cast),
a.FocusCast(),
)

case tea.WindowSizeMsg:
SetHeight(msg.Height)
SetWidth(msg.Width)

a.statusLine.SetSize(msg.Width, 1)
_, statusHeight := lipgloss.Size(a.statusLine.View())

// set the height of the statusLine
wx, wy := msg.Width, msg.Height-1
wx, wy := msg.Width, msg.Height-statusHeight

sideMax := 30
sidePct := int(float64(wx) * 0.2)
sx := sidePct
if sideMax < sidePct {
sx = sideMax
}
a.sidebar.SetSize(sx, wy)

qw := wx - sx
qh := wy - 10
a.quickSelect.SetSize(qw, qh)
a.sidebar.SetSize(sx, wy-4)
sideWidth, _ := lipgloss.Size(a.sidebar.View())

pw := wx - sx
pw := wx - sideWidth
py := wy - 10
a.publish.SetSize(pw, py)
a.splash.SetSize(pw, py)
a.quickSelect.SetSize(pw, py)
a.help.SetSize(pw, py)

hw := wx - sx
hy := wy - 10
a.help.SetSize(hw, hy)
fx, fy := mainStyle.GetFrameSize()
mx, my := wx-sideWidth-fx-4, wy-fy

// substract the sidebar width from the window width
mx, my := wx-sx, wy
childMsg := tea.WindowSizeMsg{
Width: mx,
Height: my,
}

for n, m := range a.models {
um, cmd := m.Update(childMsg)
a.models[n] = um
cmds = append(cmds, cmd)
}
_, fcmd := a.feed.Update(childMsg)
_, pcmd := a.profile.Update(childMsg)
_, ccmd := a.channel.Update(childMsg)
_, cscmd := a.cast.Update(childMsg)

cmds = append(cmds, fcmd, pcmd, ccmd, cscmd)

case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
Expand Down Expand Up @@ -426,21 +393,11 @@ func (a *App) View() string {
main = a.help.View()
}

main = mainStyle.Render(main)

return lipgloss.JoinVertical(lipgloss.Top,
lipgloss.JoinHorizontal(lipgloss.Center, side, main),
a.statusLine.View(),
)

}

func UpdateChildren(msg tea.Msg, models ...tea.Model) tea.Cmd {
cmds := make([]tea.Cmd, len(models))

// Only text inputs with Focus() set will respond, so it's safe to simply
// update all of them here without any further logic.
for i := range models {
models[i], cmds[i] = models[i].Update(msg)
}

return tea.Batch(cmds...)
}
Loading