Files
go2tv/internal/gui/main_mobile.go
2023-05-01 19:48:14 +03:00

298 lines
6.6 KiB
Go

//go:build android || ios
// +build android ios
package gui
import (
"errors"
"net/url"
"sort"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/alexballas/go2tv/devices"
"github.com/alexballas/go2tv/soapcalls"
"github.com/alexballas/go2tv/soapcalls/utils"
)
func mainWindow(s *NewScreen) fyne.CanvasObject {
w := s.Current
list := new(widget.List)
data := make([]devType, 0)
w.Canvas().SetOnTypedKey(func(k *fyne.KeyEvent) {
if k.Name == "Space" || k.Name == "P" {
currentState := s.getScreenState()
switch currentState {
case "Playing":
go pauseAction(s)
case "Paused":
go playAction(s)
}
}
if k.Name == "S" {
go stopAction(s)
}
})
go func() {
datanew, err := getDevices(1)
data = datanew
if err != nil {
data = nil
}
list.Refresh()
}()
mfiletext := widget.NewEntry()
sfiletext := widget.NewEntry()
mfile := widget.NewButton("Select Media File", func() {
go mediaAction(s)
})
mfiletext.Disable()
sfile := widget.NewButton("Select Subtitles File", func() {
go subsAction(s)
})
sfiletext.Disable()
playpause := widget.NewButtonWithIcon("Play", theme.MediaPlayIcon(), func() {
go playAction(s)
})
stop := widget.NewButtonWithIcon("Stop", theme.MediaStopIcon(), func() {
go stopAction(s)
})
volumeup := widget.NewButtonWithIcon("", theme.ContentAddIcon(), func() {
go volumeAction(s, true)
})
muteunmute := widget.NewButtonWithIcon("", theme.VolumeMuteIcon(), func() {
go muteAction(s)
})
volumedown := widget.NewButtonWithIcon("", theme.ContentRemoveIcon(), func() {
go volumeAction(s, false)
})
clearmedia := widget.NewButtonWithIcon("", theme.CancelIcon(), func() {
go clearmediaAction(s)
})
clearsubs := widget.NewButtonWithIcon("", theme.CancelIcon(), func() {
go clearsubsAction(s)
})
externalmedia := widget.NewCheck("Media from URL", func(b bool) {})
medialoop := widget.NewCheck("Loop Selected", func(b bool) {})
mediafilelabel := canvas.NewText("File:", nil)
subsfilelabel := canvas.NewText("Subtitles:", nil)
devicelabel := canvas.NewText("Select Device:", nil)
list = widget.NewList(
func() int {
return len(data)
},
func() fyne.CanvasObject {
return container.NewHBox(widget.NewIcon(theme.NavigateNextIcon()), widget.NewLabel("Template Object"))
},
func(i widget.ListItemID, o fyne.CanvasObject) {
o.(*fyne.Container).Objects[1].(*widget.Label).SetText(data[i].name)
})
s.PlayPause = playpause
s.Stop = stop
s.MuteUnmute = muteunmute
s.ExternalMediaURL = externalmedia
s.MediaText = mfiletext
s.SubsText = sfiletext
s.DeviceList = list
actionbuttons := container.New(&mainButtonsLayout{buttonHeight: 1.5, buttonPadding: theme.Padding()},
playpause,
volumedown,
muteunmute,
volumeup,
stop)
checklists := container.NewHBox(externalmedia, medialoop)
mediasubsbuttons := container.New(layout.NewGridLayout(2), mfile, sfile)
sfiletextArea := container.New(layout.NewBorderLayout(nil, nil, nil, clearsubs), clearsubs, sfiletext)
mfiletextArea := container.New(layout.NewBorderLayout(nil, nil, nil, clearmedia), clearmedia, mfiletext)
viewfilescont := container.New(layout.NewFormLayout(), mediafilelabel, mfiletextArea, subsfilelabel, sfiletextArea)
buttons := container.NewVBox(mediasubsbuttons, viewfilescont, checklists, actionbuttons, container.NewPadded(devicelabel))
content := container.New(layout.NewBorderLayout(buttons, nil, nil, nil), buttons, list)
// Widgets actions
list.OnSelected = func(id widget.ListItemID) {
playpause.Enable()
t, err := soapcalls.DMRextractor(data[id].addr)
check(w, err)
if err == nil {
s.selectedDevice = data[id]
s.controlURL = t.AvtransportControlURL
s.eventlURL = t.AvtransportEventSubURL
s.renderingControlURL = t.RenderingControlURL
s.connectionManagerURL = t.ConnectionManagerURL
if s.tvdata != nil {
s.tvdata.RenderingControlURL = s.renderingControlURL
}
}
}
var mediafileOld fyne.URI
var mediafileOldText string
externalmedia.OnChanged = func(b bool) {
if b {
mfile.Disable()
// rename the label
mediafilelabel.Text = "URL:"
mediafilelabel.Refresh()
// keep old values
mediafileOld = s.mediafile
mediafileOldText = s.MediaText.Text
// Clear the Media Text Area
clearmediaAction(s)
// Set some Media text defaults
// to indicate that we're expecting a URL
mfiletext.SetPlaceHolder("Enter URL here")
mfiletext.Enable()
return
}
medialoop.Enable()
mfile.Enable()
mediafilelabel.Text = "File:"
mfiletext.SetPlaceHolder("")
s.MediaText.Text = mediafileOldText
s.mediafile = mediafileOld
mediafilelabel.Refresh()
mfiletext.Disable()
}
medialoop.OnChanged = func(b bool) {
s.Medialoop = b
}
// Device list auto-refresh
go refreshDevList(s, &data)
// Check mute status for selected device
go checkMutefunc(s)
return content
}
func refreshDevList(s *NewScreen, data *[]devType) {
refreshDevices := time.NewTicker(5 * time.Second)
w := s.Current
_, err := getDevices(2)
if err != nil && !errors.Is(err, devices.ErrNoDeviceAvailable) {
check(w, err)
}
for range refreshDevices.C {
datanew, _ := getDevices(2)
// check to see if the new refresh includes
// one of the already selected devices
var includes bool
u, _ := url.Parse(s.controlURL)
for _, d := range datanew {
n, _ := url.Parse(d.addr)
if n.Host == u.Host {
includes = true
}
}
*data = datanew
if !includes {
if utils.HostPortIsAlive(u.Host) {
*data = append(*data, s.selectedDevice)
sort.Slice(*data, func(i, j int) bool {
return (*data)[i].name < (*data)[j].name
})
} else {
s.controlURL = ""
s.DeviceList.UnselectAll()
}
}
var found bool
for n, a := range *data {
if s.selectedDevice.addr == a.addr {
found = true
s.DeviceList.Select(n)
}
}
if !found {
s.DeviceList.UnselectAll()
}
s.DeviceList.Refresh()
}
}
func checkMutefunc(s *NewScreen) {
checkMute := time.NewTicker(1 * time.Second)
var checkMuteCounter int
for range checkMute.C {
// Stop trying after 5 failures
// to get the mute status
if checkMuteCounter == 5 {
s.renderingControlURL = ""
checkMuteCounter = 0
}
if s.renderingControlURL == "" {
continue
}
if s.tvdata == nil {
s.tvdata = &soapcalls.TVPayload{RenderingControlURL: s.renderingControlURL}
}
isMuted, err := s.tvdata.GetMuteSoapCall()
if err != nil {
checkMuteCounter++
continue
}
checkMuteCounter = 0
switch isMuted {
case "1":
setMuteUnmuteView("Unmute", s)
case "0":
setMuteUnmuteView("Mute", s)
}
}
}