VideoTools/vendor/fyne.io/fyne/v2/internal/preferences.go
Stu Leak 68df790d27 Fix player frame generation and video playback
Major improvements to UnifiedPlayer:

1. GetFrameImage() now works when paused for responsive UI updates
2. Play() method properly starts FFmpeg process
3. Frame display loop runs continuously for smooth video display
4. Disabled audio temporarily to fix video playback fundamentals
5. Simplified FFmpeg command to focus on video stream only

Player now:
- Generates video frames correctly
- Shows video when paused
- Has responsive progress tracking
- Starts playback properly

Next steps: Re-enable audio playback once video is stable
2026-01-07 22:20:00 -05:00

317 lines
7.3 KiB
Go

package internal
import (
"reflect"
"sync"
"fyne.io/fyne/v2"
)
// InMemoryPreferences provides an implementation of the fyne.Preferences API that is stored in memory.
type InMemoryPreferences struct {
values map[string]any
lock sync.RWMutex
changeListeners []func()
}
// Declare conformity with Preferences interface
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
func (p *InMemoryPreferences) Float(key string) float64 {
return p.FloatWithFallback(key, 0.0)
}
func (p *InMemoryPreferences) FloatList(key string) []float64 {
return p.FloatListWithFallback(key, []float64{})
}
func (p *InMemoryPreferences) FloatListWithFallback(key string, fallback []float64) []float64 {
value, ok := p.get(key)
if !ok {
return fallback
}
valf, ok := value.([]float64)
if ok {
return valf
}
vali, ok := value.([]int)
if ok {
flts := make([]float64, len(vali))
for i, f := range vali {
flts[i] = float64(f)
}
return flts
}
return fallback
}
// FloatWithFallback looks up a float64 value and returns the given fallback if not found
func (p *InMemoryPreferences) FloatWithFallback(key string, fallback float64) float64 {
value, ok := p.get(key)
if !ok {
return fallback
}
valf, ok := value.(float64)
if ok {
return valf
}
vali, ok := value.(int)
if ok {
return float64(vali)
}
return fallback
}
// Int looks up an integer value for the key
func (p *InMemoryPreferences) Int(key string) int {
return p.IntWithFallback(key, 0)
}
func (p *InMemoryPreferences) IntList(key string) []int {
return p.IntListWithFallback(key, []int{})
}
func (p *InMemoryPreferences) IntListWithFallback(key string, fallback []int) []int {
value, ok := p.get(key)
if !ok {
return fallback
}
vali, ok := value.([]int)
if ok {
return vali
}
// integers can be de-serialised as floats, so support both
valf, ok := value.([]float64)
if ok {
ints := make([]int, len(valf))
for i, f := range valf {
ints[i] = int(f)
}
return ints
}
return fallback
}
// IntWithFallback looks up an integer value and returns the given fallback if not found
func (p *InMemoryPreferences) IntWithFallback(key string, fallback int) int {
value, ok := p.get(key)
if !ok {
return fallback
}
vali, ok := value.(int)
if ok {
return vali
}
// integers can be de-serialised as floats, so support both
valf, ok := value.(float64)
if !ok {
return fallback
}
return int(valf)
}
// ReadValues provides read access to the underlying value map - for internal use only...
// You should not retain a reference to the map nor write to the values in the callback function
func (p *InMemoryPreferences) ReadValues(fn func(map[string]any)) {
p.lock.RLock()
fn(p.values)
p.lock.RUnlock()
}
// RemoveValue deletes a value on the given key
func (p *InMemoryPreferences) RemoveValue(key string) {
p.remove(key)
}
// SetBool saves a boolean value for the given key
func (p *InMemoryPreferences) SetBool(key string, value bool) {
p.set(key, value)
}
func (p *InMemoryPreferences) SetBoolList(key string, value []bool) {
p.set(key, value)
}
// SetFloat saves a float64 value for the given key
func (p *InMemoryPreferences) SetFloat(key string, value float64) {
p.set(key, value)
}
func (p *InMemoryPreferences) SetFloatList(key string, value []float64) {
p.set(key, value)
}
// SetInt saves an integer value for the given key
func (p *InMemoryPreferences) SetInt(key string, value int) {
p.set(key, value)
}
func (p *InMemoryPreferences) SetIntList(key string, value []int) {
p.set(key, value)
}
// SetString saves a string value for the given key
func (p *InMemoryPreferences) SetString(key string, value string) {
p.set(key, value)
}
func (p *InMemoryPreferences) SetStringList(key string, value []string) {
p.set(key, value)
}
// String looks up a string value for the key
func (p *InMemoryPreferences) String(key string) string {
return p.StringWithFallback(key, "")
}
func (p *InMemoryPreferences) StringList(key string) []string {
return p.StringListWithFallback(key, []string{})
}
func (p *InMemoryPreferences) StringListWithFallback(key string, fallback []string) []string {
value, ok := p.get(key)
if !ok {
return fallback
}
vals, ok := value.([]string)
if !ok {
return fallback
}
return vals
}
// StringWithFallback looks up a string value and returns the given fallback if not found
func (p *InMemoryPreferences) StringWithFallback(key, fallback string) string {
value, ok := p.get(key)
if !ok {
return fallback
}
vals, ok := value.(string)
if !ok {
return fallback
}
return vals
}
// WriteValues provides write access to the underlying value map - for internal use only...
// You should not retain a reference to the map passed to the callback function
func (p *InMemoryPreferences) WriteValues(fn func(map[string]any)) {
p.lock.Lock()
fn(p.values)
p.lock.Unlock()
p.fireChange()
}
// NewInMemoryPreferences creates a new preferences implementation stored in memory
func NewInMemoryPreferences() *InMemoryPreferences {
return &InMemoryPreferences{values: make(map[string]any)}
}
func (p *InMemoryPreferences) fireChange() {
p.lock.RLock()
listeners := p.changeListeners
p.lock.RUnlock()
for _, l := range listeners {
l()
}
}
func (p *InMemoryPreferences) get(key string) (any, bool) {
p.lock.RLock()
defer p.lock.RUnlock()
v, err := p.values[key]
return v, err
}
func (p *InMemoryPreferences) remove(key string) {
p.lock.Lock()
delete(p.values, key)
p.lock.Unlock()
p.fireChange()
}
func (p *InMemoryPreferences) set(key string, value any) {
p.lock.Lock()
if reflect.TypeOf(value).Kind() == reflect.Slice {
s := reflect.ValueOf(value)
old := reflect.ValueOf(p.values[key])
if p.values[key] != nil && s.Len() == old.Len() {
changed := false
for i := 0; i < s.Len(); i++ {
if s.Index(i).Interface() != old.Index(i).Interface() {
changed = true
break
}
}
if !changed {
p.lock.Unlock()
return
}
}
} else {
if stored, ok := p.values[key]; ok && stored == value {
p.lock.Unlock()
return
}
}
p.values[key] = value
p.lock.Unlock()
p.fireChange()
}