Refactor: uistate -> context

pull/71/head
lawl 4 years ago
parent be9849b748
commit 6238c208e5

@ -73,9 +73,9 @@ func main() {
rnnoisefile := dumpLib() rnnoisefile := dumpLib()
defer removeLib(rnnoisefile) defer removeLib(rnnoisefile)
ui := uistate{} ctx := ntcontext{}
ui.config = readConfig() ctx.config = readConfig()
ui.librnnoise = rnnoisefile ctx.librnnoise = rnnoisefile
paClient, err := pulseaudio.NewClient() paClient, err := pulseaudio.NewClient()
if err != nil { if err != nil {
@ -95,9 +95,9 @@ func main() {
if threshold > 0 { if threshold > 0 {
if threshold > 95 { if threshold > 95 {
fmt.Fprintf(os.Stderr, "Threshold of '%d' too high, setting to maximum of 95.\n", threshold) fmt.Fprintf(os.Stderr, "Threshold of '%d' too high, setting to maximum of 95.\n", threshold)
ui.config.Threshold = 95 ctx.config.Threshold = 95
} else { } else {
ui.config.Threshold = threshold ctx.config.Threshold = threshold
} }
} }
@ -120,7 +120,7 @@ func main() {
sources := getSources(paClient) sources := getSources(paClient)
for i := range sources { for i := range sources {
if sources[i].ID == sourceName { if sources[i].ID == sourceName {
loadSupressor(paClient, sources[i], &ui) loadSupressor(&ctx, sources[i])
os.Exit(0) os.Exit(0)
} }
} }
@ -130,16 +130,16 @@ func main() {
} }
if ui.config.EnableUpdates { if ctx.config.EnableUpdates {
go updateCheck(&ui) go updateCheck(&ctx)
} }
go paConnectionWatchdog(&ui) go paConnectionWatchdog(&ctx)
wnd := nucular.NewMasterWindowSize(0, "NoiseTorch", image.Point{550, 300}, func(w *nucular.Window) { wnd := nucular.NewMasterWindowSize(0, "NoiseTorch", image.Point{550, 300}, func(w *nucular.Window) {
updatefn(w, &ui) updatefn(&ctx, w)
}) })
ui.masterWindow = &wnd ctx.masterWindow = &wnd
style := style.FromTheme(style.DarkTheme, 2.0) style := style.FromTheme(style.DarkTheme, 2.0)
style.Font = font.DefaultFont(16, 1) style.Font = font.DefaultFont(16, 1)
wnd.SetStyle(style) wnd.SetStyle(style)
@ -194,9 +194,9 @@ func getSources(client *pulseaudio.Client) []input {
return inputs return inputs
} }
func paConnectionWatchdog(ui *uistate) { func paConnectionWatchdog(ctx *ntcontext) {
for { for {
if ui.paClient.Connected() { if ctx.paClient.Connected() {
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
continue continue
} }
@ -207,12 +207,12 @@ func paConnectionWatchdog(ui *uistate) {
fmt.Fprintf(os.Stderr, "Couldn't create pulseaudio client: %v\n", err) fmt.Fprintf(os.Stderr, "Couldn't create pulseaudio client: %v\n", err)
} }
ui.paClient = paClient ctx.paClient = paClient
go updateNoiseSupressorLoaded(paClient, &ui.noiseSupressorState) go updateNoiseSupressorLoaded(paClient, &ctx.noiseSupressorState)
ui.inputList = getSources(paClient) ctx.inputList = getSources(paClient)
resetUI(ui) resetUI(ctx)
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
} }

@ -63,7 +63,8 @@ func supressorState(c *pulseaudio.Client) int {
return unloaded return unloaded
} }
func loadSupressor(c *pulseaudio.Client, inp input, ui *uistate) error { func loadSupressor(ctx *ntcontext, inp input) error {
c := ctx.paClient
log.Printf("Querying pulse rlimit\n") log.Printf("Querying pulse rlimit\n")
@ -98,7 +99,7 @@ func loadSupressor(c *pulseaudio.Client, inp input, ui *uistate) error {
idx, err = c.LoadModule("module-ladspa-sink", idx, err = c.LoadModule("module-ladspa-sink",
fmt.Sprintf("sink_name=nui_mic_raw_in sink_master=nui_mic_denoised_out "+ fmt.Sprintf("sink_name=nui_mic_raw_in sink_master=nui_mic_denoised_out "+
"label=noise_suppressor_mono plugin=%s control=%d", ui.librnnoise, ui.config.Threshold)) "label=noise_suppressor_mono plugin=%s control=%d", ctx.librnnoise, ctx.config.Threshold))
if err != nil { if err != nil {
return err return err
} }

130
ui.go

@ -12,7 +12,7 @@ import (
"github.com/lawl/pulseaudio" "github.com/lawl/pulseaudio"
) )
type uistate struct { type ntcontext struct {
inputList []input inputList []input
noiseSupressorState int noiseSupressorState int
paClient *pulseaudio.Client paClient *pulseaudio.Client
@ -33,25 +33,25 @@ var green = color.RGBA{34, 187, 69, 255}
var red = color.RGBA{255, 70, 70, 255} var red = color.RGBA{255, 70, 70, 255}
var orange = color.RGBA{255, 140, 0, 255} var orange = color.RGBA{255, 140, 0, 255}
func updatefn(w *nucular.Window, ui *uistate) { func updatefn(ctx *ntcontext, w *nucular.Window) {
if !ui.paClient.Connected() { if !ctx.paClient.Connected() {
connectScreen(w, ui) connectScreen(ctx, w)
return return
} }
if ui.loadingScreen { if ctx.loadingScreen {
loadingScreen(w, ui) loadingScreen(ctx, w)
return return
} }
if ui.licenseScreen { if ctx.licenseScreen {
licenseScreen(w, ui) licenseScreen(ctx, w)
return return
} }
if ui.versionScreen { if ctx.versionScreen {
versionScreen(w, ui) versionScreen(ctx, w)
return return
} }
@ -61,48 +61,48 @@ func updatefn(w *nucular.Window, ui *uistate) {
if w := w.Menu(label.TA("About", "LC"), 120, nil); w != nil { if w := w.Menu(label.TA("About", "LC"), 120, nil); w != nil {
w.Row(10).Dynamic(1) w.Row(10).Dynamic(1)
if w.MenuItem(label.T("Licenses")) { if w.MenuItem(label.T("Licenses")) {
ui.licenseScreen = true ctx.licenseScreen = true
} }
w.Row(10).Dynamic(1) w.Row(10).Dynamic(1)
if w.MenuItem(label.T("Source code")) { if w.MenuItem(label.T("Source code")) {
exec.Command("xdg-open", "https://github.com/lawl/NoiseTorch").Run() exec.Command("xdg-open", "https://github.com/lawl/NoiseTorch").Run()
} }
if w.MenuItem(label.T("Version")) { if w.MenuItem(label.T("Version")) {
ui.versionScreen = true ctx.versionScreen = true
} }
} }
w.MenubarEnd() w.MenubarEnd()
w.Row(15).Dynamic(1) w.Row(15).Dynamic(1)
if ui.noiseSupressorState == loaded { if ctx.noiseSupressorState == loaded {
w.LabelColored("NoiseTorch active", "RC", green) w.LabelColored("NoiseTorch active", "RC", green)
} else if ui.noiseSupressorState == unloaded { } else if ctx.noiseSupressorState == unloaded {
w.LabelColored("NoiseTorch inactive", "RC", red) w.LabelColored("NoiseTorch inactive", "RC", red)
} else if ui.noiseSupressorState == inconsistent { } else if ctx.noiseSupressorState == inconsistent {
w.LabelColored("Inconsistent state, please unload first.", "RC", orange) w.LabelColored("Inconsistent state, please unload first.", "RC", orange)
} }
if ui.update.available && !ui.update.triggered { if ctx.update.available && !ctx.update.triggered {
w.Row(20).Ratio(0.9, 0.1) w.Row(20).Ratio(0.9, 0.1)
w.LabelColored("Update available! Click to install version: "+ui.update.serverVersion, "LC", green) w.LabelColored("Update available! Click to install version: "+ctx.update.serverVersion, "LC", green)
if w.ButtonText("Update") { if w.ButtonText("Update") {
ui.update.triggered = true ctx.update.triggered = true
go update(ui) go update(ctx)
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
} }
} }
if ui.update.triggered { if ctx.update.triggered {
w.Row(20).Dynamic(1) w.Row(20).Dynamic(1)
w.Label(ui.update.updatingText, "CC") w.Label(ctx.update.updatingText, "CC")
} }
if w.TreePush(nucular.TreeTab, "Settings", true) { if w.TreePush(nucular.TreeTab, "Settings", true) {
w.Row(15).Dynamic(2) w.Row(15).Dynamic(2)
if w.CheckboxText("Display Monitor Sources", &ui.config.DisplayMonitorSources) { if w.CheckboxText("Display Monitor Sources", &ctx.config.DisplayMonitorSources) {
ui.sourceListColdWidthIndex++ //recompute the with because of new elements ctx.sourceListColdWidthIndex++ //recompute the with because of new elements
go writeConfig(ui.config) go writeConfig(ctx.config)
} }
w.Spacing(1) w.Spacing(1)
@ -112,13 +112,13 @@ func updatefn(w *nucular.Window, ui *uistate) {
if w.Input().Mouse.HoveringRect(w.LastWidgetBounds) { if w.Input().Mouse.HoveringRect(w.LastWidgetBounds) {
w.Tooltip("If you have a decent microphone, you can usually turn this all the way up.") w.Tooltip("If you have a decent microphone, you can usually turn this all the way up.")
} }
if w.SliderInt(0, &ui.config.Threshold, 95, 1) { if w.SliderInt(0, &ctx.config.Threshold, 95, 1) {
go writeConfig(ui.config) go writeConfig(ctx.config)
ui.reloadRequired = true ctx.reloadRequired = true
} }
w.Label(fmt.Sprintf("%d%%", ui.config.Threshold), "RC") w.Label(fmt.Sprintf("%d%%", ctx.config.Threshold), "RC")
if ui.reloadRequired { if ctx.reloadRequired {
w.Row(20).Dynamic(1) w.Row(20).Dynamic(1)
w.LabelColored("Reloading NoiseTorch is required to apply these changes.", "LC", orange) w.LabelColored("Reloading NoiseTorch is required to apply these changes.", "LC", orange)
} }
@ -129,19 +129,19 @@ func updatefn(w *nucular.Window, ui *uistate) {
w.Row(15).Dynamic(1) w.Row(15).Dynamic(1)
w.Label("Select an input device below:", "LC") w.Label("Select an input device below:", "LC")
for i := range ui.inputList { for i := range ctx.inputList {
el := &ui.inputList[i] el := &ctx.inputList[i]
if el.isMonitor && !ui.config.DisplayMonitorSources { if el.isMonitor && !ctx.config.DisplayMonitorSources {
continue continue
} }
w.Row(15).Static() w.Row(15).Static()
w.LayoutFitWidth(0, 0) w.LayoutFitWidth(0, 0)
if w.CheckboxText("", &el.checked) { if w.CheckboxText("", &el.checked) {
ensureOnlyOneInputSelected(&ui.inputList, el) ensureOnlyOneInputSelected(&ctx.inputList, el)
} }
w.LayoutFitWidth(ui.sourceListColdWidthIndex, 0) w.LayoutFitWidth(ctx.sourceListColdWidthIndex, 0)
if el.dynamicLatency { if el.dynamicLatency {
w.Label(el.Name, "LC") w.Label(el.Name, "LC")
} else { } else {
@ -153,53 +153,53 @@ func updatefn(w *nucular.Window, ui *uistate) {
w.Spacing(1) w.Spacing(1)
w.Row(25).Dynamic(2) w.Row(25).Dynamic(2)
if ui.noiseSupressorState != unloaded { if ctx.noiseSupressorState != unloaded {
if w.ButtonText("Unload NoiseTorch") { if w.ButtonText("Unload NoiseTorch") {
ui.loadingScreen = true ctx.loadingScreen = true
ui.reloadRequired = false ctx.reloadRequired = false
go func() { // don't block the UI thread, just display a working screen so user can't run multiple loads/unloads go func() { // don't block the UI thread, just display a working screen so user can't run multiple loads/unloads
if err := unloadSupressor(ui.paClient); err != nil { if err := unloadSupressor(ctx.paClient); err != nil {
log.Println(err) log.Println(err)
} }
//wait until PA reports it has actually loaded it, timeout at 10s //wait until PA reports it has actually loaded it, timeout at 10s
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
if supressorState(ui.paClient) != unloaded { if supressorState(ctx.paClient) != unloaded {
time.Sleep(time.Millisecond * 500) time.Sleep(time.Millisecond * 500)
} }
} }
ui.loadingScreen = false ctx.loadingScreen = false
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
}() }()
} }
} else { } else {
w.Spacing(1) w.Spacing(1)
} }
txt := "Load NoiseTorch" txt := "Load NoiseTorch"
if ui.noiseSupressorState == loaded { if ctx.noiseSupressorState == loaded {
txt = "Reload NoiseTorch" txt = "Reload NoiseTorch"
} }
if inp, ok := inputSelection(ui); ok && ui.noiseSupressorState != inconsistent { if inp, ok := inputSelection(ctx); ok && ctx.noiseSupressorState != inconsistent {
if w.ButtonText(txt) { if w.ButtonText(txt) {
ui.loadingScreen = true ctx.loadingScreen = true
ui.reloadRequired = false ctx.reloadRequired = false
go func() { // don't block the UI thread, just display a working screen so user can't run multiple loads/unloads go func() { // don't block the UI thread, just display a working screen so user can't run multiple loads/unloads
if ui.noiseSupressorState == loaded { if ctx.noiseSupressorState == loaded {
if err := unloadSupressor(ui.paClient); err != nil { if err := unloadSupressor(ctx.paClient); err != nil {
log.Println(err) log.Println(err)
} }
} }
if err := loadSupressor(ui.paClient, inp, ui); err != nil { if err := loadSupressor(ctx, inp); err != nil {
log.Println(err) log.Println(err)
} }
//wait until PA reports it has actually loaded it, timeout at 10s //wait until PA reports it has actually loaded it, timeout at 10s
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
if supressorState(ui.paClient) != loaded { if supressorState(ctx.paClient) != loaded {
time.Sleep(time.Millisecond * 500) time.Sleep(time.Millisecond * 500)
} }
} }
ui.loadingScreen = false ctx.loadingScreen = false
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
}() }()
} }
} else { } else {
@ -220,8 +220,8 @@ func ensureOnlyOneInputSelected(inps *[]input, current *input) {
current.checked = true current.checked = true
} }
func inputSelection(ui *uistate) (input, bool) { func inputSelection(ctx *ntcontext) (input, bool) {
for _, in := range ui.inputList { for _, in := range ctx.inputList {
if in.checked { if in.checked {
return in, true return in, true
} }
@ -229,16 +229,16 @@ func inputSelection(ui *uistate) (input, bool) {
return input{}, false return input{}, false
} }
func loadingScreen(w *nucular.Window, ui *uistate) { func loadingScreen(ctx *ntcontext, w *nucular.Window) {
w.Row(50).Dynamic(1) w.Row(50).Dynamic(1)
w.Label("Working...", "CB") w.Label("Working...", "CB")
w.Row(50).Dynamic(1) w.Row(50).Dynamic(1)
w.Label("(this may take a few seconds)", "CB") w.Label("(this may take a few seconds)", "CB")
} }
func licenseScreen(w *nucular.Window, ui *uistate) { func licenseScreen(ctx *ntcontext, w *nucular.Window) {
w.Row(255).Dynamic(1) w.Row(255).Dynamic(1)
field := &ui.licenseTextArea field := &ctx.licenseTextArea
field.Flags |= nucular.EditMultiline field.Flags |= nucular.EditMultiline
if len(field.Buffer) < 1 { if len(field.Buffer) < 1 {
field.Buffer = []rune(licenseString) field.Buffer = []rune(licenseString)
@ -248,11 +248,11 @@ func licenseScreen(w *nucular.Window, ui *uistate) {
w.Row(20).Dynamic(2) w.Row(20).Dynamic(2)
w.Spacing(1) w.Spacing(1)
if w.ButtonText("OK") { if w.ButtonText("OK") {
ui.licenseScreen = false ctx.licenseScreen = false
} }
} }
func versionScreen(w *nucular.Window, ui *uistate) { func versionScreen(ctx *ntcontext, w *nucular.Window) {
w.Row(50).Dynamic(1) w.Row(50).Dynamic(1)
w.Label("Version", "CB") w.Label("Version", "CB")
w.Row(50).Dynamic(1) w.Row(50).Dynamic(1)
@ -262,19 +262,19 @@ func versionScreen(w *nucular.Window, ui *uistate) {
w.Row(20).Dynamic(2) w.Row(20).Dynamic(2)
w.Spacing(1) w.Spacing(1)
if w.ButtonText("OK") { if w.ButtonText("OK") {
ui.versionScreen = false ctx.versionScreen = false
} }
} }
func connectScreen(w *nucular.Window, ui *uistate) { func connectScreen(ctx *ntcontext, w *nucular.Window) {
w.Row(50).Dynamic(1) w.Row(50).Dynamic(1)
w.Label("Connecting to pulseaudio...", "CB") w.Label("Connecting to pulseaudio...", "CB")
} }
func resetUI(ui *uistate) { func resetUI(ctx *ntcontext) {
ui.loadingScreen = false ctx.loadingScreen = false
if ui.masterWindow != nil { if ctx.masterWindow != nil {
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
} }
} }

@ -22,7 +22,7 @@ type updateui struct {
updatingText string updatingText string
} }
func updateCheck(ui *uistate) { func updateCheck(ctx *ntcontext) {
log.Println("Checking for updates") log.Println("Checking for updates")
bodybuf, err := fetchFile("version.txt") bodybuf, err := fetchFile("version.txt")
if err != nil { if err != nil {
@ -31,27 +31,27 @@ func updateCheck(ui *uistate) {
} }
body := strings.TrimSpace(string(bodybuf)) body := strings.TrimSpace(string(bodybuf))
ui.update.serverVersion = body ctx.update.serverVersion = body
if ui.update.serverVersion != version { if ctx.update.serverVersion != version {
ui.update.available = true ctx.update.available = true
} }
} }
func update(ui *uistate) { func update(ctx *ntcontext) {
sig, err := fetchFile("NoiseTorch_x64.tgz.sig") sig, err := fetchFile("NoiseTorch_x64.tgz.sig")
if err != nil { if err != nil {
log.Println("Couldn't fetch signature", err) log.Println("Couldn't fetch signature", err)
ui.update.updatingText = "Update failed!" ctx.update.updatingText = "Update failed!"
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
return return
} }
tgz, err := fetchFile("NoiseTorch_x64.tgz") tgz, err := fetchFile("NoiseTorch_x64.tgz")
if err != nil { if err != nil {
log.Println("Couldn't fetch tgz", err) log.Println("Couldn't fetch tgz", err)
ui.update.updatingText = "Update failed!" ctx.update.updatingText = "Update failed!"
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
return return
} }
@ -61,16 +61,16 @@ func update(ui *uistate) {
if !verified { if !verified {
log.Printf("SIGNATURE VERIFICATION FAILED, ABORTING UPDATE!\n") log.Printf("SIGNATURE VERIFICATION FAILED, ABORTING UPDATE!\n")
ui.update.updatingText = "Update failed!" ctx.update.updatingText = "Update failed!"
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
return return
} }
untar(bytes.NewReader(tgz), os.Getenv("HOME")) untar(bytes.NewReader(tgz), os.Getenv("HOME"))
log.Printf("Update installed!\n") log.Printf("Update installed!\n")
ui.update.updatingText = "Update installed! (Restart NoiseTorch to apply)" ctx.update.updatingText = "Update installed! (Restart NoiseTorch to apply)"
(*ui.masterWindow).Changed() (*ctx.masterWindow).Changed()
} }
func fetchFile(file string) ([]byte, error) { func fetchFile(file string) ([]byte, error) {

Loading…
Cancel
Save