expose more config file settings in the UI

This commit is contained in:
Drew Weymouth
2025-02-21 16:31:04 -08:00
parent 90f85d26a6
commit 95ef3eae38
4 changed files with 104 additions and 54 deletions
+4 -2
View File
@@ -127,8 +127,10 @@ func StartupApp(appName, displayAppName, appVersion, appVersionTag, latestReleas
log.Printf("Using config dir: %s", confDir)
log.Printf("Using cache dir: %s", cacheDir)
a.UpdateChecker = NewUpdateChecker(appVersionTag, latestReleaseURL, &a.Config.Application.LastCheckedVersion)
a.UpdateChecker.Start(a.bgrndCtx, 24*time.Hour)
if a.Config.Application.EnableAutoUpdateChecker {
a.UpdateChecker = NewUpdateChecker(appVersionTag, latestReleaseURL, &a.Config.Application.LastCheckedVersion)
a.UpdateChecker.Start(a.bgrndCtx, 24*time.Hour)
}
if err := a.initMPV(); err != nil {
return nil, err
+2
View File
@@ -53,6 +53,7 @@ type AppConfig struct {
EnqueueBatchSize int
Language string
DisableDPIDetection bool
EnableAutoUpdateChecker bool
// Experimental - may be removed in future
FontNormalTTF string
@@ -189,6 +190,7 @@ func DefaultConfig(appVersionTag string) *Config {
SkipSSLVerify: false,
EnqueueBatchSize: 100,
Language: "auto",
EnableAutoUpdateChecker: true,
},
AlbumPage: AlbumPageConfig{
TracklistColumns: []string{"Artist", "Time", "Plays", "Favorite", "Rating"},
+7
View File
@@ -16,10 +16,13 @@
"albums": "albums",
"All": "All",
"All Tracks": "All Tracks",
"Allow multiple app instances": "Allow multiple app instances",
"Alt. URL": "Alt. URL",
"An error occurred": "An error occurred",
"An error occurred adding tracks to the playlist": "An error occurred adding tracks to the playlist",
"An error occurred updating the playlist": "An error occurred updating the playlist",
"Appearance": "Appearance",
"Application font": "Application font",
"Are you sure you want to delete the server": "Are you sure you want to delete the server",
"Artist": "Artist",
"Artist (A-Z)": "Artist (A-Z)",
@@ -30,6 +33,7 @@
"Audiobook": "Audiobook",
"Authentication failed": "Authentication failed",
"Auto": "Auto",
"Automatically check for updates": "Automatically check for updates",
"Autoplay": "Autoplay",
"Autoselect device": "Autoselect device",
"Back": "Back",
@@ -58,6 +62,7 @@
"Demo": "Demo",
"_Description": "Description",
"Disable server transcoding": "Disable server transcoding",
"Disable automatic DPI adjustment": "Disable automatic DPI adjustment",
"Disc number": "Disc number",
"Discography": "Discography",
"discs": "discs",
@@ -68,6 +73,7 @@
"Edit": "Edit",
"Edit Playlist": "Edit Playlist",
"Edit server": "Edit server",
"Enable LrcLib lyrics fetcher": "Enable LrcLib lyrics fetcher",
"Enable system tray": "Enable system tray",
"Enabled": "Enabled",
"Enter": "Enter",
@@ -187,6 +193,7 @@
"Single": "Single",
"Size": "Size",
"Skip duplicate tracks": "Skip duplicate tracks",
"Skip SSL certificate verification": "Skip SSL certificate verification",
"Skip this version": "Skip this version",
"Sort": "Sort",
"Soundtrack": "Soundtrack",
+91 -52
View File
@@ -65,21 +65,23 @@ func NewSettingsDialog(
s := &SettingsDialog{config: config, audioDevices: audioDeviceList, themeFiles: themeFileList, clientDecidesScrobble: clientDecidesScrobble}
s.ExtendBaseWidget(s)
// TODO: Once Fyne supports disableable sliders, it's probably a nicer UX
// to create the equalizer tab but disable it if we are not using an equalizer player
// TODO: It may be a nicer UX to always create the equalizer tab,
// but disable it if we are not using an equalizer player
var tabs *container.AppTabs
if isEqualizerPlayer {
tabs = container.NewAppTabs(
s.createGeneralTab(canSavePlayQueue),
s.createAppearanceTab(window),
s.createPlaybackTab(isLocalPlayer, isReplayGainPlayer),
s.createEqualizerTab(equalizerBands),
s.createExperimentalTab(window),
s.createAdvancedTab(),
)
} else {
tabs = container.NewAppTabs(
s.createGeneralTab(canSavePlayQueue),
s.createAppearanceTab(window),
s.createPlaybackTab(isLocalPlayer, isReplayGainPlayer),
s.createExperimentalTab(window),
s.createAdvancedTab(),
)
}
@@ -99,41 +101,6 @@ func NewSettingsDialog(
}
func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container.TabItem {
themeNames := []string{"Default"}
themeFileNames := []string{""}
i, selIndex := 1, 0
for filename, displayname := range s.themeFiles {
themeFileNames = append(themeFileNames, filename)
themeNames = append(themeNames, displayname)
if strings.EqualFold(filename, s.config.Theme.ThemeFile) {
selIndex = i
}
i++
}
themeFileSelect := widget.NewSelect(themeNames, nil)
themeFileSelect.SetSelectedIndex(selIndex)
themeFileSelect.OnChanged = func(_ string) {
s.config.Theme.ThemeFile = themeFileNames[themeFileSelect.SelectedIndex()]
if s.OnThemeSettingChanged != nil {
s.OnThemeSettingChanged()
}
}
themeModeSelect := widget.NewSelect([]string{
string(myTheme.AppearanceDark),
string(myTheme.AppearanceLight),
string(myTheme.AppearanceAuto)}, nil)
themeModeSelect.OnChanged = func(_ string) {
s.config.Theme.Appearance = themeModeSelect.Options[themeModeSelect.SelectedIndex()]
if s.OnThemeSettingChanged != nil {
s.OnThemeSettingChanged()
}
}
themeModeSelect.SetSelected(s.config.Theme.Appearance)
if themeModeSelect.Selected == "" {
themeModeSelect.SetSelectedIndex(0)
}
pages := util.LocalizeSlice(backend.SupportedStartupPages)
var startupPage *widget.Select
startupPage = widget.NewSelect(pages, func(_ string) {
@@ -308,11 +275,8 @@ func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container.
scrobbleEnabled.Checked = s.config.Scrobbling.Enabled
return container.NewTabItem(lang.L("General"), container.NewVBox(
util.NewHSpace(0), // insert a theme.Padding amount of space at top
container.NewHBox(widget.NewLabel(lang.L("Language")), languageSelect),
container.NewBorder(nil, nil, widget.NewLabel(lang.L("Theme")), /*left*/
container.NewHBox(widget.NewLabel(lang.L("Mode")), themeModeSelect, util.NewHSpace(5)), // right
themeFileSelect, // center
),
container.NewHBox(
widget.NewLabel(lang.L("Startup page")), container.NewGridWithColumns(2, startupPage),
),
@@ -473,11 +437,41 @@ func (s *SettingsDialog) createEqualizerTab(eqBands []string) *container.TabItem
return container.NewTabItem(lang.L("Equalizer"), cont)
}
func (s *SettingsDialog) createExperimentalTab(window fyne.Window) *container.TabItem {
warningLabel := widget.NewLabel("WARNING: these settings are experimental and may " +
"make the application buggy or increase system resource use. " +
"They may be removed in future versions.")
warningLabel.Wrapping = fyne.TextWrapWord
func (s *SettingsDialog) createAppearanceTab(window fyne.Window) *container.TabItem {
themeNames := []string{"Default"}
themeFileNames := []string{""}
i, selIndex := 1, 0
for filename, displayname := range s.themeFiles {
themeFileNames = append(themeFileNames, filename)
themeNames = append(themeNames, displayname)
if strings.EqualFold(filename, s.config.Theme.ThemeFile) {
selIndex = i
}
i++
}
themeFileSelect := widget.NewSelect(themeNames, nil)
themeFileSelect.SetSelectedIndex(selIndex)
themeFileSelect.OnChanged = func(_ string) {
s.config.Theme.ThemeFile = themeFileNames[themeFileSelect.SelectedIndex()]
if s.OnThemeSettingChanged != nil {
s.OnThemeSettingChanged()
}
}
themeModeSelect := widget.NewSelect([]string{
string(myTheme.AppearanceDark),
string(myTheme.AppearanceLight),
string(myTheme.AppearanceAuto)}, nil)
themeModeSelect.OnChanged = func(_ string) {
s.config.Theme.Appearance = themeModeSelect.Options[themeModeSelect.SelectedIndex()]
if s.OnThemeSettingChanged != nil {
s.OnThemeSettingChanged()
}
}
themeModeSelect.SetSelected(s.config.Theme.Appearance)
if themeModeSelect.Selected == "" {
themeModeSelect.SetSelectedIndex(0)
}
normalFontEntry := widget.NewEntry()
normalFontEntry.SetPlaceHolder("path to .ttf or empty to use default")
@@ -518,13 +512,24 @@ func (s *SettingsDialog) createExperimentalTab(window fyne.Window) *container.Ta
} else {
uiScaleRadio.Selected = "Normal"
}
return container.NewTabItem("Experimental", container.NewVBox(
warningLabel,
s.newSectionSeparator(),
disableDPI := widget.NewCheck(lang.L("Disable automatic DPI adjustment"), func(b bool) {
s.config.Application.DisableDPIDetection = b
s.setRestartRequired()
})
disableDPI.Checked = s.config.Application.DisableDPIDetection
return container.NewTabItem(lang.L("Appearance"), container.NewVBox(
util.NewHSpace(0), // insert a theme.Padding amount of space at top
container.NewBorder(nil, nil, widget.NewLabel(lang.L("Theme")), /*left*/
container.NewHBox(widget.NewLabel(lang.L("Mode")), themeModeSelect, util.NewHSpace(5)), // right
themeFileSelect, // center
),
widget.NewRichText(&widget.TextSegment{Text: lang.L("UI Scaling"), Style: util.BoldRichTextStyle}),
uiScaleRadio,
disableDPI,
s.newSectionSeparator(),
widget.NewRichText(&widget.TextSegment{Text: "Application Font", Style: util.BoldRichTextStyle}),
widget.NewRichText(&widget.TextSegment{Text: lang.L("Application font"), Style: util.BoldRichTextStyle}),
container.New(layout.NewFormLayout(),
widget.NewLabel("Normal font"), container.NewBorder(nil, nil, nil, normalFontBrowse, normalFontEntry),
widget.NewLabel("Bold font"), container.NewBorder(nil, nil, nil, boldFontBrowse, boldFontEntry),
@@ -532,6 +537,40 @@ func (s *SettingsDialog) createExperimentalTab(window fyne.Window) *container.Ta
))
}
func (s *SettingsDialog) createAdvancedTab() *container.TabItem {
multi := widget.NewCheckWithData(lang.L("Allow multiple app instances"), binding.BindBool(&s.config.Application.AllowMultiInstance))
sslSkip := widget.NewCheckWithData(lang.L("Skip SSL certificate verification"), binding.BindBool(&s.config.Application.SkipSSLVerify))
update := widget.NewCheckWithData(lang.L("Automatically check for updates"), binding.BindBool(&s.config.Application.EnableAutoUpdateChecker))
lrclib := widget.NewCheckWithData(lang.L("Enable LrcLib lyrics fetcher"), binding.BindBool(&s.config.Application.EnableLrcLib))
threeDigitValidator := func(text, selText string, r rune) bool {
return unicode.IsDigit(r) && len(text)-len(selText) < 3
}
percentEntry := widgets.NewTextRestrictedEntry(threeDigitValidator)
percentEntry.SetMinCharWidth(3)
percentEntry.OnChanged = func(str string) {
if i, err := strconv.Atoi(str); err == nil {
s.config.Application.MaxImageCacheSizeMB = i
}
}
percentEntry.Text = strconv.Itoa(s.config.Application.MaxImageCacheSizeMB)
imgCacheCfg := container.NewHBox(
widget.NewLabel(lang.L("Maximum image cache size")),
percentEntry,
widget.NewLabel("MB"),
)
return container.NewTabItem(lang.L("Advanced"), container.NewVBox(
multi,
sslSkip,
update,
lrclib,
imgCacheCfg,
))
}
func (s *SettingsDialog) doChooseTTFFile(window fyne.Window, entry *widget.Entry) {
callback := func(urirc fyne.URIReadCloser, err error) {
if err == nil && urirc != nil {