Add comments to gui

This commit is contained in:
Elara 2021-08-26 08:47:17 -07:00
parent ea63f43638
commit 50f3f244a3
6 changed files with 74 additions and 5 deletions

View File

@ -11,20 +11,28 @@ import (
) )
func guiErr(err error, msg string, parent fyne.Window) { func guiErr(err error, msg string, parent fyne.Window) {
// Create new label containing message
msgLbl := widget.NewLabel(msg) msgLbl := widget.NewLabel(msg)
// Text formatting settings
msgLbl.Wrapping = fyne.TextWrapWord msgLbl.Wrapping = fyne.TextWrapWord
msgLbl.Alignment = fyne.TextAlignCenter msgLbl.Alignment = fyne.TextAlignCenter
// Create new rectangle to set the size of the dialog
rect := canvas.NewRectangle(color.Transparent) rect := canvas.NewRectangle(color.Transparent)
// Set minimum size of rectangle to 350x0
rect.SetMinSize(fyne.NewSize(350, 0)) rect.SetMinSize(fyne.NewSize(350, 0))
// Create new container containing message and rectangle
content := container.NewVBox( content := container.NewVBox(
msgLbl, msgLbl,
rect, rect,
) )
if err != nil { if err != nil {
// Create new label containing error text
errLbl := widget.NewLabel(err.Error()) errLbl := widget.NewLabel(err.Error())
// Create new dropdown containing error label
content.Add(widget.NewAccordion( content.Add(widget.NewAccordion(
widget.NewAccordionItem("More Details", errLbl), widget.NewAccordionItem("More Details", errLbl),
)) ))
} }
// Show error dialog
dialog.NewCustom("Error", "Ok", content, parent).Show() dialog.NewCustom("Error", "Ok", content, parent).Show()
} }

View File

