preferences.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package internal
  2. import (
  3. "sync"
  4. "fyne.io/fyne/v2"
  5. )
  6. // InMemoryPreferences provides an implementation of the fyne.Preferences API that is stored in memory.
  7. type InMemoryPreferences struct {
  8. values map[string]interface{}
  9. lock sync.RWMutex
  10. changeListeners []func()
  11. wg *sync.WaitGroup
  12. }
  13. // Declare conformity with Preferences interface
  14. var _ fyne.Preferences = (*InMemoryPreferences)(nil)
  15. // AddChangeListener allows code to be notified when some preferences change. This will fire on any update.
  16. // The passed 'listener' should not try to write values.
  17. func (p *InMemoryPreferences) AddChangeListener(listener func()) {
  18. p.lock.Lock()
  19. defer p.lock.Unlock()
  20. p.changeListeners = append(p.changeListeners, listener)
  21. }
  22. // ChangeListeners returns the list of listeners registered for this set of preferences.
  23. func (p *InMemoryPreferences) ChangeListeners() []func() {
  24. return p.changeListeners
  25. }
  26. // ReadValues provides read access to the underlying value map - for internal use only...
  27. // You should not retain a reference to the map nor write to the values in the callback function
  28. func (p *InMemoryPreferences) ReadValues(fn func(map[string]interface{})) {
  29. p.lock.RLock()
  30. fn(p.values)
  31. p.lock.RUnlock()
  32. }
  33. // WriteValues provides write access to the underlying value map - for internal use only...
  34. // You should not retain a reference to the map passed to the callback function
  35. func (p *InMemoryPreferences) WriteValues(fn func(map[string]interface{})) {
  36. p.lock.Lock()
  37. fn(p.values)
  38. p.lock.Unlock()
  39. p.fireChange()
  40. }
  41. func (p *InMemoryPreferences) set(key string, value interface{}) {
  42. p.lock.Lock()
  43. if stored, ok := p.values[key]; ok && stored == value {
  44. p.lock.Unlock()
  45. return
  46. }
  47. p.values[key] = value
  48. p.lock.Unlock()
  49. p.fireChange()
  50. }
  51. func (p *InMemoryPreferences) get(key string) (interface{}, bool) {
  52. p.lock.RLock()
  53. defer p.lock.RUnlock()
  54. v, err := p.values[key]
  55. return v, err
  56. }
  57. func (p *InMemoryPreferences) remove(key string) {
  58. p.lock.Lock()
  59. delete(p.values, key)
  60. p.lock.Unlock()
  61. p.fireChange()
  62. }
  63. func (p *InMemoryPreferences) fireChange() {
  64. p.lock.RLock()
  65. listeners := p.changeListeners
  66. p.lock.RUnlock()
  67. for _, l := range listeners {
  68. p.wg.Add(1)
  69. go func(listener func()) {
  70. defer p.wg.Done()
  71. listener()
  72. }(l)
  73. }
  74. p.wg.Wait()
  75. }
  76. // Bool looks up a boolean value for the key
  77. func (p *InMemoryPreferences) Bool(key string) bool {
  78. return p.BoolWithFallback(key, false)
  79. }
  80. // BoolWithFallback looks up a boolean value and returns the given fallback if not found
  81. func (p *InMemoryPreferences) BoolWithFallback(key string, fallback bool) bool {
  82. value, ok := p.get(key)
  83. if !ok {
  84. return fallback
  85. }
  86. val, ok := value.(bool)
  87. if !ok {
  88. return false
  89. }
  90. return val
  91. }
  92. // SetBool saves a boolean value for the given key
  93. func (p *InMemoryPreferences) SetBool(key string, value bool) {
  94. p.set(key, value)
  95. }
  96. // Float looks up a float64 value for the key
  97. func (p *InMemoryPreferences) Float(key string) float64 {
  98. return p.FloatWithFallback(key, 0.0)
  99. }
  100. // FloatWithFallback looks up a float64 value and returns the given fallback if not found
  101. func (p *InMemoryPreferences) FloatWithFallback(key string, fallback float64) float64 {
  102. value, ok := p.get(key)
  103. if !ok {
  104. return fallback
  105. }
  106. val, ok := value.(float64)
  107. if !ok {
  108. return 0.0
  109. }
  110. return val
  111. }
  112. // SetFloat saves a float64 value for the given key
  113. func (p *InMemoryPreferences) SetFloat(key string, value float64) {
  114. p.set(key, value)
  115. }
  116. // Int looks up an integer value for the key
  117. func (p *InMemoryPreferences) Int(key string) int {
  118. return p.IntWithFallback(key, 0)
  119. }
  120. // IntWithFallback looks up an integer value and returns the given fallback if not found
  121. func (p *InMemoryPreferences) IntWithFallback(key string, fallback int) int {
  122. value, ok := p.get(key)
  123. if !ok {
  124. return fallback
  125. }
  126. // integers can be de-serialised as floats, so support both
  127. if intVal, ok := value.(int); ok {
  128. return intVal
  129. }
  130. val, ok := value.(float64)
  131. if !ok {
  132. return 0
  133. }
  134. return int(val)
  135. }
  136. // SetInt saves an integer value for the given key
  137. func (p *InMemoryPreferences) SetInt(key string, value int) {
  138. p.set(key, value)
  139. }
  140. // String looks up a string value for the key
  141. func (p *InMemoryPreferences) String(key string) string {
  142. return p.StringWithFallback(key, "")
  143. }
  144. // StringWithFallback looks up a string value and returns the given fallback if not found
  145. func (p *InMemoryPreferences) StringWithFallback(key, fallback string) string {
  146. value, ok := p.get(key)
  147. if !ok {
  148. return fallback
  149. }
  150. return value.(string)
  151. }
  152. // SetString saves a string value for the given key
  153. func (p *InMemoryPreferences) SetString(key string, value string) {
  154. p.set(key, value)
  155. }
  156. // RemoveValue deletes a value on the given key
  157. func (p *InMemoryPreferences) RemoveValue(key string) {
  158. p.remove(key)
  159. }
  160. // NewInMemoryPreferences creates a new preferences implementation stored in memory
  161. func NewInMemoryPreferences() *InMemoryPreferences {
  162. return &InMemoryPreferences{
  163. values: make(map[string]interface{}),
  164. wg: &sync.WaitGroup{},
  165. }
  166. }