expose more config file settings in the UI
This commit is contained in:
+4
-2
@@ -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
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user