mirror of
https://github.com/Valkyrie00/bold-brew.git
synced 2026-03-14 22:35:53 +01:00
feat: io service refactoring (#18)
* refactored io legend and handler * implmented dedicated IOService * refactored and fixed io service * fixed quality issues * fix general and copilot issues
This commit is contained in:
parent
672d3982fd
commit
f514bc3a30
10 changed files with 207 additions and 125 deletions
4
.github/workflows/quality.yml
vendored
4
.github/workflows/quality.yml
vendored
|
|
@ -18,9 +18,9 @@ jobs:
|
|||
with:
|
||||
go-version: stable
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
version: v1.63.4
|
||||
version: v2.1
|
||||
skip-cache: true
|
||||
|
||||
build:
|
||||
|
|
|
|||
|
|
@ -1,27 +1,30 @@
|
|||
version: "2"
|
||||
run:
|
||||
timeout: 5m
|
||||
concurrency: 4
|
||||
go: "1.20"
|
||||
tests: false
|
||||
allow-parallel-runners: true
|
||||
go: '1.20'
|
||||
concurrency: 4
|
||||
|
||||
output:
|
||||
formats:
|
||||
- format: colored-line-number
|
||||
text:
|
||||
path: stdout
|
||||
print-issued-lines: true
|
||||
print-linter-name: true
|
||||
sort-results: true
|
||||
show-stats: true
|
||||
|
||||
print-linter-name: true
|
||||
print-issued-lines: true
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- gosimple
|
||||
- govet
|
||||
- staticcheck
|
||||
- unused
|
||||
- gofmt
|
||||
- gosec
|
||||
- stylecheck
|
||||
- revive
|
||||
default: none
|
||||
enable:
|
||||
- gosec
|
||||
- govet
|
||||
- revive
|
||||
- staticcheck
|
||||
- unused
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -33,8 +33,8 @@ run: build
|
|||
##############################
|
||||
# QUALITY
|
||||
##############################
|
||||
.PHONY: lint
|
||||
lint:
|
||||
.PHONY: quality
|
||||
quality:
|
||||
@golangci-lint run
|
||||
|
||||
##############################
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ var (
|
|||
|
||||
type AppServiceInterface interface {
|
||||
GetApp() *tview.Application
|
||||
GetLayout() ui.LayoutInterface
|
||||
Boot() (err error)
|
||||
BuildApp()
|
||||
}
|
||||
|
||||
type AppService struct {
|
||||
app *tview.Application
|
||||
layout ui.LayoutInterface
|
||||
theme *theme.Theme
|
||||
layout ui.LayoutInterface
|
||||
|
||||
packages *[]models.Formula
|
||||
filteredPackages *[]models.Formula
|
||||
|
|
@ -37,37 +38,37 @@ type AppService struct {
|
|||
brewVersion string
|
||||
|
||||
BrewService BrewServiceInterface
|
||||
CommandService CommandServiceInterface
|
||||
SelfUpdateService SelfUpdateServiceInterface
|
||||
IOService IOServiceInterface
|
||||
}
|
||||
|
||||
func NewAppService() AppServiceInterface {
|
||||
app := tview.NewApplication()
|
||||
themeService := theme.NewTheme()
|
||||
brewService := NewBrewService()
|
||||
layout := ui.NewLayout(themeService)
|
||||
|
||||
appService := &AppService{
|
||||
s := &AppService{
|
||||
app: app,
|
||||
theme: themeService,
|
||||
layout: ui.NewLayout(themeService),
|
||||
layout: layout,
|
||||
|
||||
packages: new([]models.Formula),
|
||||
filteredPackages: new([]models.Formula),
|
||||
showOnlyInstalled: false,
|
||||
showOnlyOutdated: false,
|
||||
brewVersion: "-",
|
||||
|
||||
BrewService: brewService,
|
||||
CommandService: NewCommandService(),
|
||||
SelfUpdateService: NewSelfUpdateService(),
|
||||
}
|
||||
|
||||
return appService
|
||||
// Initialize services
|
||||
s.IOService = NewIOService(s)
|
||||
s.BrewService = NewBrewService()
|
||||
s.SelfUpdateService = NewSelfUpdateService()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *AppService) GetApp() *tview.Application {
|
||||
return s.app
|
||||
}
|
||||
func (s *AppService) GetApp() *tview.Application { return s.app }
|
||||
func (s *AppService) GetLayout() ui.LayoutInterface { return s.layout }
|
||||
|
||||
func (s *AppService) Boot() (err error) {
|
||||
if s.brewVersion, err = s.BrewService.GetBrewVersion(); err != nil {
|
||||
|
|
@ -259,7 +260,7 @@ func (s *AppService) BuildApp() {
|
|||
s.layout.GetSearch().SetHandlers(inputDoneFunc, changedFunc)
|
||||
|
||||
// Add key event handler and set the root view
|
||||
s.app.SetInputCapture(s.handleKeyEventInput)
|
||||
s.app.SetInputCapture(s.IOService.HandleKeyEventInput)
|
||||
s.app.SetRoot(s.layout.Root(), true)
|
||||
s.app.SetFocus(s.layout.GetTable().View())
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func (s *BrewService) loadInstalled() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// Mark all installed packages as locally installed and set LocalPath
|
||||
// Mark all installed Packages as locally installed and set LocalPath
|
||||
prefix := s.GetPrefixPath()
|
||||
for i := range *s.installed {
|
||||
(*s.installed)[i].LocallyInstalled = true
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ func (s *CommandService) executeCommand(
|
|||
if err != nil {
|
||||
if err != io.EOF {
|
||||
app.QueueUpdateDraw(func() {
|
||||
outputView.Write([]byte(fmt.Sprintf("\nError: %v\n", err)))
|
||||
fmt.Fprintf(outputView, "\nError: %v\n", err)
|
||||
})
|
||||
}
|
||||
break
|
||||
|
|
@ -112,7 +112,7 @@ func (s *CommandService) executeCommand(
|
|||
if err != nil {
|
||||
if err != io.EOF {
|
||||
app.QueueUpdateDraw(func() {
|
||||
outputView.Write([]byte(fmt.Sprintf("\nError: %v\n", err)))
|
||||
fmt.Fprintf(outputView, "\nError: %v\n", err)
|
||||
})
|
||||
}
|
||||
break
|
||||
|
|
|
|||
|
|
@ -1,107 +1,174 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"bbrew/internal/ui"
|
||||
"fmt"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
func (s *AppService) handleKeyEventInput(event *tcell.EventKey) *tcell.EventKey {
|
||||
var (
|
||||
IoSearch = IOAction{Key: tcell.KeyRune, Rune: '/', KeySlug: "/", Name: "Search"}
|
||||
IoFilterInstalled = IOAction{Key: tcell.KeyRune, Rune: 'f', KeySlug: "f", Name: "Filter Installed"}
|
||||
IoFilterOutdated = IOAction{Key: tcell.KeyRune, Rune: 'o', KeySlug: "o", Name: "Filter Outdated"}
|
||||
IoInstall = IOAction{Key: tcell.KeyRune, Rune: 'i', KeySlug: "i", Name: "Install"}
|
||||
IoUpdate = IOAction{Key: tcell.KeyRune, Rune: 'u', KeySlug: "u", Name: "Update"}
|
||||
IoRemove = IOAction{Key: tcell.KeyRune, Rune: 'r', KeySlug: "r", Name: "Remove"}
|
||||
IoUpdateAll = IOAction{Key: tcell.KeyCtrlU, Rune: 0, KeySlug: "ctrl+u", Name: "Update All"}
|
||||
IoBack = IOAction{Key: tcell.KeyEsc, Rune: 0, KeySlug: "esc", Name: "Back to Table"}
|
||||
IoQuit = IOAction{Key: tcell.KeyRune, Rune: 'q', KeySlug: "q", Name: "Quit"}
|
||||
)
|
||||
|
||||
type IOAction struct {
|
||||
Key tcell.Key
|
||||
Rune rune
|
||||
Name string
|
||||
KeySlug string
|
||||
Action func()
|
||||
}
|
||||
|
||||
func (k *IOAction) SetAction(action func()) {
|
||||
k.Action = action
|
||||
}
|
||||
|
||||
type IOServiceInterface interface {
|
||||
HandleKeyEventInput(event *tcell.EventKey) *tcell.EventKey
|
||||
}
|
||||
|
||||
type IOService struct {
|
||||
appService *AppService
|
||||
layout ui.LayoutInterface
|
||||
commandService CommandServiceInterface
|
||||
keyActions []*IOAction
|
||||
legendEntries []struct{ KeySlug, Name string }
|
||||
}
|
||||
|
||||
var NewIOService = func(appService *AppService) IOServiceInterface {
|
||||
s := &IOService{
|
||||
appService: appService,
|
||||
layout: appService.GetLayout(),
|
||||
commandService: NewCommandService(),
|
||||
}
|
||||
|
||||
// Define actions for each key input
|
||||
s.keyActions = []*IOAction{&IoSearch, &IoFilterInstalled, &IoFilterOutdated, &IoInstall, &IoUpdate, &IoUpdateAll, &IoRemove, &IoBack, &IoQuit}
|
||||
IoQuit.SetAction(s.handleQuitEvent)
|
||||
IoUpdate.SetAction(s.handleUpdatePackageEvent)
|
||||
IoUpdateAll.SetAction(s.handleUpdateAllPackagesEvent)
|
||||
IoRemove.SetAction(s.handleRemovePackageEvent)
|
||||
IoInstall.SetAction(s.handleInstallPackageEvent)
|
||||
IoSearch.SetAction(s.handleSearchFieldEvent)
|
||||
IoFilterInstalled.SetAction(s.handleFilterPackagesEvent)
|
||||
IoFilterOutdated.SetAction(s.handleFilterOutdatedPackagesEvent)
|
||||
IoBack.SetAction(s.handleBack)
|
||||
|
||||
// Convert IOMap to a map for easier access
|
||||
s.legendEntries = make([]struct{ KeySlug, Name string }, len(s.keyActions))
|
||||
for i, input := range s.keyActions {
|
||||
s.legendEntries[i] = struct{ KeySlug, Name string }{KeySlug: input.KeySlug, Name: input.Name}
|
||||
}
|
||||
|
||||
// Initialize the legend text
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, "")
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *IOService) HandleKeyEventInput(event *tcell.EventKey) *tcell.EventKey {
|
||||
if s.layout.GetSearch().Field().HasFocus() {
|
||||
return event
|
||||
}
|
||||
|
||||
keyActions := map[tcell.Key]func(){
|
||||
tcell.KeyRune: func() {
|
||||
runeActions := map[rune]func(){
|
||||
'q': s.handleQuitEvent,
|
||||
'u': s.handleUpdatePackageEvent,
|
||||
'r': s.handleRemovePackageEvent,
|
||||
'i': s.handleInstallPackageEvent,
|
||||
'/': s.handleSearchFieldEvent,
|
||||
'f': s.handleFilterPackagesEvent,
|
||||
'o': s.handleFilterOutdatedPackagesEvent, // New key binding for filtering outdated packages
|
||||
for _, input := range s.keyActions {
|
||||
if event.Modifiers() == tcell.ModNone && input.Key == event.Key() && input.Rune == event.Rune() { // Check Rune
|
||||
if input.Action != nil {
|
||||
input.Action()
|
||||
return nil
|
||||
}
|
||||
if action, exists := runeActions[event.Rune()]; exists {
|
||||
action()
|
||||
} else if event.Modifiers() != tcell.ModNone && input.Key == event.Key() { // Check Key only
|
||||
if input.Action != nil {
|
||||
input.Action()
|
||||
return nil
|
||||
}
|
||||
},
|
||||
tcell.KeyCtrlU: s.handleUpdateAllPackagesEvent,
|
||||
tcell.KeyEsc: func() {
|
||||
s.app.SetRoot(s.layout.Root(), true)
|
||||
s.app.SetFocus(s.layout.GetTable().View())
|
||||
},
|
||||
}
|
||||
|
||||
if action, exists := keyActions[event.Key()]; exists {
|
||||
action()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
func (s *AppService) handleSearchFieldEvent() {
|
||||
s.app.SetFocus(s.layout.GetSearch().Field())
|
||||
func (s *IOService) handleBack() {
|
||||
s.appService.GetApp().SetRoot(s.layout.Root(), true)
|
||||
s.appService.GetApp().SetFocus(s.layout.GetTable().View())
|
||||
}
|
||||
|
||||
func (s *AppService) handleQuitEvent() {
|
||||
s.app.Stop()
|
||||
func (s *IOService) handleSearchFieldEvent() {
|
||||
s.appService.GetApp().SetFocus(s.layout.GetSearch().Field())
|
||||
}
|
||||
|
||||
func (s *AppService) handleFilterPackagesEvent() {
|
||||
if s.showOnlyOutdated {
|
||||
s.showOnlyOutdated = false
|
||||
s.showOnlyInstalled = true
|
||||
func (s *IOService) handleQuitEvent() {
|
||||
s.appService.GetApp().Stop()
|
||||
}
|
||||
|
||||
func (s *IOService) handleFilterPackagesEvent() {
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, "")
|
||||
|
||||
if s.appService.showOnlyOutdated {
|
||||
s.appService.showOnlyOutdated = false
|
||||
s.appService.showOnlyInstalled = true
|
||||
} else {
|
||||
s.showOnlyInstalled = !s.showOnlyInstalled
|
||||
s.appService.showOnlyInstalled = !s.appService.showOnlyInstalled
|
||||
}
|
||||
|
||||
// Update the search field label
|
||||
if s.showOnlyOutdated {
|
||||
if s.appService.showOnlyOutdated {
|
||||
s.layout.GetSearch().Field().SetLabel("Search (Outdated): ")
|
||||
} else if s.showOnlyInstalled {
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, IoFilterOutdated.KeySlug)
|
||||
} else if s.appService.showOnlyInstalled {
|
||||
s.layout.GetSearch().Field().SetLabel("Search (Installed): ")
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, IoFilterInstalled.KeySlug)
|
||||
} else {
|
||||
s.layout.GetSearch().Field().SetLabel("Search (All): ")
|
||||
}
|
||||
|
||||
s.search(s.layout.GetSearch().Field().GetText(), true)
|
||||
s.appService.search(s.layout.GetSearch().Field().GetText(), true)
|
||||
}
|
||||
|
||||
func (s *AppService) handleFilterOutdatedPackagesEvent() {
|
||||
if s.showOnlyInstalled {
|
||||
s.showOnlyInstalled = false
|
||||
s.showOnlyOutdated = true
|
||||
func (s *IOService) handleFilterOutdatedPackagesEvent() {
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, "")
|
||||
|
||||
if s.appService.showOnlyInstalled {
|
||||
s.appService.showOnlyInstalled = false
|
||||
s.appService.showOnlyOutdated = true
|
||||
} else {
|
||||
s.showOnlyOutdated = !s.showOnlyOutdated
|
||||
s.appService.showOnlyOutdated = !s.appService.showOnlyOutdated
|
||||
}
|
||||
|
||||
// Update the search field label
|
||||
if s.showOnlyOutdated {
|
||||
if s.appService.showOnlyOutdated {
|
||||
s.layout.GetSearch().Field().SetLabel("Search (Outdated): ")
|
||||
} else if s.showOnlyInstalled {
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, IoFilterOutdated.KeySlug)
|
||||
} else if s.appService.showOnlyInstalled {
|
||||
s.layout.GetSearch().Field().SetLabel("Search (Installed): ")
|
||||
s.layout.GetLegend().SetLegend(s.legendEntries, IoFilterInstalled.KeySlug)
|
||||
} else {
|
||||
s.layout.GetSearch().Field().SetLabel("Search (All): ")
|
||||
}
|
||||
|
||||
s.search(s.layout.GetSearch().Field().GetText(), true)
|
||||
s.appService.search(s.layout.GetSearch().Field().GetText(), true)
|
||||
}
|
||||
|
||||
func (s *AppService) showModal(text string, confirmFunc func(), cancelFunc func()) {
|
||||
func (s *IOService) showModal(text string, confirmFunc func(), cancelFunc func()) {
|
||||
modal := s.layout.GetModal().Build(text, confirmFunc, cancelFunc)
|
||||
s.app.SetRoot(modal, true)
|
||||
s.appService.app.SetRoot(modal, true)
|
||||
}
|
||||
|
||||
func (s *AppService) closeModal() {
|
||||
s.app.SetRoot(s.layout.Root(), true)
|
||||
s.app.SetFocus(s.layout.GetTable().View())
|
||||
func (s *IOService) closeModal() {
|
||||
s.appService.app.SetRoot(s.layout.Root(), true)
|
||||
s.appService.app.SetFocus(s.layout.GetTable().View())
|
||||
}
|
||||
|
||||
func (s *AppService) handleInstallPackageEvent() {
|
||||
func (s *IOService) handleInstallPackageEvent() {
|
||||
row, _ := s.layout.GetTable().View().GetSelection()
|
||||
if row > 0 {
|
||||
info := (*s.filteredPackages)[row-1]
|
||||
info := (*s.appService.filteredPackages)[row-1]
|
||||
s.showModal(
|
||||
fmt.Sprintf("Are you sure you want to install the package: %s?", info.Name),
|
||||
func() {
|
||||
|
|
@ -109,21 +176,21 @@ func (s *AppService) handleInstallPackageEvent() {
|
|||
s.layout.GetOutput().Clear()
|
||||
go func() {
|
||||
s.layout.GetNotifier().ShowWarning(fmt.Sprintf("Installing %s...", info.Name))
|
||||
if err := s.CommandService.InstallPackage(info, s.app, s.layout.GetOutput().View()); err != nil {
|
||||
if err := s.commandService.InstallPackage(info, s.appService.app, s.layout.GetOutput().View()); err != nil {
|
||||
s.layout.GetNotifier().ShowError(fmt.Sprintf("Failed to install %s", info.Name))
|
||||
return
|
||||
}
|
||||
s.layout.GetNotifier().ShowSuccess(fmt.Sprintf("Installed %s", info.Name))
|
||||
s.forceRefreshResults()
|
||||
s.appService.forceRefreshResults()
|
||||
}()
|
||||
}, s.closeModal)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AppService) handleRemovePackageEvent() {
|
||||
func (s *IOService) handleRemovePackageEvent() {
|
||||
row, _ := s.layout.GetTable().View().GetSelection()
|
||||
if row > 0 {
|
||||
info := (*s.filteredPackages)[row-1]
|
||||
info := (*s.appService.filteredPackages)[row-1]
|
||||
s.showModal(
|
||||
fmt.Sprintf("Are you sure you want to remove the package: %s?", info.Name),
|
||||
func() {
|
||||
|
|
@ -131,21 +198,21 @@ func (s *AppService) handleRemovePackageEvent() {
|
|||
s.layout.GetOutput().Clear()
|
||||
go func() {
|
||||
s.layout.GetNotifier().ShowWarning(fmt.Sprintf("Removing %s...", info.Name))
|
||||
if err := s.CommandService.RemovePackage(info, s.app, s.layout.GetOutput().View()); err != nil {
|
||||
if err := s.commandService.RemovePackage(info, s.appService.app, s.layout.GetOutput().View()); err != nil {
|
||||
s.layout.GetNotifier().ShowError(fmt.Sprintf("Failed to remove %s", info.Name))
|
||||
return
|
||||
}
|
||||
s.layout.GetNotifier().ShowSuccess(fmt.Sprintf("Removed %s", info.Name))
|
||||
s.forceRefreshResults()
|
||||
s.appService.forceRefreshResults()
|
||||
}()
|
||||
}, s.closeModal)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AppService) handleUpdatePackageEvent() {
|
||||
func (s *IOService) handleUpdatePackageEvent() {
|
||||
row, _ := s.layout.GetTable().View().GetSelection()
|
||||
if row > 0 {
|
||||
info := (*s.filteredPackages)[row-1]
|
||||
info := (*s.appService.filteredPackages)[row-1]
|
||||
s.showModal(
|
||||
fmt.Sprintf("Are you sure you want to update the package: %s?", info.Name),
|
||||
func() {
|
||||
|
|
@ -153,29 +220,29 @@ func (s *AppService) handleUpdatePackageEvent() {
|
|||
s.layout.GetOutput().Clear()
|
||||
go func() {
|
||||
s.layout.GetNotifier().ShowWarning(fmt.Sprintf("Updating %s...", info.Name))
|
||||
if err := s.CommandService.UpdatePackage(info, s.app, s.layout.GetOutput().View()); err != nil {
|
||||
if err := s.commandService.UpdatePackage(info, s.appService.app, s.layout.GetOutput().View()); err != nil {
|
||||
s.layout.GetNotifier().ShowError(fmt.Sprintf("Failed to update %s", info.Name))
|
||||
return
|
||||
}
|
||||
s.layout.GetNotifier().ShowSuccess(fmt.Sprintf("Updated %s", info.Name))
|
||||
s.forceRefreshResults()
|
||||
s.appService.forceRefreshResults()
|
||||
}()
|
||||
}, s.closeModal)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AppService) handleUpdateAllPackagesEvent() {
|
||||
s.showModal("Are you sure you want to update all packages?", func() {
|
||||
func (s *IOService) handleUpdateAllPackagesEvent() {
|
||||
s.showModal("Are you sure you want to update all Packages?", func() {
|
||||
s.closeModal()
|
||||
s.layout.GetOutput().Clear()
|
||||
go func() {
|
||||
s.layout.GetNotifier().ShowWarning("Updating all packages...")
|
||||
if err := s.CommandService.UpdateAllPackages(s.app, s.layout.GetOutput().View()); err != nil {
|
||||
s.layout.GetNotifier().ShowError("Failed to update all packages")
|
||||
s.layout.GetNotifier().ShowWarning("Updating all Packages...")
|
||||
if err := s.commandService.UpdateAllPackages(s.appService.app, s.layout.GetOutput().View()); err != nil {
|
||||
s.layout.GetNotifier().ShowError("Failed to update all Packages")
|
||||
return
|
||||
}
|
||||
s.layout.GetNotifier().ShowSuccess("Updated all packages")
|
||||
s.forceRefreshResults()
|
||||
s.layout.GetNotifier().ShowSuccess("Updated all Packages")
|
||||
s.appService.forceRefreshResults()
|
||||
}()
|
||||
}, s.closeModal)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package components
|
|||
|
||||
import (
|
||||
"bbrew/internal/ui/theme"
|
||||
"fmt"
|
||||
"github.com/rivo/tview"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Legend struct {
|
||||
|
|
@ -11,20 +13,7 @@ type Legend struct {
|
|||
}
|
||||
|
||||
func NewLegend(theme *theme.Theme) *Legend {
|
||||
legendText := tview.Escape(
|
||||
"[/] Search | " +
|
||||
"[f] Filter Installed | " +
|
||||
"[o] Filter Outdated | " +
|
||||
"[i] Install | " +
|
||||
"[u] Update | " +
|
||||
"[ctrl+u] Update All | " +
|
||||
"[r] Remove | " +
|
||||
"[Esc] Back to Table | " +
|
||||
"[q] Quit",
|
||||
)
|
||||
|
||||
legendView := tview.NewTextView().
|
||||
SetText(legendText).
|
||||
SetDynamicColors(true).
|
||||
SetTextAlign(tview.AlignCenter).
|
||||
SetTextColor(theme.LegendColor)
|
||||
|
|
@ -39,6 +28,27 @@ func (l *Legend) View() *tview.TextView {
|
|||
return l.view
|
||||
}
|
||||
|
||||
func (l *Legend) GetFormattedLabel(keySlug, label string, active bool) string {
|
||||
if active {
|
||||
return fmt.Sprintf("[yellow::b]%s[-]", tview.Escape(fmt.Sprintf("[%s] %s", keySlug, label)))
|
||||
}
|
||||
|
||||
return tview.Escape(fmt.Sprintf("[%s] %s", keySlug, label))
|
||||
}
|
||||
|
||||
func (l *Legend) SetLegend(legend []struct{ KeySlug, Name string }, activeKey string) {
|
||||
var builder strings.Builder
|
||||
for i, item := range legend {
|
||||
active := item.KeySlug == activeKey
|
||||
builder.WriteString(l.GetFormattedLabel(item.KeySlug, item.Name, active))
|
||||
if i < len(legend)-1 {
|
||||
builder.WriteString(" | ")
|
||||
}
|
||||
}
|
||||
|
||||
l.SetText(builder.String())
|
||||
}
|
||||
|
||||
func (l *Legend) SetText(text string) {
|
||||
l.view.SetText(text)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ func (m *Modal) Build(text string, confirmFunc func(), cancelFunc func()) *tview
|
|||
SetText(text).
|
||||
AddButtons([]string{"Confirm", "Cancel"}).
|
||||
SetDoneFunc(func(buttonIndex int, _ string) {
|
||||
if buttonIndex == 0 {
|
||||
switch buttonIndex {
|
||||
case 0:
|
||||
confirmFunc()
|
||||
} else if buttonIndex == 1 {
|
||||
case 1:
|
||||
cancelFunc()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ type Layout struct {
|
|||
theme *theme.Theme
|
||||
}
|
||||
|
||||
func NewLayout(theme *theme.Theme) *Layout {
|
||||
func NewLayout(theme *theme.Theme) LayoutInterface {
|
||||
return &Layout{
|
||||
mainContent: tview.NewGrid(),
|
||||
header: components.NewHeader(theme),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue