ronantakizawa/codereview-bench huggingface dataset:
Repository: fyne-io/fyne
File: internal/driver/glfw/window.go (Go)

Code before:
package glfw

import (
	"context"
	_ "image/png" // for the icon
	"math"
	"runtime"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/internal/app"
	"fyne.io/fyne/v2/internal/cache"
	"fyne.io/fyne/v2/internal/driver"
	"fyne.io/fyne/v2/internal/driver/common"
	"fyne.io/fyne/v2/internal/scale"
)

const (
	doubleClickDelay       = 300 // ms (maximum interval between clicks for double click detection)
	dragMoveThreshold      = 2   // how far can we move before it is a drag
	windowIconSize         = 256
)

func (w *window) Title() string {
	return w.title
}

func (w *window) SetTitle(title string) {
	w.title = title

	w.runOnMainWhenCreated(func() {
		w.view().SetTitle(title)
	})
}

func (w *window) FullScreen() bool {
	return w.fullScreen
}

// minSizeOnScreen gets the padded minimum size of a window content in screen pixels
func (w *window) minSizeOnScreen() (int, int) {
	// get minimum size of content inside the window
	return w.screenSize(w.canvas.MinSize())
}

// screenSize computes the actual output size of the given content size in screen pixels

Review comment (bug):
This is the reason that `goimports` is failing. With the long names removed from the block, it wants the equal signs to be brought more to the left.

Code after:
package glfw

import (
	"context"
	_ "image/png" // for the icon
	"math"
	"runtime"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/internal/app"
	"fyne.io/fyne/v2/internal/cache"
	"fyne.io/fyne/v2/internal/driver"
	"fyne.io/fyne/v2/internal/driver/common"
	"fyne.io/fyne/v2/internal/scale"
)

const (
	doubleClickDelay  = 300 // ms (maximum interval between clicks for double click detection)
	dragMoveThreshold = 2   // how far can we move before it is a drag
	windowIconSize    = 256
)

func (w *window) Title() string {
	return w.title
}

func (w *window) SetTitle(title string) {
	w.title = title

	w.runOnMainWhenCreated(func() {
		w.view().SetTitle(title)
	})
}

func (w *window) FullScreen() bool {
	return w.fullScreen
}

// minSizeOnScreen gets the padded minimum size of a window content in screen pixels
func (w *window) minSizeOnScreen() (int, int) {
	// get minimum size of content inside the window
	return w.screenSize(w.canvas.MinSize())
}

// screenSize computes the actual output size of the given content size in screen pixels
Repository: fyne-io/fyne
File: widget/popup.go (Go)

Code before:
	p.Refresh()
}

// Show this pop-up as overlay if not already shown.
func (p *PopUp) Show() {
	if !p.overlayShown {
		p.Canvas.Overlays().Add(p)
		p.overlayShown = true
	}
	p.Refresh()
	p.BaseWidget.Show()
}

// ShowAtPosition shows this pop-up at the given position.
func (p *PopUp) ShowAtPosition(pos fyne.Position) {
	p.Move(pos)
	p.Show()
}

// ShowAtRelativePosition shows this pop-up at the given position relative to stated object.
//
// Since 2.4
func (p *PopUp) ShowAtRelativePosition(rel fyne.Position, to fyne.CanvasObject) {
	withRelativePosition(rel, to, func(pos fyne.Position) {
		p.ShowAtPosition(pos)
	})
}

// Tapped is called when the user taps the popUp background - if not modal then dismiss this widget
func (p *PopUp) Tapped(_ *fyne.PointEvent) {
	if !p.modal {
		p.Hide()
	}
}

// TappedSecondary is called when the user right/alt taps the background - if not modal then dismiss this widget
func (p *PopUp) TappedSecondary(_ *fyne.PointEvent) {
	if !p.modal {
		p.Hide()
	}
}

// MinSize returns the size that this widget should not shrink below
func (p *PopUp) MinSize() fyne.Size {
	p.ExtendBaseWidget(p)
	return p.BaseWidget.MinSize()
}

// CreateRenderer is a private method to Fyne which links this widget to its renderer
func (p *PopUp) CreateRenderer() fyne.WidgetRenderer {
	p.ExtendBaseWidget(p)

Review comment (suggestion):
You should be able to drop the wrapper function here.
```suggestion
	withRelativePosition(rel, to, p.ShowAtPosition)
```

Code after:
	p.Refresh()
}

