mirror of
https://github.com/taigrr/adb.git
synced 2026-04-02 02:58:42 -07:00
Add multidevice support to eventcapture, complete bubbletea UI for tapRec example
This commit is contained in:
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user