218 lines
6.2 KiB
Go
218 lines
6.2 KiB
Go
package dialogs
|
|
|
|
import (
|
|
"math"
|
|
"strconv"
|
|
"supersonic/backend"
|
|
"supersonic/ui/layouts"
|
|
"supersonic/ui/widgets"
|
|
"unicode"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/widget"
|
|
)
|
|
|
|
var boldStyle = widget.RichTextStyle{TextStyle: fyne.TextStyle{Bold: true}}
|
|
|
|
type SettingsDialog struct {
|
|
widget.BaseWidget
|
|
|
|
OnReplayGainSettingsChanged func()
|
|
OnAudioExclusiveSettingChanged func()
|
|
OnDismiss func()
|
|
|
|
config *backend.Config
|
|
|
|
content fyne.CanvasObject
|
|
}
|
|
|
|
func NewSettingsDialog(config *backend.Config) *SettingsDialog {
|
|
s := &SettingsDialog{config: config}
|
|
s.ExtendBaseWidget(s)
|
|
|
|
tabs := container.NewAppTabs(
|
|
s.createGeneralTab(),
|
|
s.createPlaybackTab(),
|
|
)
|
|
s.content = container.NewVBox(tabs, widget.NewSeparator(),
|
|
container.NewHBox(layout.NewSpacer(), widget.NewButton("Close", func() {
|
|
if s.OnDismiss != nil {
|
|
s.OnDismiss()
|
|
}
|
|
})))
|
|
|
|
return s
|
|
}
|
|
|
|
func (s *SettingsDialog) createGeneralTab() *container.TabItem {
|
|
twoDigitValidator := func(text string, r rune) bool {
|
|
return unicode.IsDigit(r) && len(text) < 2
|
|
}
|
|
|
|
percentEntry := widgets.NewTextRestrictedEntry(twoDigitValidator)
|
|
percentEntry.SetMinCharWidth(2)
|
|
percentEntry.OnChanged = func(str string) {
|
|
if i, err := strconv.Atoi(str); err == nil {
|
|
s.config.Scrobbling.ThresholdPercent = i
|
|
}
|
|
}
|
|
percentEntry.Text = strconv.Itoa(s.config.Scrobbling.ThresholdPercent)
|
|
if !s.config.Scrobbling.Enabled {
|
|
percentEntry.Disable()
|
|
}
|
|
|
|
durationEntry := widgets.NewTextRestrictedEntry(twoDigitValidator)
|
|
durationEntry.SetMinCharWidth(2)
|
|
durationEntry.OnChanged = func(str string) {
|
|
if i, err := strconv.Atoi(str); err == nil {
|
|
s.config.Scrobbling.ThresholdTimeSeconds = i * 60
|
|
}
|
|
}
|
|
if secs := s.config.Scrobbling.ThresholdTimeSeconds; secs >= 0 {
|
|
val := int(math.Round(float64(secs) / 60.))
|
|
durationEntry.Text = strconv.Itoa(val)
|
|
}
|
|
if !s.config.Scrobbling.Enabled || s.config.Scrobbling.ThresholdTimeSeconds < 0 {
|
|
durationEntry.Disable()
|
|
}
|
|
|
|
lastScrobbleText := durationEntry.Text
|
|
if lastScrobbleText == "" {
|
|
lastScrobbleText = "4" // default scrobble minutes
|
|
}
|
|
durationEnabled := widget.NewCheck("or when", func(checked bool) {
|
|
if !checked {
|
|
s.config.Scrobbling.ThresholdTimeSeconds = -1
|
|
lastScrobbleText = durationEntry.Text
|
|
durationEntry.Text = ""
|
|
durationEntry.Disable()
|
|
} else {
|
|
durationEntry.Text = lastScrobbleText
|
|
durationEntry.Enable()
|
|
durationEntry.Refresh()
|
|
durationEntry.OnChanged(durationEntry.Text)
|
|
}
|
|
})
|
|
durationEnabled.Checked = s.config.Scrobbling.ThresholdTimeSeconds >= 0
|
|
if !s.config.Scrobbling.Enabled {
|
|
durationEnabled.Disable()
|
|
}
|
|
|
|
scrobbleEnabled := widget.NewCheck("Send playback statistics to server", func(checked bool) {
|
|
s.config.Scrobbling.Enabled = checked
|
|
if !checked {
|
|
percentEntry.Disable()
|
|
durationEnabled.Disable()
|
|
durationEntry.Disable()
|
|
} else {
|
|
percentEntry.Enable()
|
|
durationEnabled.Enable()
|
|
if durationEnabled.Checked {
|
|
durationEntry.Enable()
|
|
}
|
|
}
|
|
})
|
|
scrobbleEnabled.Checked = s.config.Scrobbling.Enabled
|
|
|
|
return container.NewTabItem("General", container.NewVBox(
|
|
widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: boldStyle}),
|
|
scrobbleEnabled,
|
|
container.NewHBox(
|
|
widget.NewLabel("Scrobble when"),
|
|
percentEntry,
|
|
widget.NewLabel("percent of track is played"),
|
|
),
|
|
container.NewHBox(
|
|
durationEnabled,
|
|
durationEntry,
|
|
widget.NewLabel("minutes of track have been played"),
|
|
),
|
|
))
|
|
}
|
|
|
|
func (s *SettingsDialog) createPlaybackTab() *container.TabItem {
|
|
replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track"}, nil)
|
|
replayGainSelect.OnChanged = func(_ string) {
|
|
switch replayGainSelect.SelectedIndex() {
|
|
case 0:
|
|
s.config.ReplayGain.Mode = backend.ReplayGainNone
|
|
case 1:
|
|
s.config.ReplayGain.Mode = backend.ReplayGainAlbum
|
|
case 2:
|
|
s.config.ReplayGain.Mode = backend.ReplayGainTrack
|
|
}
|
|
s.onReplayGainSettingsChanged()
|
|
}
|
|
|
|
// set initially selected option
|
|
switch s.config.ReplayGain.Mode {
|
|
case backend.ReplayGainAlbum:
|
|
replayGainSelect.SetSelectedIndex(1)
|
|
case backend.ReplayGainTrack:
|
|
replayGainSelect.SetSelectedIndex(2)
|
|
default:
|
|
replayGainSelect.SetSelectedIndex(0)
|
|
}
|
|
|
|
preampGain := widgets.NewTextRestrictedEntry(func(curText string, r rune) bool {
|
|
return (curText == "" && r == '-') ||
|
|
(curText == "" && unicode.IsDigit(r)) ||
|
|
((curText == "-" || curText == "0") && unicode.IsDigit(r))
|
|
})
|
|
preampGain.SetMinCharWidth(2)
|
|
preampGain.OnChanged = func(text string) {
|
|
if f, err := strconv.ParseFloat(text, 64); err == nil {
|
|
s.config.ReplayGain.PreampGainDB = f
|
|
s.onReplayGainSettingsChanged()
|
|
}
|
|
}
|
|
initVal := math.Round(s.config.ReplayGain.PreampGainDB)
|
|
if initVal < -9 {
|
|
initVal = -9
|
|
} else if initVal > 9 {
|
|
initVal = 9
|
|
}
|
|
preampGain.Text = strconv.Itoa(int(initVal))
|
|
|
|
preventClipping := widget.NewCheck("", func(checked bool) {
|
|
s.config.ReplayGain.PreventClipping = checked
|
|
s.onReplayGainSettingsChanged()
|
|
})
|
|
preventClipping.Checked = s.config.ReplayGain.PreventClipping
|
|
|
|
audioExclusive := widget.NewCheck("Audio exclusive mode", func(checked bool) {
|
|
s.config.LocalPlayback.AudioExclusive = checked
|
|
s.onAudioExclusiveSettingsChanged()
|
|
})
|
|
audioExclusive.Checked = s.config.LocalPlayback.AudioExclusive
|
|
|
|
return container.NewTabItem("Playback", container.NewVBox(
|
|
widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: boldStyle}),
|
|
container.New(layout.NewFormLayout(),
|
|
widget.NewLabel("ReplayGain mode"), replayGainSelect,
|
|
widget.NewLabel("ReplayGain preamp"), container.NewHBox(preampGain, widget.NewLabel("dB")),
|
|
widget.NewLabel("Prevent clipping"), container.NewHBox(preventClipping, layout.NewSpacer()),
|
|
),
|
|
container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15}, widget.NewSeparator()),
|
|
container.NewHBox(audioExclusive, layout.NewSpacer()),
|
|
))
|
|
}
|
|
|
|
func (s *SettingsDialog) onReplayGainSettingsChanged() {
|
|
if s.OnReplayGainSettingsChanged != nil {
|
|
s.OnReplayGainSettingsChanged()
|
|
}
|
|
}
|
|
|
|
func (s *SettingsDialog) onAudioExclusiveSettingsChanged() {
|
|
if s.OnAudioExclusiveSettingChanged != nil {
|
|
s.OnAudioExclusiveSettingChanged()
|
|
}
|
|
}
|
|
|
|
func (s *SettingsDialog) CreateRenderer() fyne.WidgetRenderer {
|
|
return widget.NewSimpleRenderer(s.content)
|
|
}
|