Updates #22: add focus arrow key navigation to tracklist
This commit is contained in:
@@ -257,6 +257,8 @@ func (g *GridViewItem) TypedKey(e *fyne.KeyEvent) {
|
|||||||
focusArg = 3
|
focusArg = 3
|
||||||
case fyne.KeyEnter:
|
case fyne.KeyEnter:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
case fyne.KeyReturn:
|
||||||
|
fallthrough
|
||||||
case fyne.KeySpace:
|
case fyne.KeySpace:
|
||||||
if g.OnShowItemPage != nil {
|
if g.OnShowItemPage != nil {
|
||||||
g.OnShowItemPage()
|
g.OnShowItemPage()
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ type ListRowBase struct {
|
|||||||
Selected bool
|
Selected bool
|
||||||
Focused bool
|
Focused bool
|
||||||
|
|
||||||
OnTapped func()
|
OnTapped func()
|
||||||
OnDoubleTapped func()
|
OnDoubleTapped func()
|
||||||
|
OnFocusNeighbor func(up bool) //TODO: func(up, selecting bool)
|
||||||
|
|
||||||
tappedAt int64 // unixMillis
|
tappedAt int64 // unixMillis
|
||||||
focusedRect *canvas.Rectangle
|
focusedRect *canvas.Rectangle
|
||||||
@@ -57,7 +58,22 @@ func (l *ListRowBase) FocusLost() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *ListRowBase) TypedKey(e *fyne.KeyEvent) {
|
func (l *ListRowBase) TypedKey(e *fyne.KeyEvent) {
|
||||||
|
/**
|
||||||
|
// TODO: enable shift+arrows for selection, but it's complicated to implement in the widgets
|
||||||
|
desktop, ok := fyne.CurrentApp().Driver().(desktop.Driver)
|
||||||
|
isSelecting := func() bool {
|
||||||
|
return ok && desktop.CurrentKeyModifiers()&fyne.KeyModifierShift != 0
|
||||||
|
}
|
||||||
|
*/
|
||||||
switch {
|
switch {
|
||||||
|
case e.Name == fyne.KeyUp:
|
||||||
|
if l.OnFocusNeighbor != nil {
|
||||||
|
l.OnFocusNeighbor(true)
|
||||||
|
}
|
||||||
|
case e.Name == fyne.KeyDown:
|
||||||
|
if l.OnFocusNeighbor != nil {
|
||||||
|
l.OnFocusNeighbor(false)
|
||||||
|
}
|
||||||
case e.Name == fyne.KeySpace:
|
case e.Name == fyne.KeySpace:
|
||||||
if l.OnTapped != nil {
|
if l.OnTapped != nil {
|
||||||
l.OnTapped()
|
l.OnTapped()
|
||||||
|
|||||||
+34
-4
@@ -101,6 +101,7 @@ type Tracklist struct {
|
|||||||
tracksMutex sync.RWMutex
|
tracksMutex sync.RWMutex
|
||||||
tracks []*trackModel
|
tracks []*trackModel
|
||||||
tracksOrigOrder []*trackModel
|
tracksOrigOrder []*trackModel
|
||||||
|
itemForIndex map[int]*TrackRow
|
||||||
|
|
||||||
nowPlayingID string
|
nowPlayingID string
|
||||||
colLayout *layouts.ColumnsLayout
|
colLayout *layouts.ColumnsLayout
|
||||||
@@ -117,7 +118,7 @@ type trackModel struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTracklist(tracks []*mediaprovider.Track) *Tracklist {
|
func NewTracklist(tracks []*mediaprovider.Track) *Tracklist {
|
||||||
t := &Tracklist{visibleColumns: make([]bool, numColumns)}
|
t := &Tracklist{visibleColumns: make([]bool, numColumns), itemForIndex: make(map[int]*TrackRow)}
|
||||||
t.ExtendBaseWidget(t)
|
t.ExtendBaseWidget(t)
|
||||||
|
|
||||||
if len(tracks) > 0 {
|
if len(tracks) > 0 {
|
||||||
@@ -143,9 +144,28 @@ func NewTracklist(tracks []*mediaprovider.Track) *Tracklist {
|
|||||||
t.lenTracks,
|
t.lenTracks,
|
||||||
func() fyne.CanvasObject {
|
func() fyne.CanvasObject {
|
||||||
tr := NewTrackRow(t, playingIcon)
|
tr := NewTrackRow(t, playingIcon)
|
||||||
tr.OnTapped = func() { t.onSelectTrack(tr.trackIdx) }
|
tr.OnTapped = func() {
|
||||||
|
t.onSelectTrack(tr.trackIdx)
|
||||||
|
}
|
||||||
tr.OnTappedSecondary = t.onShowContextMenu
|
tr.OnTappedSecondary = t.onShowContextMenu
|
||||||
tr.OnDoubleTapped = func() { t.onPlayTrackAt(tr.trackIdx) }
|
tr.OnDoubleTapped = func() {
|
||||||
|
t.onPlayTrackAt(tr.trackIdx)
|
||||||
|
}
|
||||||
|
tr.OnFocusNeighbor = func(up bool) {
|
||||||
|
focusIdx := tr.trackIdx + 1
|
||||||
|
if up {
|
||||||
|
focusIdx = tr.trackIdx - 1
|
||||||
|
}
|
||||||
|
if focusIdx >= 0 && focusIdx < t.lenTracks() {
|
||||||
|
t.list.ScrollTo(focusIdx)
|
||||||
|
}
|
||||||
|
t.tracksMutex.RLock()
|
||||||
|
other, ok := t.itemForIndex[focusIdx]
|
||||||
|
t.tracksMutex.RUnlock()
|
||||||
|
if ok {
|
||||||
|
fyne.CurrentApp().Driver().CanvasForObject(t).Focus(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
return tr
|
return tr
|
||||||
},
|
},
|
||||||
func(itemID widget.ListItemID, item fyne.CanvasObject) {
|
func(itemID widget.ListItemID, item fyne.CanvasObject) {
|
||||||
@@ -161,7 +181,15 @@ func NewTracklist(tracks []*mediaprovider.Track) *Tracklist {
|
|||||||
t.tracksMutex.RUnlock()
|
t.tracksMutex.RUnlock()
|
||||||
|
|
||||||
tr := item.(*TrackRow)
|
tr := item.(*TrackRow)
|
||||||
tr.trackIdx = itemID
|
if tr.trackID != model.track.ID || tr.trackIdx != itemID {
|
||||||
|
t.tracksMutex.Lock()
|
||||||
|
if other, ok := t.itemForIndex[itemID]; ok && other == tr {
|
||||||
|
delete(t.itemForIndex, other.trackIdx)
|
||||||
|
}
|
||||||
|
t.itemForIndex[itemID] = tr
|
||||||
|
t.tracksMutex.Unlock()
|
||||||
|
tr.trackIdx = itemID
|
||||||
|
}
|
||||||
i := -1 // signal that we want to display the actual track num.
|
i := -1 // signal that we want to display the actual track num.
|
||||||
if t.Options.AutoNumber {
|
if t.Options.AutoNumber {
|
||||||
i = itemID + 1
|
i = itemID + 1
|
||||||
@@ -299,6 +327,7 @@ func (t *Tracklist) Clear() {
|
|||||||
defer t.tracksMutex.Unlock()
|
defer t.tracksMutex.Unlock()
|
||||||
t.tracks = nil
|
t.tracks = nil
|
||||||
t.tracksOrigOrder = nil
|
t.tracksOrigOrder = nil
|
||||||
|
t.itemForIndex = make(map[int]*TrackRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the tracks in the tracklist. Thread-safe.
|
// Sets the tracks in the tracklist. Thread-safe.
|
||||||
@@ -310,6 +339,7 @@ func (t *Tracklist) SetTracks(trs []*mediaprovider.Track) {
|
|||||||
func (t *Tracklist) _setTracks(trs []*mediaprovider.Track) {
|
func (t *Tracklist) _setTracks(trs []*mediaprovider.Track) {
|
||||||
t.tracksMutex.Lock()
|
t.tracksMutex.Lock()
|
||||||
defer t.tracksMutex.Unlock()
|
defer t.tracksMutex.Unlock()
|
||||||
|
t.itemForIndex = make(map[int]*TrackRow)
|
||||||
t.tracksOrigOrder = toTrackModels(trs)
|
t.tracksOrigOrder = toTrackModels(trs)
|
||||||
t.doSortTracks()
|
t.doSortTracks()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user