@ -22,7 +22,9 @@ func infoTab(parent fyne.Window) *fyne.Container {
canvas.NewRectangle(color.Transparent), canvas.NewRectangle(color.Transparent),
) )
// Create label for heart rate
heartRateLbl := newText("0 BPM", 24) heartRateLbl := newText("0 BPM", 24)
// Creae container to store heart rate section
heartRate := container.NewVBox( heartRate := container.NewVBox(
newText("Heart Rate", 12), newText("Heart Rate", 12),
heartRateLbl, heartRateLbl,
@ -30,12 +32,17 @@ func infoTab(parent fyne.Window) *fyne.Container {
) )
infoLayout.Add(heartRate) infoLayout.Add(heartRate)
// Watch for heart rate updates
go watch(types.ReqTypeWatchHeartRate, func(data interface{}) { go watch(types.ReqTypeWatchHeartRate, func(data interface{}) {
// Change text of heart rate label
heartRateLbl.Text = fmt.Sprintf("%d BPM", int(data.(float64))) heartRateLbl.Text = fmt.Sprintf("%d BPM", int(data.(float64)))
// Refresh label
heartRateLbl.Refresh() heartRateLbl.Refresh()
}, parent) }, parent)
// Create label for battery level
battLevelLbl := newText("0%", 24) battLevelLbl := newText("0%", 24)
// Create container to store battery level section
battLevel := container.NewVBox( battLevel := container.NewVBox(
newText("Battery Level", 12), newText("Battery Level", 12),
battLevelLbl, battLevelLbl,
@ -43,6 +50,7 @@ func infoTab(parent fyne.Window) *fyne.Container {
) )
infoLayout.Add(battLevel) infoLayout.Add(battLevel)
// Watch for changes in battery level
go watch(types.ReqTypeWatchBattLevel, func(data interface{}) { go watch(types.ReqTypeWatchBattLevel, func(data interface{}) {
battLevelLbl.Text = fmt.Sprintf("%d%%", int(data.(float64))) battLevelLbl.Text = fmt.Sprintf("%d%%", int(data.(float64)))
battLevelLbl.Refresh() battLevelLbl.Refresh()

View File

@ -8,9 +8,12 @@ import (
var SockPath = "/tmp/itd/socket" var SockPath = "/tmp/itd/socket"
func main() { func main() {
// Create new app
a := app.New() a := app.New()
// Create new window with title "itgui"
window := a.NewWindow("itgui") window := a.NewWindow("itgui")
// Create new app tabs container
tabs := container.NewAppTabs( tabs := container.NewAppTabs(
container.NewTabItem("Info", infoTab(window)), container.NewTabItem("Info", infoTab(window)),
container.NewTabItem("Notify", notifyTab(window)), container.NewTabItem("Notify", notifyTab(window)),
@ -18,6 +21,8 @@ func main() {
container.NewTabItem("Upgrade", upgradeTab(window)), container.NewTabItem("Upgrade", upgradeTab(window)),
) )
// Set tabs as window content
window.SetContent(tabs) window.SetContent(tabs)
// Show window and run app
window.ShowAndRun() window.ShowAndRun()
} }

View File

@ -12,18 +12,23 @@ import (
) )
func notifyTab(parent fyne.Window) *fyne.Container { func notifyTab(parent fyne.Window) *fyne.Container {
// Create new entry for notification title
titleEntry := widget.NewEntry() titleEntry := widget.NewEntry()
titleEntry.SetPlaceHolder("Title") titleEntry.SetPlaceHolder("Title")
// Create multiline entry for notification body
bodyEntry := widget.NewMultiLineEntry() bodyEntry := widget.NewMultiLineEntry()
bodyEntry.SetPlaceHolder("Body") bodyEntry.SetPlaceHolder("Body")
// Create new button to send notification
sendBtn := widget.NewButton("Send", func() { sendBtn := widget.NewButton("Send", func() {
// Dial itd UNIX socket
conn, err := net.Dial("unix", SockPath) conn, err := net.Dial("unix", SockPath)
if err != nil { if err != nil {
guiErr(err, "Error dialing socket", parent) guiErr(err, "Error dialing socket", parent)
return return
} }
// Encode notify request on connection
json.NewEncoder(conn).Encode(types.Request{ json.NewEncoder(conn).Encode(types.Request{
Type: types.ReqTypeNotify, Type: types.ReqTypeNotify,
Data: types.ReqDataNotify{ Data: types.ReqDataNotify{
@ -33,6 +38,7 @@ func notifyTab(parent fyne.Window) *fyne.Container {
}) })
}) })
// Return new container containing all elements
return container.NewVBox( return container.NewVBox(
layout.NewSpacer(), layout.NewSpacer(),
titleEntry, titleEntry,

View File

@ -13,24 +13,30 @@ import (
) )
func timeTab(parent fyne.Window) *fyne.Container { func timeTab(parent fyne.Window) *fyne.Container {
// Create new entry for time string
timeEntry := widget.NewEntry() timeEntry := widget.NewEntry()
// Set text to current time formatter properly
timeEntry.SetText(time.Now().Format(time.RFC1123)) timeEntry.SetText(time.Now().Format(time.RFC1123))
// Create button to set current time
currentBtn := widget.NewButton("Set Current", func() { currentBtn := widget.NewButton("Set Current", func() {
timeEntry.SetText(time.Now().Format(time.RFC1123)) timeEntry.SetText(time.Now().Format(time.RFC1123))
setTime(true) setTime(true)
}) })
// Create button to set time inside entry
timeBtn := widget.NewButton("Set", func() { timeBtn := widget.NewButton("Set", func() {
// Parse time as RFC1123 string
parsedTime, err := time.Parse(time.RFC1123, timeEntry.Text) parsedTime, err := time.Parse(time.RFC1123, timeEntry.Text)
if err != nil { if err != nil {
guiErr(err, "Error parsing time string", parent) guiErr(err, "Error parsing time string", parent)
return return
} }
// Set time to parsed time
setTime(false, parsedTime) setTime(false, parsedTime)
}) })
// Return new container with all elements centered
return container.NewVBox( return container.NewVBox(
layout.NewSpacer(), layout.NewSpacer(),
timeEntry, timeEntry,
@ -43,17 +49,25 @@ func timeTab(parent fyne.Window) *fyne.Container {
// setTime sets the first element in the variadic parameter // setTime sets the first element in the variadic parameter
// if current is false, otherwise, it sets the current time. // if current is false, otherwise, it sets the current time.
func setTime(current bool, t ...time.Time) error { func setTime(current bool, t ...time.Time) error {
// Dial UNIX socket
conn, err := net.Dial("unix", SockPath) conn, err := net.Dial("unix", SockPath)
if err != nil { if err != nil {
return err return err
} }
defer conn.Close()
var data string var data string
// If current is true, use the string "now"
// otherwise, use the formatted time from the
// first element in the variadic parameter.
// "now" is more accurate than formatting
// current time as only seconds are preserved
// in that case.
if current { if current {
data = "now" data = "now"
} else { } else {
data = t[0].Format(time.RFC3339) data = t[0].Format(time.RFC3339)
} }
defer conn.Close() // Encode SetTime request with above data
err = json.NewEncoder(conn).Encode(types.Request{ err = json.NewEncoder(conn).Encode(types.Request{
Type: types.ReqTypeSetTime, Type: types.ReqTypeSetTime,
Data: data, Data: data,

View File

@ -23,6 +23,7 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
initPktPath string initPktPath string
) )
// Create archive selection dialog
archiveDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) { archiveDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
if e != nil || uc == nil { if e != nil || uc == nil {
return return
@ -30,9 +31,12 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
uc.Close() uc.Close()
archivePath = uc.URI().Path() archivePath = uc.URI().Path()
}, parent) }, parent)
// Limit dialog to .zip files
archiveDialog.SetFilter(storage.NewExtensionFileFilter([]string{".zip"})) archiveDialog.SetFilter(storage.NewExtensionFileFilter([]string{".zip"}))
// Create button to show dialog
archiveBtn := widget.NewButton("Select archive (.zip)", archiveDialog.Show) archiveBtn := widget.NewButton("Select archive (.zip)", archiveDialog.Show)
// Create firmware selection dialog
firmwareDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) { firmwareDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
if e != nil || uc == nil { if e != nil || uc == nil {
return return
@ -40,9 +44,12 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
uc.Close() uc.Close()
fiwmarePath = uc.URI().Path() fiwmarePath = uc.URI().Path()
}, parent) }, parent)
// Limit dialog to .bin files
firmwareDialog.SetFilter(storage.NewExtensionFileFilter([]string{".bin"})) firmwareDialog.SetFilter(storage.NewExtensionFileFilter([]string{".bin"}))
// Create button to show dialog
firmwareBtn := widget.NewButton("Select init packet (.bin)", firmwareDialog.Show) firmwareBtn := widget.NewButton("Select init packet (.bin)", firmwareDialog.Show)
// Create init packet selection dialog
initPktDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) { initPktDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
if e != nil || uc == nil { if e != nil || uc == nil {
return return
@ -50,19 +57,25 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
uc.Close() uc.Close()
initPktPath = uc.URI().Path() initPktPath = uc.URI().Path()
}, parent) }, parent)
// Limit dialog to .dat files
initPktDialog.SetFilter(storage.NewExtensionFileFilter([]string{".dat"})) initPktDialog.SetFilter(storage.NewExtensionFileFilter([]string{".dat"}))
// Create button to show dialog
initPktBtn := widget.NewButton("Select init packet (.dat)", initPktDialog.Show) initPktBtn := widget.NewButton("Select init packet (.dat)", initPktDialog.Show)
// Hide init packet and firmware buttons
initPktBtn.Hide() initPktBtn.Hide()
firmwareBtn.Hide() firmwareBtn.Hide()
// Create dropdown to select upgrade type
upgradeTypeSelect := widget.NewSelect([]string{ upgradeTypeSelect := widget.NewSelect([]string{
"Archive", "Archive",
"Files", "Files",
}, func(s string) { }, func(s string) {
// Hide all buttons
archiveBtn.Hide() archiveBtn.Hide()
initPktBtn.Hide() initPktBtn.Hide()
firmwareBtn.Hide() firmwareBtn.Hide()
// Unhide appropriate button(s)
switch s { switch s {
case "Archive": case "Archive":
archiveBtn.Show() archiveBtn.Show()
@ -71,26 +84,35 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
firmwareBtn.Show() firmwareBtn.Show()
} }
}) })
// Select first elemetn
upgradeTypeSelect.SetSelectedIndex(0) upgradeTypeSelect.SetSelectedIndex(0)
// Create new button to start DFU
startBtn := widget.NewButton("Start", func() { startBtn := widget.NewButton("Start", func() {
// If archive path does not exist and both init packet and firmware paths
// also do not exist, return error
if archivePath == "" && (initPktPath == "" && fiwmarePath == "") { if archivePath == "" && (initPktPath == "" && fiwmarePath == "") {
guiErr(nil, "Upgrade requires archive or files selected", parent) guiErr(nil, "Upgrade requires archive or files selected", parent)
return return
} }
// Create new label for byte progress
progressLbl := widget.NewLabelWithStyle("0 / 0 B", fyne.TextAlignCenter, fyne.TextStyle{}) progressLbl := widget.NewLabelWithStyle("0 / 0 B", fyne.TextAlignCenter, fyne.TextStyle{})
// Create new progress bar
progressBar := widget.NewProgressBar() progressBar := widget.NewProgressBar()
// Create modal dialog containing label and progress bar
progressDlg := widget.NewModalPopUp(container.NewVBox( progressDlg := widget.NewModalPopUp(container.NewVBox(
layout.NewSpacer(), layout.NewSpacer(),
progressLbl, progressLbl,
progressBar, progressBar,
layout.NewSpacer(), layout.NewSpacer(),
), parent.Canvas()) ), parent.Canvas())
// Resize modal to 300x100
progressDlg.Resize(fyne.NewSize(300, 100)) progressDlg.Resize(fyne.NewSize(300, 100))
var fwUpgType int var fwUpgType int
var files []string var files []string
// Get appropriate upgrade type and file paths
switch upgradeTypeSelect.Selected { switch upgradeTypeSelect.Selected {
case "Archive": case "Archive":
fwUpgType = types.UpgradeTypeArchive fwUpgType = types.UpgradeTypeArchive
@ -100,6 +122,7 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
files = append(files, initPktPath, fiwmarePath) files = append(files, initPktPath, fiwmarePath)
} }
// Dial itd UNIX socket
conn, err := net.Dial("unix", SockPath) conn, err := net.Dial("unix", SockPath)
if err != nil { if err != nil {
guiErr(err, "Error dialing socket", parent) guiErr(err, "Error dialing socket", parent)
@ -107,6 +130,7 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
} }
defer conn.Close() defer conn.Close()
// Encode firmware upgrade request to connection
json.NewEncoder(conn).Encode(types.Request{ json.NewEncoder(conn).Encode(types.Request{
Type: types.ReqTypeFwUpgrade, Type: types.ReqTypeFwUpgrade,
Data: types.ReqDataFwUpgrade{ Data: types.ReqDataFwUpgrade{
@ -115,7 +139,10 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
}, },
}) })
// Show progress dialog
progressDlg.Show() progressDlg.Show()
// Hide progress dialog after completion
defer progressDlg.Hide()
scanner := bufio.NewScanner(conn) scanner := bufio.NewScanner(conn)
for scanner.Scan() { for scanner.Scan() {
@ -141,16 +168,17 @@ func upgradeTab(parent fyne.Window) *fyne.Container {
if event.Received == event.Total { if event.Received == event.Total {
break break
} }
// Set label text to received / total B
progressLbl.SetText(fmt.Sprintf("%d / %d B", event.Received, event.Total)) progressLbl.SetText(fmt.Sprintf("%d / %d B", event.Received, event.Total))
// Set progress bar values
progressBar.Max = float64(event.Total) progressBar.Max = float64(event.Total)
progressBar.Value = float64(event.Received) progressBar.Value = float64(event.Received)
// Refresh progress bar
progressBar.Refresh() progressBar.Refresh()
} }
conn.Close()
progressDlg.Hide()
}) })
// Return container containing all elements
return container.NewVBox( return container.NewVBox(
layout.NewSpacer(), layout.NewSpacer(),
upgradeTypeSelect, upgradeTypeSelect,