detail_view.go
1 package tui 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/charmbracelet/lipgloss" 9 tea "github.com/charmbracelet/bubbletea" 10 ) 11 12 func (m *model) updateDetailView(msg tea.Msg) (tea.Model, tea.Cmd) { 13 switch msg := msg.(type) { 14 case tea.KeyMsg: 15 switch msg.String() { 16 case "q", "esc": 17 m.view = m.previousView 18 m.previousView = DetailView 19 return m, nil 20 case " ": 21 if m.selected >= 0 && m.selected < len(m.filtered) { 22 entity := m.filtered[m.selected] 23 domain := entity.GetDomain() 24 if domain == "light" || domain == "switch" || domain == "input_boolean" || domain == "script" || domain == "automation" || domain == "scene" { 25 service := "turn_on" 26 if domain == "automation" { 27 service = "trigger" 28 } 29 if domain == "script" { 30 service = entity.State 31 if entity.State == "on" { 32 service = "turn_off" 33 } 34 } 35 if entity.IsOn() && (domain == "light" || domain == "switch" || domain == "input_boolean") { 36 service = "turn_off" 37 } 38 m.haClient.CallService(domain, service, map[string]interface{}{ 39 "entity_id": entity.EntityID, 40 }) 41 } 42 } 43 44 case "f", "F": 45 if m.selected >= 0 && m.selected < len(m.filtered) { 46 entityID := m.filtered[m.selected].EntityID 47 if m.favorites[entityID] { 48 delete(m.favorites, entityID) 49 } else { 50 m.favorites[entityID] = true 51 } 52 m.saveFavorites() 53 return m, m.refreshEntities() 54 } 55 } 56 } 57 return m, nil 58 } 59 60 func (m *model) viewDetailView() string { 61 if m.selected < 0 || m.selected >= len(m.filtered) { 62 return "No entity selected" 63 } 64 65 entity := m.filtered[m.selected] 66 width := m.width - 4 67 68 content := strings.Builder{} 69 70 content.WriteString(titleStyle.Render("Entity Details\n\n")) 71 72 plainLabel := baseStyle.Foreground(darkBlue) 73 content.WriteString(fmt.Sprintf("%s: %s\n\n", plainLabel.Render("Name"), entity.GetName())) 74 content.WriteString(fmt.Sprintf("%s: %s\n\n", plainLabel.Render("Entity ID"), entity.EntityID)) 75 content.WriteString(fmt.Sprintf("%s: %s\n\n", plainLabel.Render("Domain"), entity.GetDomain())) 76 77 state := entity.State 78 if entity.IsOn() { 79 state = statusOnStyle.Render(state) 80 } else { 81 state = statusOffStyle.Render(state) 82 } 83 content.WriteString(fmt.Sprintf("%s: %s\n\n", plainLabel.Render("State"), state)) 84 85 if len(entity.Attributes) > 0 { 86 content.WriteString(titleStyle.Render("Attributes\n\n")) 87 keys := make([]string, 0, len(entity.Attributes)) 88 for k := range entity.Attributes { 89 if k != "friendly_name" && k != "icon" { 90 keys = append(keys, k) 91 } 92 } 93 94 sort.Strings(keys) 95 96 maxKeyLen := 0 97 for _, key := range keys { 98 if len(key) > maxKeyLen { 99 maxKeyLen = len(key) 100 } 101 } 102 103 for _, key := range keys { 104 value := fmt.Sprintf("%v", entity.Attributes[key]) 105 valueStr := value 106 if len(valueStr) > width-maxKeyLen-4 { 107 valueStr = valueStr[:width-maxKeyLen-7] + "..." 108 } 109 keyLabel := plainLabel.Width(maxKeyLen) 110 content.WriteString(fmt.Sprintf("%s: %s\n", keyLabel.Render(key), valueStr)) 111 } 112 } 113 114 content.WriteString("\n\n") 115 content.WriteString(helpStyle.Render("Press [space] toggle | [F] favorite | [q/esc] go back")) 116 117 contentLines := strings.Split(content.String(), "\n") 118 contentHeight := len(contentLines) + 2 119 120 availableHeight := m.height - 4 121 displayHeight := min(contentHeight, availableHeight) 122 123 border := lipgloss.NewStyle(). 124 Border(lipgloss.RoundedBorder()). 125 BorderForeground(blue). 126 Padding(1). 127 Width(min(width, 80)). 128 Height(displayHeight) 129 130 return border.Render(content.String()) 131 } 132 133 func min(a, b int) int { 134 if a < b { 135 return a 136 } 137 return b 138 }