Files
filepass/internal/tui/tui.go
2026-04-18 04:31:10 +09:00

103 lines
2.5 KiB
Go

package tui
import (
"filepass/internal/pages"
"filepass/internal/services"
"charm.land/bubbles/v2/textinput"
)
type page int
const (
pageHome page = iota
pageConfig
pageAddServer
pageSelectServer
pageServerActions
pageFileAction
pageSend
pageCleanAll
pageRemoveServer
pageSelectEditServer
pageEditServer
)
type TUIInterface struct {
Services *services.ServicesStore
Page page
MenuItems []pages.MenuItem
Selected int
Servers map[string]services.Server
ServerNames []string // sorted, stable order for list rendering
NoServers bool
InitErr error
FlashMsg string
Form addServerForm
FormErr string // inline field error (e.g. duplicate name)
Quitting bool
WindowWidth int
WindowHeight int
// server actions page
ActiveServer string
LocalDir string // user's cwd, destination for received files
StorageFiles []string
StorageLoading bool
StorageErr error
FileSelected int // cursor within StorageFiles
FileFocused bool // true = ↑↓ drives file list, false = action menu
FileScrollOff int // first visible row in StorageFiles list
FileViewHeight int // available visible rows for StorageFiles list
// file action page
ActiveFile string
FileOpLoading bool
FileOpErr error
FileOpSuccess string
// edit server page
EditingServer string // original name of server being edited
// clean all confirmation page
CleanInput textinput.Model
CleanOpLoading bool
CleanOpErr error
// send / file picker page
Picker picker
}
func NewTUIInterface(store *services.ServicesStore, localDir string) TUIInterface {
return TUIInterface{
Services: store,
Page: pageHome,
MenuItems: pages.HomeMenuItems(),
LocalDir: localDir,
}
}
// fileListHeight calculates how many rows can fit in the server storage file list.
func (m TUIInterface) fileListHeight() int {
h := m.WindowHeight
if h == 0 {
return 0 // unconstrained until first WindowSizeMsg
}
// Card chrome overhead (border top+bottom, inner padding top+bottom)
const cardOverhead = 6
// Header (title + subtitle + margins)
const headerLines = 4
// Footer (border + content)
const footerLines = 2
// Server actions menu rows (Send / Clean All)
actionLines := len(m.MenuItems)
if actionLines < 1 {
actionLines = 2
}
// File section chrome: section margin+border+padding + local-dir label+margin
const fileSectionOverhead = 5
used := cardOverhead + headerLines + footerLines + actionLines + fileSectionOverhead
available := h - used
if available < 1 {
available = 1
}
return available
}