// Show this pop-up as overlay if not already shown.
func (p *PopUp) Show() {
	if !p.overlayShown {
		p.Canvas.Overlays().Add(p)
		p.overlayShown = true
	}
	p.Refresh()
	p.BaseWidget.Show()
}

// ShowAtPosition shows this pop-up at the given position.
func (p *PopUp) ShowAtPosition(pos fyne.Position) {
	p.Move(pos)
	p.Show()
}

// ShowAtRelativePosition shows this pop-up at the given position relative to stated object.
//
// Since 2.4
func (p *PopUp) ShowAtRelativePosition(rel fyne.Position, to fyne.CanvasObject) {
	withRelativePosition(rel, to, p.ShowAtPosition)
}

// Tapped is called when the user taps the popUp background - if not modal then dismiss this widget
func (p *PopUp) Tapped(_ *fyne.PointEvent) {
	if !p.modal {
		p.Hide()
	}
}

// TappedSecondary is called when the user right/alt taps the background - if not modal then dismiss this widget
func (p *PopUp) TappedSecondary(_ *fyne.PointEvent) {
	if !p.modal {
		p.Hide()
	}
}

// MinSize returns the size that this widget should not shrink below
func (p *PopUp) MinSize() fyne.Size {
	p.ExtendBaseWidget(p)
	return p.BaseWidget.MinSize()
}

// CreateRenderer is a private method to Fyne which links this widget to its renderer
func (p *PopUp) CreateRenderer() fyne.WidgetRenderer {
	p.ExtendBaseWidget(p)
	background := canvas.NewRectangle(theme.OverlayBackgroundColor())
	if p.modal {
Repository: fyne-io/fyne
File: widget/popup_menu.go (Go)

Code before:
//
// Implements: fyne.Widget
func (p *PopUpMenu) Show() {
	p.Menu.alignment = p.alignment
	p.Menu.Refresh()

	p.overlay.Show()
	p.Menu.Show()
	if !fyne.CurrentDevice().IsMobile() {
		p.canvas.Focus(p)
	}
}

// ShowAtPosition shows the pop-up menu at the specified position.
func (p *PopUpMenu) ShowAtPosition(pos fyne.Position) {
	p.Move(pos)
	p.Show()
}

// ShowAtRelativePosition shows the pop-up menu at the position relative to given object.
//
// Since 2.4
func (p *PopUpMenu) ShowAtRelativePosition(rel fyne.Position, to fyne.CanvasObject) {
	withRelativePosition(rel, to, func(pos fyne.Position) {
		p.ShowAtPosition(pos)
	})
}

// TypedKey handles key events. It allows keyboard control of the pop-up menu.
//
// Implements: fyne.Focusable
func (p *PopUpMenu) TypedKey(e *fyne.KeyEvent) {
	switch e.Name {
	case fyne.KeyDown:
		p.ActivateNext()
	case fyne.KeyEnter, fyne.KeyReturn, fyne.KeySpace:
		p.TriggerLast()
	case fyne.KeyEscape:
		p.Dismiss()
	case fyne.KeyLeft:
		p.DeactivateLastSubmenu()
	case fyne.KeyRight:
		p.ActivateLastSubmenu()
	case fyne.KeyUp:
		p.ActivatePrevious()
	}
}

// TypedRune handles text events. For pop-up menus this does nothing.
//
// Implements: fyne.Focusable

Review comment (suggestion):
The same simplification can be applied here.
```suggestion
	withRelativePosition(rel, to, p.ShowAtPosition)
```

Code after:
//
// Implements: fyne.Widget
func (p *PopUpMenu) Show() {
	p.Menu.alignment = p.alignment
	p.Menu.Refresh()

	p.overlay.Show()
	p.Menu.Show()
	if !fyne.CurrentDevice().IsMobile() {
		p.canvas.Focus(p)
	}
}

// ShowAtPosition shows the pop-up menu at the specified position.
func (p *PopUpMenu) ShowAtPosition(pos fyne.Position) {
	p.Move(pos)
	p.Show()
}

// ShowAtRelativePosition shows the pop-up menu at the position relative to given object.
//
// Since 2.4
func (p *PopUpMenu) ShowAtRelativePosition(rel fyne.Position, to fyne.CanvasObject) {
	withRelativePosition(rel, to, p.ShowAtPosition)
}

// TypedKey handles key events. It allows keyboard control of the pop-up menu.
//
// Implements: fyne.Focusable
func (p *PopUpMenu) TypedKey(e *fyne.KeyEvent) {
	switch e.Name {
	case fyne.KeyDown:
		p.ActivateNext()
	case fyne.KeyEnter, fyne.KeyReturn, fyne.KeySpace:
		p.TriggerLast()
	case fyne.KeyEscape:
		p.Dismiss()
	case fyne.KeyLeft:
		p.DeactivateLastSubmenu()
	case fyne.KeyRight:
		p.ActivateLastSubmenu()
	case fyne.KeyUp:
		p.ActivatePrevious()
	}
}

// TypedRune handles text events. For pop-up menus this does nothing.
//
// Implements: fyne.Focusable
func (p *PopUpMenu) TypedRune(rune) {}
Repository: fyne-io/fyne
File: internal/driver/glfw/window_desktop.go (Go)

Code before:

	runOnMain(func() {
		monitor := w.getMonitorForWindow()
		mode := monitor.GetVideoMode()

		if full {
			w.viewport.SetMonitor(monitor, 0, 0, mode.Width, mode.Height, mode.RefreshRate)
		} else {
			if w.width == 0 && w.height == 0 { // if we were fullscreen on creation...
				w.width, w.height = w.screenSize(w.canvas.Size())
			}
			w.viewport.SetMonitor(nil, w.xpos, w.ypos, w.width, w.height, 0)
		}
	})
}

func (w *window) CenterOnScreen() {
	w.centered = true

	if w.view() != nil {
		runOnMain(w.doCenterOnScreen)
	}
}

func (w *window) SetOnDropped(dropped func(pos fyne.Position, items []fyne.URI)) {
	runOnDraw(w, func() {
		glfw.GetCurrentContext().SetDropCallback(func(win *glfw.Window, names []string) {
			if dropped == nil {
				return
			}

			uris := make([]fyne.URI, len(names))
			for i, name := range names {
				uris[i] = storage.NewFileURI(name)
			}

			dropped(w.mousePos, uris)
		})
	})
}

func (w *window) doCenterOnScreen() {
	viewWidth, viewHeight := w.screenSize(w.canvas.size)
	if w.width > viewWidth { // in case our window has not called back to canvas size yet
		viewWidth = w.width
	}
	if w.height > viewHeight {
		viewHeight = w.height
	}

	// get window dimensions in pixels

Review comment (suggestion):
It seems like the passed function that I want to run on the draw thread never actually runs. The code within works fine if I put it within one of the other functions that already are passed to `runOnDraw()` in other places within the codebase. Any help on why this queue never gets us anywhere would be helpful. 

Code after:

	runOnMain(func() {
		monitor := w.getMonitorForWindow()
		mode := monitor.GetVideoMode()

		if full {
			w.viewport.SetMonitor(monitor, 0, 0, mode.Width, mode.Height, mode.RefreshRate)
		} else {
			if w.width == 0 && w.height == 0 { // if we were fullscreen on creation...
				w.width, w.height = w.screenSize(w.canvas.Size())
			}
			w.viewport.SetMonitor(nil, w.xpos, w.ypos, w.width, w.height, 0)
		}
	})
}

func (w *window) CenterOnScreen() {
	w.centered = true

	if w.view() != nil {
		runOnMain(w.doCenterOnScreen)
	}
}

func (w *window) SetOnDropped(dropped func(pos fyne.Position, items []fyne.URI)) {
	w.runOnMainWhenCreated(func() {
		w.viewport.SetDropCallback(func(win *glfw.Window, names []string) {
			if dropped == nil {
				return
			}

			uris := make([]fyne.URI, len(names))
			for i, name := range names {
				uris[i] = storage.NewFileURI(name)
			}

			dropped(w.mousePos, uris)
		})
	})
}

func (w *window) doCenterOnScreen() {
	viewWidth, viewHeight := w.screenSize(w.canvas.size)
	if w.width > viewWidth { // in case our window has not called back to canvas size yet
		viewWidth = w.width
	}
	if w.height > viewHeight {
		viewHeight = w.height
	}

	// get window dimensions in pixels
Repository: fyne-io/fyne
File: container/apptabs_internal_test.go (Go)

Code before:
	assert.Equal(t, "Replace", renderer.label.Text)
}

func Test_tabButtonRenderer_DeleteAdd(t *testing.T) {
	item1 := &TabItem{Text: "Test", Content: widget.NewLabel("Content")}
	item2 := &TabItem{Text: "Delete", Content: widget.NewLabel("Delete")}
	tabs := NewAppTabs(item1, item2)
	tabRenderer := cache.Renderer(tabs).(*appTabsRenderer)
	indicator := tabRenderer.indicator

	pos := indicator.Position()
	tabs.SelectTab(item2)
	assert.NotEqual(t, pos, indicator.Position())
	pos = indicator.Position()

	tabs.Remove(item2)
	tabs.Append(item2)
	tabs.SelectTab(item2)
	assert.Equal(t, pos, indicator.Position())
}

func Test_tabButtonRenderer_EmptyDeleteAdd(t *testing.T) {
	item1 := &TabItem{Text: "Test", Content: widget.NewLabel("Content")}
	tabs := NewAppTabs()

	//cause tab button was build with enough space, without enough space, btns will not created.
	tabs.Resize(fyne.NewSize(300, 200))

	tabRenderer := cache.Renderer(tabs).(*appTabsRenderer)
	indicator := tabRenderer.indicator
	divider := tabRenderer.divider
	assert.Equal(t, 0, len(tabRenderer.bar.Objects[0].(*fyne.Container).Objects))
	assert.Equal(t, true, indicator.Hidden)
	assert.Equal(t, true, divider.Hidden)

	tabs.Append(item1)
	assert.Equal(t, 1, len(tabRenderer.bar.Objects[0].(*fyne.Container).Objects))
	assert.Equal(t, false, indicator.Hidden)
	assert.Equal(t, false, divider.Hidden)

	tabs.Remove(item1)
	assert.Equal(t, 0, len(tabRenderer.bar.Objects[0].(*fyne.Container).Objects))
	assert.Equal(t, true, indicator.Hidden)
	assert.Equal(t, true, divider.Hidden)
}


Review comment (suggestion):
This doesn't read very clearly.
```suggestion
	// ensure enough space for buttons to be created.
```

Code after:
	assert.Equal(t, "Replace", renderer.label.Text)
}

func Test_tabButtonRenderer_DeleteAdd(t *testing.T) {
	item1 := &TabItem{Text: "Test", Content: widget.NewLabel("Content")}
	item2 := &TabItem{Text: "Delete", Content: widget.NewLabel("Delete")}
	tabs := NewAppTabs(item1, item2)
	tabRenderer := cache.Renderer(tabs).(*appTabsRenderer)
	indicator := tabRenderer.indicator

	pos := indicator.Position()
	tabs.SelectTab(item2)
	assert.NotEqual(t, pos, indicator.Position())
	pos = indicator.Position()

	tabs.Remove(item2)
	tabs.Append(item2)
	tabs.SelectTab(item2)
	assert.Equal(t, pos, indicator.Position())
}

func Test_tabButtonRenderer_EmptyDeleteAdd(t *testing.T) {
	item1 := &TabItem{Text: "Test", Content: widget.NewLabel("Content")}
	tabs := NewAppTabs()

	// ensure enough space for buttons to be created.
	tabs.Resize(fyne.NewSize(300, 200))

	tabRenderer := cache.Renderer(tabs).(*appTabsRenderer)
	assert.Equal(t, 0, len(tabRenderer.bar.Objects[0].(*fyne.Container).Objects))

	tabs.Append(item1)
	assert.Equal(t, 1, len(tabRenderer.bar.Objects[0].(*fyne.Container).Objects))

	tabs.Remove(item1)
	assert.Equal(t, 0, len(tabRenderer.bar.Objects[0].(*fyne.Container).Objects))
}
Repository: fyne-io/fyne
File: widget/list.go (Go)

Code before:
	return newListRenderer(objects, l, l.scroller, layout)
}

// MinSize returns the size that this widget should not shrink below.
func (l *List) MinSize() fyne.Size {
	l.ExtendBaseWidget(l)

	return l.BaseWidget.MinSize()
}

func (l *List) refreshBase() (*listLayout, map[ListItemID]*listItem, fyne.Focusable) {
	if l.scroller != nil {
		l.BaseWidget.Refresh()
		lo := l.scroller.Content.(*fyne.Container).Layout.(*listLayout)
		visible := lo.visible
		canvas := fyne.CurrentApp().Driver().CanvasForObject(lo.list)
		var focused fyne.Focusable
		if canvas != nil {
			focused = canvas.Focused()
		}
		return lo, visible, focused
	}
	return nil, nil, nil
}

func (l *List) Refresh() {
	lo, visible, focused := l.refreshBase()
	for id, item := range visible {
		item.updated = false
		lo.setupListItem(item, id, focused == item)
	}
}

func (l *List) RefreshItem(id ListItemID) {
	lo, visible, focused := l.refreshBase()
	if item, ok := visible[id]; ok {
		lo.setupListItem(item, id, focused == item)
	}
}

// SetItemHeight supports changing the height of the specified list item. Items normally take the height of the template
// returned from the CreateItem callback. The height parameter uses the same units as a fyne.Size type and refers
// to the internal content height not including the divider size.
//
// Since: 2.3
func (l *List) SetItemHeight(id ListItemID, height float32) {
	l.propertyLock.Lock()

	if l.itemHeights == nil {
		l.itemHeights = make(map[ListItemID]float32)
	}

Review comment (suggestion):
By adding this function you are cutting out the existing Refresh work in the renderer (having overridden the BaseWidget.Refresh()).
Just looking at it this may lead to duplications, or could be redundant code in renderer now.

Code after:
	return newListRenderer(objects, l, l.scroller, layout)
}

// MinSize returns the size that this widget should not shrink below.
func (l *List) MinSize() fyne.Size {
	l.ExtendBaseWidget(l)

	return l.BaseWidget.MinSize()
}

// RefreshItem refreshes a single item, specified by the item ID passed in.
//
// Since: 2.4
func (l *List) RefreshItem(id ListItemID) {
	if l.scroller == nil {
		return
	}
	l.BaseWidget.Refresh()
	lo := l.scroller.Content.(*fyne.Container).Layout.(*listLayout)
	visible := lo.visible
	canvas := fyne.CurrentApp().Driver().CanvasForObject(lo.list)
	var focused fyne.Focusable
	if canvas != nil {
		focused = canvas.Focused()
	}
	if item, ok := visible[id]; ok {
		lo.setupListItem(item, id, focused == item)
	}
}

// SetItemHeight supports changing the height of the specified list item. Items normally take the height of the template
// returned from the CreateItem callback. The height parameter uses the same units as a fyne.Size type and refers
// to the internal content height not including the divider size.
//
// Since: 2.3
func (l *List) SetItemHeight(id ListItemID, height float32) {
	l.propertyLock.Lock()

	if l.itemHeights == nil {
		l.itemHeights = make(map[ListItemID]float32)
	}

	refresh := l.itemHeights[id] != height
	l.itemHeights[id] = height
	l.propertyLock.Unlock()

	if refresh {
		l.RefreshItem(id)
	}
}
Repository: fyne-io/fyne
File: widget/list.go (Go)

Code before:
	layout.Resize(layout.MinSize())
	objects := []fyne.CanvasObject{l.scroller}
	return newListRenderer(objects, l, l.scroller, layout)
}

// MinSize returns the size that this widget should not shrink below.
func (l *List) MinSize() fyne.Size {
	l.ExtendBaseWidget(l)

	return l.BaseWidget.MinSize()
}

func (l *List) RefreshItem(id ListItemID) {
	if l.scroller != nil {
		l.BaseWidget.Refresh()
		lo := l.scroller.Content.(*fyne.Container).Layout.(*listLayout)
		visible := lo.visible
		canvas := fyne.CurrentApp().Driver().CanvasForObject(lo.list)
		var focused fyne.Focusable
		if canvas != nil {
			focused = canvas.Focused()
		}
		if item, ok := visible[id]; ok {
			lo.setupListItem(item, id, focused == item)
		}
	}
}

// SetItemHeight supports changing the height of the specified list item. Items normally take the height of the template
// returned from the CreateItem callback. The height parameter uses the same units as a fyne.Size type and refers
// to the internal content height not including the divider size.
//
// Since: 2.3
func (l *List) SetItemHeight(id ListItemID, height float32) {
	l.propertyLock.Lock()

	if l.itemHeights == nil {
		l.itemHeights = make(map[ListItemID]float32)
	}

	refresh := l.itemHeights[id] != height
	l.itemHeights[id] = height
	l.propertyLock.Unlock()

	if refresh {
		l.RefreshItem(id)
	}
}

func (l *List) scrollTo(id ListItemID) {
	if l.scroller == nil {

Review comment (suggestion):
We prefer to keep the main code path not indented as it is a bit easier to read, i.e. you just put the if-statement on top:
```go
if l.scroller == nil {
    return
}
```

Code after:
	layout.Resize(layout.MinSize())
	objects := []fyne.CanvasObject{l.scroller}
	return newListRenderer(objects, l, l.scroller, layout)
}

// MinSize returns the size that this widget should not shrink below.
func (l *List) MinSize() fyne.Size {
	l.ExtendBaseWidget(l)

	return l.BaseWidget.MinSize()
}

// RefreshItem refreshes a single item, specified by the item ID passed in.
//
// Since: 2.4
func (l *List) RefreshItem(id ListItemID) {
	if l.scroller == nil {
		return
	}
	l.BaseWidget.Refresh()
	lo := l.scroller.Content.(*fyne.Container).Layout.(*listLayout)
	visible := lo.visible
	canvas := fyne.CurrentApp().Driver().CanvasForObject(lo.list)
	var focused fyne.Focusable
	if canvas != nil {
		focused = canvas.Focused()
	}
	if item, ok := visible[id]; ok {
		lo.setupListItem(item, id, focused == item)
	}
}

// SetItemHeight supports changing the height of the specified list item. Items normally take the height of the template
// returned from the CreateItem callback. The height parameter uses the same units as a fyne.Size type and refers
// to the internal content height not including the divider size.
//
// Since: 2.3
func (l *List) SetItemHeight(id ListItemID, height float32) {
	l.propertyLock.Lock()

	if l.itemHeights == nil {
		l.itemHeights = make(map[ListItemID]float32)
	}

	refresh := l.itemHeights[id] != height
	l.itemHeights[id] = height
	l.propertyLock.Unlock()

	if refresh {
		l.RefreshItem(id)
	}
Repository: fyne-io/fyne
File: internal/preferences.go (Go)

Code before:
var _ fyne.Preferences = (*InMemoryPreferences)(nil)

// AddChangeListener allows code to be notified when some preferences change. This will fire on any update.
// The passed 'listener' should not try to write values.
func (p *InMemoryPreferences) AddChangeListener(listener func()) {
	p.lock.Lock()
	defer p.lock.Unlock()

	p.changeListeners = append(p.changeListeners, listener)
}

// Bool looks up a boolean value for the key
func (p *InMemoryPreferences) Bool(key string) bool {
	return p.BoolWithFallback(key, false)
}

func (p *InMemoryPreferences) BoolList(key string) []bool {
	return p.BoolListWithFallback(key, []bool{})
}

func (p *InMemoryPreferences) BoolListWithFallback(key string, fallback []bool) []bool {
	value, ok := p.get(key)
	if !ok {
		return fallback
	}
	_, ok1 := value.([]bool)
	if !ok1 {
		return fallback
	}
	return value.([]bool)
}

// BoolWithFallback looks up a boolean value and returns the given fallback if not found
func (p *InMemoryPreferences) BoolWithFallback(key string, fallback bool) bool {
	value, ok := p.get(key)
	if !ok {
		return fallback
	}
	_, ok1 := value.(bool)
	if !ok1 {
		return fallback
	}
	return value.(bool)
}

// ChangeListeners returns the list of listeners registered for this set of preferences.
func (p *InMemoryPreferences) ChangeListeners() []func() {
	return p.changeListeners
}

// Float looks up a float64 value for the key

Review comment (suggestion):
There is no need to call this `ok1`. Just change it like this:
```go
	_, ok = value.([]bool)
```


Code after:
var _ fyne.Preferences = (*InMemoryPreferences)(nil)

// AddChangeListener allows code to be notified when some preferences change. This will fire on any update.
// The passed 'listener' should not try to write values.
func (p *InMemoryPreferences) AddChangeListener(listener func()) {
	p.lock.Lock()
	defer p.lock.Unlock()

	p.changeListeners = append(p.changeListeners, listener)
}

// Bool looks up a boolean value for the key
func (p *InMemoryPreferences) Bool(key string) bool {
	return p.BoolWithFallback(key, false)
}

func (p *InMemoryPreferences) BoolList(key string) []bool {
	return p.BoolListWithFallback(key, []bool{})
}

func (p *InMemoryPreferences) BoolListWithFallback(key string, fallback []bool) []bool {
	value, ok := p.get(key)
	if !ok {
		return fallback
	}
	valb, ok := value.([]bool)
	if !ok {
		return fallback
	}
	return valb
}

// BoolWithFallback looks up a boolean value and returns the given fallback if not found
func (p *InMemoryPreferences) BoolWithFallback(key string, fallback bool) bool {
	value, ok := p.get(key)
	if !ok {
		return fallback
	}
	valb, ok := value.(bool)
	if !ok {
		return fallback
	}
	return valb
}

// ChangeListeners returns the list of listeners registered for this set of preferences.
func (p *InMemoryPreferences) ChangeListeners() []func() {
	return p.changeListeners
}

// Float looks up a float64 value for the key