package ui import ( "sync" "time" "fyne.io/fyne/v2" ) type Debouncer struct { mu sync.Mutex timer *time.Timer duration time.Duration callback func() } func NewDebouncer(duration time.Duration, callback func()) *Debouncer { return &Debouncer{ duration: duration, callback: callback, } } func (d *Debouncer) Trigger() { d.mu.Lock() defer d.mu.Unlock() if d.timer != nil { d.timer.Stop() } d.timer = time.AfterFunc(d.duration, func() { fyne.Do(d.callback) }) } type Throttler struct { mu sync.Mutex lastCall time.Time interval time.Duration callback func() } func NewThrottler(interval time.Duration, callback func()) *Throttler { return &Throttler{ interval: interval, callback: callback, } } func (t *Throttler) Trigger() { t.mu.Lock() defer t.mu.Unlock() now := time.Now() if now.Sub(t.lastCall) >= t.interval { t.lastCall = now fyne.Do(t.callback) } } type LazyLoader struct { mu sync.Mutex loaded bool loading bool callback func() } func NewLazyLoader(callback func()) *LazyLoader { return &LazyLoader{ callback: callback, } } func (l *LazyLoader) Load() { l.mu.Lock() defer l.mu.Unlock() if l.loaded || l.loading { return } l.loading = true go func() { l.callback() l.mu.Lock() l.loaded = true l.loading = false l.mu.Unlock() }() } type VirtualList struct { items []interface{} renderer func(item interface{}) fyne.CanvasObject visible int start int end int } func NewVirtualList(items []interface{}, renderer func(item interface{}) fyne.CanvasObject, visible int) *VirtualList { return &VirtualList{ items: items, renderer: renderer, visible: visible, end: visible, } } func (vl *VirtualList) GetVisibleItems() []fyne.CanvasObject { if vl.start >= len(vl.items) { return []fyne.CanvasObject{} } if vl.end > len(vl.items) { vl.end = len(vl.items) } var result []fyne.CanvasObject for i := vl.start; i < vl.end; i++ { result = append(result, vl.renderer(vl.items[i])) } return result } func (vl *VirtualList) ScrollTo(index int) { if index < 0 { index = 0 } if index >= len(vl.items) { index = len(vl.items) - 1 } vl.start = index vl.end = index + vl.visible if vl.end > len(vl.items) { vl.end = len(vl.items) vl.start = vl.end - vl.visible if vl.start < 0 { vl.start = 0 } } } type MemoryPool struct { mu sync.Mutex items []interface{} new func() interface{} reset func(interface{}) } func NewMemoryPool(new func() interface{}, reset func(interface{})) *MemoryPool { return &MemoryPool{ new: new, reset: reset, } } func (mp *MemoryPool) Get() interface{} { mp.mu.Lock() defer mp.mu.Unlock() if len(mp.items) > 0 { item := mp.items[len(mp.items)-1] mp.items = mp.items[:len(mp.items)-1] mp.reset(item) return item } return mp.new() } func (mp *MemoryPool) Put(item interface{}) { mp.mu.Lock() defer mp.mu.Unlock() mp.items = append(mp.items, item) }