| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package app
- import (
- "bytes"
- "os"
- "path/filepath"
- "sync"
- "fyne.io/fyne/v2"
- "fyne.io/fyne/v2/theme"
- )
- var noAnimations bool // set to true at compile time if no_animations tag is passed
- // SettingsSchema is used for loading and storing global settings
- type SettingsSchema struct {
- // these items are used for global settings load
- ThemeName string `json:"theme"`
- Scale float32 `json:"scale"`
- PrimaryColor string `json:"primary_color"`
- CloudName string `json:"cloud_name"`
- CloudConfig string `json:"cloud_config"`
- DisableAnimations bool `json:"no_animations"`
- }
- // StoragePath returns the location of the settings storage
- func (sc *SettingsSchema) StoragePath() string {
- return filepath.Join(rootConfigDir(), "settings.json")
- }
- // Declare conformity with Settings interface
- var _ fyne.Settings = (*settings)(nil)
- type settings struct {
- propertyLock sync.RWMutex
- theme fyne.Theme
- themeSpecified bool
- variant fyne.ThemeVariant
- changeListeners sync.Map // map[chan fyne.Settings]bool
- watcher interface{} // normally *fsnotify.Watcher or nil - avoid import in this file
- schema SettingsSchema
- }
- func (s *settings) BuildType() fyne.BuildType {
- return buildMode
- }
- func (s *settings) PrimaryColor() string {
- s.propertyLock.RLock()
- defer s.propertyLock.RUnlock()
- return s.schema.PrimaryColor
- }
- // OverrideTheme allows the settings app to temporarily preview different theme details.
- // Please make sure that you remember the original settings and call this again to revert the change.
- func (s *settings) OverrideTheme(theme fyne.Theme, name string) {
- s.propertyLock.Lock()
- defer s.propertyLock.Unlock()
- s.schema.PrimaryColor = name
- s.theme = theme
- }
- func (s *settings) Theme() fyne.Theme {
- s.propertyLock.RLock()
- defer s.propertyLock.RUnlock()
- return s.theme
- }
- func (s *settings) SetTheme(theme fyne.Theme) {
- s.themeSpecified = true
- s.applyTheme(theme, s.variant)
- }
- func (s *settings) ShowAnimations() bool {
- return !s.schema.DisableAnimations && !noAnimations
- }
- func (s *settings) ThemeVariant() fyne.ThemeVariant {
- return s.variant
- }
- func (s *settings) applyTheme(theme fyne.Theme, variant fyne.ThemeVariant) {
- s.propertyLock.Lock()
- defer s.propertyLock.Unlock()
- s.variant = variant
- s.theme = theme
- s.apply()
- }
- func (s *settings) Scale() float32 {
- s.propertyLock.RLock()
- defer s.propertyLock.RUnlock()
- if s.schema.Scale < 0.0 {
- return 1.0 // catching any really old data still using the `-1` value for "auto" scale
- }
- return s.schema.Scale
- }
- func (s *settings) AddChangeListener(listener chan fyne.Settings) {
- s.changeListeners.Store(listener, true) // the boolean is just a dummy value here.
- }
- func (s *settings) apply() {
- s.changeListeners.Range(func(key, _ interface{}) bool {
- listener := key.(chan fyne.Settings)
- select {
- case listener <- s:
- default:
- l := listener
- go func() { l <- s }()
- }
- return true
- })
- }
- func (s *settings) fileChanged() {
- s.load()
- s.apply()
- }
- func (s *settings) loadSystemTheme() fyne.Theme {
- path := filepath.Join(rootConfigDir(), "theme.json")
- data, err := fyne.LoadResourceFromPath(path)
- if err != nil {
- if !os.IsNotExist(err) {
- fyne.LogError("Failed to load user theme file: "+path, err)
- }
- return theme.DefaultTheme()
- }
- if data != nil && data.Content() != nil {
- th, err := theme.FromJSONReader(bytes.NewReader(data.Content()))
- if err == nil {
- return th
- }
- fyne.LogError("Failed to parse user theme file: "+path, err)
- }
- return theme.DefaultTheme()
- }
- func (s *settings) setupTheme() {
- name := s.schema.ThemeName
- if env := os.Getenv("FYNE_THEME"); env != "" {
- name = env
- }
- variant := defaultVariant()
- effectiveTheme := s.theme
- if !s.themeSpecified {
- effectiveTheme = s.loadSystemTheme()
- }
- switch name {
- case "light":
- variant = theme.VariantLight
- case "dark":
- variant = theme.VariantDark
- }
- s.applyTheme(effectiveTheme, variant)
- }
- func loadSettings() *settings {
- s := &settings{}
- s.load()
- return s
- }
|