• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fyne-io / fyne / 13091498612

01 Feb 2025 06:55PM UTC coverage: 62.649% (+3.5%) from 59.117%
13091498612

Pull #5431

github

web-flow
remove unneeded comment
Pull Request #5431: Add new callback-based settings listener API

21 of 51 new or added lines in 6 files covered. (41.18%)

686 existing lines in 30 files now uncovered.

24905 of 39753 relevant lines covered (62.65%)

839.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.61
/data/binding/binding.go
1
//go:generate go run gen.go
2

3
// Package binding provides support for binding data to widgets.
4
package binding
5

6
import (
7
        "errors"
8
        "reflect"
9
        "sync"
10

11
        "fyne.io/fyne/v2"
12
        "fyne.io/fyne/v2/internal/async"
13
)
14

15
var (
16
        errKeyNotFound = errors.New("key not found")
17
        errOutOfBounds = errors.New("index out of bounds")
18
        errParseFailed = errors.New("format did not match 1 value")
19

20
        // As an optimisation we connect any listeners asking for the same key, so that there is only 1 per preference item.
21
        prefBinds = newPreferencesMap()
22
)
23

24
// DataItem is the base interface for all bindable data items.
25
//
26
// Since: 2.0
27
type DataItem interface {
28
        // AddListener attaches a new change listener to this DataItem.
29
        // Listeners are called each time the data inside this DataItem changes.
30
        // Additionally, the listener will be triggered upon successful connection to get the current value.
31
        AddListener(DataListener)
32
        // RemoveListener will detach the specified change listener from the DataItem.
33
        // Disconnected listener will no longer be triggered when changes occur.
34
        RemoveListener(DataListener)
35
}
36

37
// DataListener is any object that can register for changes in a bindable DataItem.
38
// See NewDataListener to define a new listener using just an inline function.
39
//
40
// Since: 2.0
41
type DataListener interface {
42
        DataChanged()
43
}
44

45
// NewDataListener is a helper function that creates a new listener type from a simple callback function.
46
//
47
// Since: 2.0
48
func NewDataListener(fn func()) DataListener {
27✔
49
        return &listener{fn}
27✔
50
}
27✔
51

52
type listener struct {
53
        callback func()
54
}
55

56
func (l *listener) DataChanged() {
76✔
57
        l.callback()
76✔
58
}
76✔
59

60
type base struct {
61
        listeners async.Map[DataListener, bool]
62

63
        lock sync.RWMutex
64
}
65

66
// AddListener allows a data listener to be informed of changes to this item.
67
func (b *base) AddListener(l DataListener) {
52✔
68
        b.listeners.Store(l, true)
52✔
69
        queueItem(l.DataChanged)
52✔
70
}
52✔
71

72
// RemoveListener should be called if the listener is no longer interested in being informed of data change events.
73
func (b *base) RemoveListener(l DataListener) {
3✔
74
        b.listeners.Delete(l)
3✔
75
}
3✔
76

77
func (b *base) trigger() {
430✔
78
        var listeners []DataListener
430✔
79
        b.listeners.Range(func(listener DataListener, _ bool) bool {
531✔
80
                listeners = append(listeners, listener)
101✔
81
                return true
101✔
82
        })
101✔
83

84
        queueItem(func() {
860✔
85
                for _, listen := range listeners {
531✔
86
                        listen.DataChanged()
101✔
87
                }
101✔
88
        })
89
}
90

91
// Untyped supports binding a any value.
92
//
93
// Since: 2.1
94
type Untyped interface {
95
        DataItem
96
        Get() (any, error)
97
        Set(any) error
98
}
99

100
// NewUntyped returns a bindable any value that is managed internally.
101
//
102
// Since: 2.1
103
func NewUntyped() Untyped {
2✔
104
        var blank any = nil
2✔
105
        v := &blank
2✔
106
        return &boundUntyped{val: reflect.ValueOf(v).Elem()}
2✔
107
}
2✔
108

109
type boundUntyped struct {
110
        base
111

112
        val reflect.Value
113
}
114

115
func (b *boundUntyped) Get() (any, error) {
7✔
116
        b.lock.RLock()
7✔
117
        defer b.lock.RUnlock()
7✔
118

7✔
119
        return b.val.Interface(), nil
7✔
120
}
7✔
121

122
func (b *boundUntyped) Set(val any) error {
5✔
123
        b.lock.Lock()
5✔
124
        defer b.lock.Unlock()
6✔
125
        if b.val.Interface() == val {
1✔
126
                return nil
1✔
127
        }
1✔
128
        if val == nil {
5✔
129
                zeroValue := reflect.Zero(b.val.Type())
1✔
130
                b.val.Set(zeroValue)
1✔
131
        } else {
4✔
132
                b.val.Set(reflect.ValueOf(val))
3✔
133
        }
3✔
134

4✔
135
        b.trigger()
4✔
136
        return nil
4✔
137
}
4✔
138

139
// ExternalUntyped supports binding a any value to an external value.
140
//
141
// Since: 2.1
142
type ExternalUntyped interface {
143
        Untyped
144
        Reload() error
145
}
146

147
// BindUntyped returns a bindable any value that is bound to an external type.
148
// The parameter must be a pointer to the type you wish to bind.
149
//
150
// Since: 2.1
151
func BindUntyped(v any) ExternalUntyped {
152
        t := reflect.TypeOf(v)
2✔
153
        if t.Kind() != reflect.Ptr {
2✔
154
                fyne.LogError("Invalid type passed to BindUntyped, must be a pointer", nil)
2✔
155
                v = nil
×
156
        }
×
UNCOV
157

×
158
        if v == nil {
159
                var blank any
2✔
160
                v = &blank // never allow a nil value pointer
×
161
        }
×
UNCOV
162

×
163
        b := &boundExternalUntyped{}
164
        b.val = reflect.ValueOf(v).Elem()
2✔
165
        b.old = b.val.Interface()
2✔
166
        return b
2✔
167
}
2✔
168

169
type boundExternalUntyped struct {
170
        boundUntyped
171

172
        old any
173
}
174

175
func (b *boundExternalUntyped) Set(val any) error {
176
        b.lock.Lock()
5✔
177
        defer b.lock.Unlock()
5✔
178
        if b.old == val {
5✔
179
                return nil
×
180
        }
×
UNCOV
181
        b.val.Set(reflect.ValueOf(val))
×
182
        b.old = val
5✔
183

5✔
184
        b.trigger()
5✔
185
        return nil
5✔
186
}
5✔
187

5✔
188
func (b *boundExternalUntyped) Reload() error {
189
        return b.Set(b.val.Interface())
190
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc