Add multidevice support to eventcapture, complete bubbletea UI for tapRec example

This commit is contained in:
2022-08-03 18:29:19 -07:00
parent 08c76ed2c8
commit ed8cf8cb95
5 changed files with 239 additions and 63 deletions

View File

@@ -6,22 +6,38 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"os"
"os/signal"
"syscall"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/taigrr/adb"
)
var (
command string
file string
chosen adb.Serial
titleStyle = lipgloss.NewStyle().MarginLeft(2)
itemStyle = lipgloss.NewStyle().PaddingLeft(4)
selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
)
func main() {
flag.StringVar(&command, "command", "rec", "rec or play")
flag.StringVar(&file, "file", "taps.json", "Name of the file to save taps to or to play from")
flag.Parse()
if command != "play" && command != "rec" {
flag.PrintDefaults()
os.Exit(1)
}
sigChan := make(chan os.Signal)
ctx, cancel := context.WithCancel(context.Background())
go func() {
@@ -34,16 +50,20 @@ func main() {
fmt.Printf("Error enumerating devices: %v\n", err)
return
}
devNames := []adb.Serial{}
for _, dev := range devs {
devNames = append(devNames, dev.SerialNo)
}
selected := chooseDev(devNames)
for _, dev := range devs {
if dev.SerialNo != selected {
continue
}
if !dev.IsAuthorized {
fmt.Printf("Dev `%s` is not authorized, authorize it to continue.\n", dev.SerialNo)
continue
}
//w, h, err := dev.GetScreenResolution(ctx)
//if err != nil {
// // handle error here
// fmt.Printf("Error: %v\n", err)
//}
switch command {
case "rec":
fmt.Println("Recording taps now. Hit ctrl+c to stop.")
@@ -68,55 +88,114 @@ func main() {
return
}
defer f.Close()
var j map[string]interface{}
var t adb.TapSequence
var b bytes.Buffer
b.ReadFrom(f)
err = json.Unmarshal(b.Bytes(), &j)
t, err := adb.TapSequenceFromJSON(b.Bytes())
if err != nil {
fmt.Printf("Error parsing tap file %s: %v", file, err)
return
}
if events, ok := j["Events"]; ok {
if sliceEvent, ok := events.([]interface{}); ok {
for _, e := range sliceEvent {
if mapEvent, ok := e.(map[string]interface{}); ok {
if eventType, ok := mapEvent["Type"]; ok {
if et, ok := eventType.(float64); ok {
switch int(et) {
case int(adb.SeqSleep):
t.Events = append(t.Events, adb.SequenceSleep{})
case int(adb.SeqSwipe):
t.Events = append(t.Events, adb.SequenceSwipe{})
case int(adb.SeqTap):
t.Events = append(t.Events, adb.SequenceTap{})
}
} else {
fmt.Printf("Could not parse %v (%T) into JSON! 1\n", eventType, eventType)
}
} else {
fmt.Println("Could not parse JSON! 2")
}
} else {
fmt.Println("Could not parse JSON! 3")
}
}
} else {
fmt.Println("Could not parse JSON! 4")
}
} else {
fmt.Println("Could not parse JSON! 5")
}
dev.ReplayTapSequence(ctx, t)
err = json.Unmarshal(b.Bytes(), &t)
if err != nil {
fmt.Printf("struct: %v\n",t)
fmt.Printf("bytes: %v\n",b.String())
fmt.Printf("Error parsing tap file %s: %v", file, err)
return
}
default:
}
}
}
func NewModel(devs []adb.Serial) Model {
var m Model
items := []list.Item{}
for _, d := range devs {
items = append(items, DevEntry(d))
}
m.List = list.New(items, itemDelegate{}, 0, len(devs)+15)
return m
}
func chooseDev(devs []adb.Serial) adb.Serial {
if len(devs) == 0 {
return ""
}
if len(devs) == 1 {
return devs[0]
}
m := NewModel(devs)
m.List.Title = "Which device?"
m.List.SetShowStatusBar(false)
m.List.SetFilteringEnabled(false)
m.List.Styles.Title = titleStyle
m.List.Styles.PaginationStyle = paginationStyle
m.List.Styles.HelpStyle = helpStyle
if err := tea.NewProgram(m).Start(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
return adb.Serial(chosen)
}
type Model struct {
List list.Model
quitting bool
Choice DevEntry
}
type DevEntry adb.Serial
func (d DevEntry) FilterValue() string {
return ""
}
func (m Model) Init() tea.Cmd {
return nil
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.List.SetWidth(msg.Width)
return m, nil
case tea.KeyMsg:
switch keypress := msg.String(); keypress {
case "ctrl+c":
m.quitting = true
return m, tea.Quit
case "enter":
i, ok := m.List.SelectedItem().(DevEntry)
if ok {
chosen = adb.Serial(i)
}
return m, tea.Quit
}
}
var cmd tea.Cmd
m.List, cmd = m.List.Update(msg)
return m, cmd
}
func (m Model) View() string {
if chosen != "" {
return quitTextStyle.Render("Chosen device: " + string(chosen))
}
return "\n" + m.List.View()
}
type itemDelegate struct{}
func (d itemDelegate) Height() int { return 1 }
func (d itemDelegate) Spacing() int { return 0 }
func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
i, ok := listItem.(DevEntry)
if !ok {
return
}
str := fmt.Sprintf("%d. %s", index+1, i)
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
fmt.Fprint(w, fn(str))
}