@@ -8,8 +8,9 @@ require (
|
|||||||
github.com/Microsoft/go-winio v0.6.2
|
github.com/Microsoft/go-winio v0.6.2
|
||||||
github.com/cenkalti/dominantcolor v1.0.3
|
github.com/cenkalti/dominantcolor v1.0.3
|
||||||
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1
|
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1
|
||||||
github.com/dweymouth/fyne-advanced-list v0.0.0-20240623145729-9c6b8f99bcfe
|
github.com/dweymouth/fyne-advanced-list v0.0.0-20240806013530-392de9d6a2a1
|
||||||
github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64
|
github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64
|
||||||
|
github.com/dweymouth/fyne-tooltip v0.2.0
|
||||||
github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645
|
github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645
|
||||||
github.com/dweymouth/go-mpv v0.0.0-20240724002347-c5e5b36f1bbf
|
github.com/dweymouth/go-mpv v0.0.0-20240724002347-c5e5b36f1bbf
|
||||||
github.com/dweymouth/go-subsonic v0.0.0-20240726004217-2e8e348ad417
|
github.com/dweymouth/go-subsonic v0.0.0-20240726004217-2e8e348ad417
|
||||||
@@ -53,4 +54,4 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace fyne.io/fyne/v2 v2.5.0 => github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20240728183020-7abcad1f4139
|
replace fyne.io/fyne/v2 v2.5.0 => github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20240805144743-24df77c3cc7e
|
||||||
|
|||||||
@@ -75,12 +75,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1 h1:mGvOb3zxl4vCLv+dbf7JA6CAaM2UH/AGP1KX4DsJmTI=
|
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1 h1:mGvOb3zxl4vCLv+dbf7JA6CAaM2UH/AGP1KX4DsJmTI=
|
||||||
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1/go.mod h1:ZNCLJfehvEf34B7BbLKjgpsL9lyW7q938w/GY1XgV4E=
|
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1/go.mod h1:ZNCLJfehvEf34B7BbLKjgpsL9lyW7q938w/GY1XgV4E=
|
||||||
github.com/dweymouth/fyne-advanced-list v0.0.0-20240623145729-9c6b8f99bcfe h1:owGwqph+Y+PqjDiWjZjOFOhlo8QsLs+LHrHojaaBo34=
|
github.com/dweymouth/fyne-advanced-list v0.0.0-20240806013530-392de9d6a2a1 h1:NTiWy47NaM2WoJ4Rjlx/4QmtHpNLl6ujptmIirDJ9vk=
|
||||||
github.com/dweymouth/fyne-advanced-list v0.0.0-20240623145729-9c6b8f99bcfe/go.mod h1:sbOhla4VcfFb4OjXiUFTLXMPTnhRUlVrDMhB8HtWR4o=
|
github.com/dweymouth/fyne-advanced-list v0.0.0-20240806013530-392de9d6a2a1/go.mod h1:sbOhla4VcfFb4OjXiUFTLXMPTnhRUlVrDMhB8HtWR4o=
|
||||||
github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64 h1:RUIrnGY034rDMlcOui/daurwX5b+52KdUKhH9aXaDSg=
|
github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64 h1:RUIrnGY034rDMlcOui/daurwX5b+52KdUKhH9aXaDSg=
|
||||||
github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64/go.mod h1:3YrjFDHMlhCsSZ/OvmJCxWm9QHSgOVWZBxnraZz9Z7c=
|
github.com/dweymouth/fyne-lyrics v0.0.0-20240528234907-15eee7ce5e64/go.mod h1:3YrjFDHMlhCsSZ/OvmJCxWm9QHSgOVWZBxnraZz9Z7c=
|
||||||
github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20240728183020-7abcad1f4139 h1:JNOd+yJlurYrdAuOiibR6/EYl+/+idFkk+wwyXiNwIQ=
|
github.com/dweymouth/fyne-tooltip v0.2.0 h1:6Zy3gryctuPoQfYf8Xp3tjenioebMt11NBGW/QXIvxE=
|
||||||
github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20240728183020-7abcad1f4139/go.mod h1:9D4oT3NWeG+MLi/lP7ItZZyujHC/qqMJpoGTAYX5Uqc=
|
github.com/dweymouth/fyne-tooltip v0.2.0/go.mod h1:zEgy7p9tSVIuy2GufFbOCoK3Q04zhyDPOotlU4G3Ma4=
|
||||||
|
github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20240805144743-24df77c3cc7e h1:FSTLNY9xV0+4/x9jKPXqUpwPZfhkAMz5ZnzLBkRirMw=
|
||||||
|
github.com/dweymouth/fyne/v2 v2.3.0-rc1.0.20240805144743-24df77c3cc7e/go.mod h1:9D4oT3NWeG+MLi/lP7ItZZyujHC/qqMJpoGTAYX5Uqc=
|
||||||
github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645 h1:KzqSaQwG3HsTZQlEtkp0BeUy9vmYZ0rq0B15qIPSiBs=
|
github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645 h1:KzqSaQwG3HsTZQlEtkp0BeUy9vmYZ0rq0B15qIPSiBs=
|
||||||
github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645/go.mod h1:fcUagHBaQnt06GmBAllNE0J4O/7064zXRWdqnTTtVjI=
|
github.com/dweymouth/go-jellyfin v0.0.0-20240517151952-5ceca61cb645/go.mod h1:fcUagHBaQnt06GmBAllNE0J4O/7064zXRWdqnTTtVjI=
|
||||||
github.com/dweymouth/go-mpv v0.0.0-20240724002347-c5e5b36f1bbf h1:QVjXWx7XGkSPOCEu5EL9QVY3fkdDSnG5KEkok5o1svM=
|
github.com/dweymouth/go-mpv v0.0.0-20240724002347-c5e5b36f1bbf h1:QVjXWx7XGkSPOCEu5EL9QVY3fkdDSnG5KEkok5o1svM=
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
"Authentication failed": "Authentication failed",
|
"Authentication failed": "Authentication failed",
|
||||||
"Auto": "Auto",
|
"Auto": "Auto",
|
||||||
"Autoselect device": "Autoselect device",
|
"Autoselect device": "Autoselect device",
|
||||||
|
"Back": "Back",
|
||||||
"Bit rate": "Bit rate",
|
"Bit rate": "Bit rate",
|
||||||
"BPM": "BPM",
|
"BPM": "BPM",
|
||||||
"Broadcast": "Broadcast",
|
"Broadcast": "Broadcast",
|
||||||
@@ -73,7 +74,9 @@
|
|||||||
"Field Recording": "Field Recording",
|
"Field Recording": "Field Recording",
|
||||||
"File path": "File path",
|
"File path": "File path",
|
||||||
"File size": "File size",
|
"File size": "File size",
|
||||||
|
"Filter albums": "Filter albums",
|
||||||
"Filter genres": "Filter genres",
|
"Filter genres": "Filter genres",
|
||||||
|
"Forward": "Forward",
|
||||||
"Frequently Played": "Frequently Played",
|
"Frequently Played": "Frequently Played",
|
||||||
"General": "General",
|
"General": "General",
|
||||||
"Genre": "Genre",
|
"Genre": "Genre",
|
||||||
@@ -81,6 +84,7 @@
|
|||||||
"Github page": "Github page",
|
"Github page": "Github page",
|
||||||
"Go to release page": "Go to release page",
|
"Go to release page": "Go to release page",
|
||||||
"Hide": "Hide",
|
"Hide": "Hide",
|
||||||
|
"Home": "Home",
|
||||||
"Home Page": "Home Page",
|
"Home Page": "Home Page",
|
||||||
"hr": "hr",
|
"hr": "hr",
|
||||||
"hrs": "hrs",
|
"hrs": "hrs",
|
||||||
@@ -95,9 +99,11 @@
|
|||||||
"Login to Server": "Login to Server",
|
"Login to Server": "Login to Server",
|
||||||
"Lyrics": "Lyrics",
|
"Lyrics": "Lyrics",
|
||||||
"Lyrics not available": "Lyrics not available",
|
"Lyrics not available": "Lyrics not available",
|
||||||
|
"Menu": "Menu",
|
||||||
"min": "min",
|
"min": "min",
|
||||||
"minutes of track have been played": "minutes of track have been played",
|
"minutes of track have been played": "minutes of track have been played",
|
||||||
"Mixtape": "Mixtape",
|
"Mixtape": "Mixtape",
|
||||||
|
"Mute": "Mute",
|
||||||
"My Server": "My Server",
|
"My Server": "My Server",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"Name (A-Z)": "Name (A-Z)",
|
"Name (A-Z)": "Name (A-Z)",
|
||||||
@@ -139,6 +145,7 @@
|
|||||||
"Recently Added": "Recently Added",
|
"Recently Added": "Recently Added",
|
||||||
"Recently Played": "Recently Played",
|
"Recently Played": "Recently Played",
|
||||||
"Related": "Related",
|
"Related": "Related",
|
||||||
|
"Reload": "Reload",
|
||||||
"Remix": "Remix",
|
"Remix": "Remix",
|
||||||
"Remove from playlist": "Remove from playlist",
|
"Remove from playlist": "Remove from playlist",
|
||||||
"ReplayGain mode": "ReplayGain mode",
|
"ReplayGain mode": "ReplayGain mode",
|
||||||
@@ -163,6 +170,7 @@
|
|||||||
"Show": "Show",
|
"Show": "Show",
|
||||||
"Show info": "Show info",
|
"Show info": "Show info",
|
||||||
"Show notification on track change": "Show notification on track change",
|
"Show notification on track change": "Show notification on track change",
|
||||||
|
"Show play queue": "Show play queue",
|
||||||
"Show year in album grid cards": "Show year in album grid cards",
|
"Show year in album grid cards": "Show year in album grid cards",
|
||||||
"Shuffle": "Shuffle",
|
"Shuffle": "Shuffle",
|
||||||
"Shuffle albums": "Shuffle albums",
|
"Shuffle albums": "Shuffle albums",
|
||||||
|
|||||||
+25
-15
@@ -3,6 +3,7 @@ package browsing
|
|||||||
import (
|
import (
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
@@ -11,6 +12,8 @@ import (
|
|||||||
"github.com/dweymouth/supersonic/ui/controller"
|
"github.com/dweymouth/supersonic/ui/controller"
|
||||||
"github.com/dweymouth/supersonic/ui/layouts"
|
"github.com/dweymouth/supersonic/ui/layouts"
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
|
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Page interface {
|
type Page interface {
|
||||||
@@ -60,14 +63,14 @@ type BrowsingPane struct {
|
|||||||
|
|
||||||
curPage Page
|
curPage Page
|
||||||
|
|
||||||
home *widget.Button
|
home *ttwidget.Button
|
||||||
forward *widget.Button
|
forward *ttwidget.Button
|
||||||
back *widget.Button
|
back *ttwidget.Button
|
||||||
reload *widget.Button
|
reload *ttwidget.Button
|
||||||
history []SavedPage
|
history []SavedPage
|
||||||
historyIdx int
|
historyIdx int
|
||||||
|
|
||||||
settingsBtn *widget.Button
|
settingsBtn *ttwidget.Button
|
||||||
settingsMenu *fyne.Menu
|
settingsMenu *fyne.Menu
|
||||||
navBtnsContainer *fyne.Container
|
navBtnsContainer *fyne.Container
|
||||||
pageContainer *fyne.Container
|
pageContainer *fyne.Container
|
||||||
@@ -78,22 +81,28 @@ type BrowsingPane struct {
|
|||||||
func NewBrowsingPane(app *backend.App, contr *controller.Controller, onGoHome func()) *BrowsingPane {
|
func NewBrowsingPane(app *backend.App, contr *controller.Controller, onGoHome func()) *BrowsingPane {
|
||||||
b := &BrowsingPane{app: app}
|
b := &BrowsingPane{app: app}
|
||||||
b.ExtendBaseWidget(b)
|
b.ExtendBaseWidget(b)
|
||||||
b.home = widget.NewButtonWithIcon("", theme.HomeIcon(), onGoHome)
|
b.home = ttwidget.NewButtonWithIcon("", theme.HomeIcon(), onGoHome)
|
||||||
b.back = widget.NewButtonWithIcon("", theme.NavigateBackIcon(), b.GoBack)
|
b.home.SetToolTip(lang.L("Home"))
|
||||||
b.forward = widget.NewButtonWithIcon("", theme.NavigateNextIcon(), b.GoForward)
|
b.back = ttwidget.NewButtonWithIcon("", theme.NavigateBackIcon(), b.GoBack)
|
||||||
b.reload = widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), b.Reload)
|
b.back.SetToolTip(lang.L("Back"))
|
||||||
|
b.forward = ttwidget.NewButtonWithIcon("", theme.NavigateNextIcon(), b.GoForward)
|
||||||
|
b.forward.SetToolTip(lang.L("Forward"))
|
||||||
|
b.reload = ttwidget.NewButtonWithIcon("", theme.ViewRefreshIcon(), b.Reload)
|
||||||
|
b.reload.SetToolTip(lang.L("Reload"))
|
||||||
b.app.PlaybackManager.OnSongChange(b.onSongChange)
|
b.app.PlaybackManager.OnSongChange(b.onSongChange)
|
||||||
b.app.PlaybackManager.OnPlayTimeUpdate(b.onPlayTimeUpdate)
|
b.app.PlaybackManager.OnPlayTimeUpdate(b.onPlayTimeUpdate)
|
||||||
b.app.PlaybackManager.OnQueueChange(b.onQueueChange)
|
b.app.PlaybackManager.OnQueueChange(b.onQueueChange)
|
||||||
bkgrnd := myTheme.NewThemedRectangle(myTheme.ColorNamePageBackground)
|
bkgrnd := myTheme.NewThemedRectangle(myTheme.ColorNamePageBackground)
|
||||||
b.pageContainer = container.NewStack(bkgrnd, layout.NewSpacer())
|
b.pageContainer = container.NewStack(bkgrnd, layout.NewSpacer())
|
||||||
b.settingsBtn = widget.NewButtonWithIcon("", theme.SettingsIcon(), func() {
|
b.settingsBtn = ttwidget.NewButtonWithIcon("", theme.SettingsIcon(), func() {
|
||||||
p := widget.NewPopUpMenu(b.settingsMenu,
|
p := widget.NewPopUpMenu(b.settingsMenu,
|
||||||
fyne.CurrentApp().Driver().CanvasForObject(b.settingsBtn))
|
fyne.CurrentApp().Driver().CanvasForObject(b.settingsBtn))
|
||||||
p.ShowAtPosition(fyne.NewPos(b.Size().Width-p.MinSize().Width+4,
|
p.ShowAtPosition(fyne.NewPos(b.Size().Width-p.MinSize().Width+4,
|
||||||
b.navBtnsContainer.MinSize().Height+theme.Padding()))
|
b.navBtnsContainer.MinSize().Height+theme.Padding()))
|
||||||
})
|
})
|
||||||
quickSearchBtn := widget.NewButtonWithIcon("", theme.SearchIcon(), contr.ShowQuickSearch)
|
b.settingsBtn.SetToolTip(lang.L("Menu"))
|
||||||
|
quickSearchBtn := ttwidget.NewButtonWithIcon("", theme.SearchIcon(), contr.ShowQuickSearch)
|
||||||
|
quickSearchBtn.SetToolTip(lang.L("Search Everywhere"))
|
||||||
b.settingsMenu = fyne.NewMenu("")
|
b.settingsMenu = fyne.NewMenu("")
|
||||||
b.navBtnsContainer = container.NewHBox()
|
b.navBtnsContainer = container.NewHBox()
|
||||||
b.navBtnsPageMap = map[controller.PageName]fyne.Resource{}
|
b.navBtnsPageMap = map[controller.PageName]fyne.Resource{}
|
||||||
@@ -146,10 +155,11 @@ func (b *BrowsingPane) AddSettingsMenuSeparator() {
|
|||||||
fyne.NewMenuItemSeparator())
|
fyne.NewMenuItemSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BrowsingPane) AddNavigationButton(icon fyne.Resource, pageName controller.PageName, action func()) *widget.Button {
|
func (b *BrowsingPane) AddNavigationButton(icon fyne.Resource, pageName controller.PageName, action func()) *ttwidget.Button {
|
||||||
// make a copy of the icon, because it can change the color
|
// make a copy of the icon, because it can change the color
|
||||||
browsingPaneIcon := theme.NewThemedResource(icon)
|
browsingPaneIcon := theme.NewThemedResource(icon)
|
||||||
btn := widget.NewButtonWithIcon("", browsingPaneIcon, action)
|
btn := ttwidget.NewButtonWithIcon("", browsingPaneIcon, action)
|
||||||
|
btn.SetToolTip(lang.L(pageName.String()))
|
||||||
b.navBtnsContainer.Add(btn)
|
b.navBtnsContainer.Add(btn)
|
||||||
b.navBtnsPageMap[pageName] = browsingPaneIcon
|
b.navBtnsPageMap[pageName] = browsingPaneIcon
|
||||||
return btn
|
return btn
|
||||||
@@ -157,13 +167,13 @@ func (b *BrowsingPane) AddNavigationButton(icon fyne.Resource, pageName controll
|
|||||||
|
|
||||||
func (b *BrowsingPane) DisableNavigationButtons() {
|
func (b *BrowsingPane) DisableNavigationButtons() {
|
||||||
for _, obj := range b.navBtnsContainer.Objects {
|
for _, obj := range b.navBtnsContainer.Objects {
|
||||||
obj.(*widget.Button).Disable()
|
obj.(fyne.Disableable).Disable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BrowsingPane) EnableNavigationButtons() {
|
func (b *BrowsingPane) EnableNavigationButtons() {
|
||||||
for _, obj := range b.navBtnsContainer.Objects {
|
for _, obj := range b.navBtnsContainer.Objects {
|
||||||
obj.(*widget.Button).Enable()
|
obj.(fyne.Disableable).Enable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-27
@@ -14,6 +14,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
fynetooltip "github.com/dweymouth/fyne-tooltip"
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/backend/player"
|
"github.com/dweymouth/supersonic/backend/player"
|
||||||
@@ -49,7 +50,8 @@ type Controller struct {
|
|||||||
RefreshPageFunc func()
|
RefreshPageFunc func()
|
||||||
|
|
||||||
popUpQueueMutex sync.Mutex
|
popUpQueueMutex sync.Mutex
|
||||||
popUpQueue *widgets.PlayQueueList
|
popUpQueue *widget.PopUp
|
||||||
|
popUpQueueList *widgets.PlayQueueList
|
||||||
popUpQueueLastUsed int64
|
popUpQueueLastUsed int64
|
||||||
escapablePopUp *widget.PopUp
|
escapablePopUp *widget.PopUp
|
||||||
haveModal bool
|
haveModal bool
|
||||||
@@ -64,18 +66,22 @@ func New(app *backend.App, appVersion string, mainWindow fyne.Window) *Controlle
|
|||||||
}
|
}
|
||||||
c.initVisualizations()
|
c.initVisualizations()
|
||||||
c.App.PlaybackManager.OnQueueChange(func() {
|
c.App.PlaybackManager.OnQueueChange(func() {
|
||||||
|
c.popUpQueueMutex.Lock()
|
||||||
|
defer c.popUpQueueMutex.Unlock()
|
||||||
if c.popUpQueue != nil {
|
if c.popUpQueue != nil {
|
||||||
c.popUpQueue.SetItems(c.App.PlaybackManager.GetPlayQueue())
|
c.popUpQueueList.SetItems(c.App.PlaybackManager.GetPlayQueue())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
c.App.PlaybackManager.OnSongChange(func(track mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
c.App.PlaybackManager.OnSongChange(func(track mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
||||||
|
c.popUpQueueMutex.Lock()
|
||||||
|
defer c.popUpQueueMutex.Unlock()
|
||||||
if c.popUpQueue == nil {
|
if c.popUpQueue == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if track == nil {
|
if track == nil {
|
||||||
c.popUpQueue.SetNowPlaying("")
|
c.popUpQueueList.SetNowPlaying("")
|
||||||
} else {
|
} else {
|
||||||
c.popUpQueue.SetNowPlaying(track.Metadata().ID)
|
c.popUpQueueList.SetNowPlaying(track.Metadata().ID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return c
|
return c
|
||||||
@@ -115,10 +121,28 @@ func (m *Controller) HaveModal() bool {
|
|||||||
func (m *Controller) ShowPopUpPlayQueue() {
|
func (m *Controller) ShowPopUpPlayQueue() {
|
||||||
m.popUpQueueMutex.Lock()
|
m.popUpQueueMutex.Lock()
|
||||||
if m.popUpQueue == nil {
|
if m.popUpQueue == nil {
|
||||||
m.popUpQueue = widgets.NewPlayQueueList(m.App.ImageManager, false)
|
m.popUpQueueList = widgets.NewPlayQueueList(m.App.ImageManager, false)
|
||||||
m.popUpQueue.Reorderable = true
|
m.popUpQueueList.Reorderable = true
|
||||||
m.popUpQueue.SetItems(m.App.PlaybackManager.GetPlayQueue())
|
m.popUpQueueList.SetItems(m.App.PlaybackManager.GetPlayQueue())
|
||||||
m.ConnectPlayQueuelistActions(m.popUpQueue)
|
m.ConnectPlayQueuelistActions(m.popUpQueueList)
|
||||||
|
|
||||||
|
title := widget.NewRichTextWithText(lang.L("Play Queue"))
|
||||||
|
title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter
|
||||||
|
title.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = true
|
||||||
|
ctr := container.NewBorder(title, nil, nil, nil,
|
||||||
|
container.NewPadded(m.popUpQueueList),
|
||||||
|
)
|
||||||
|
m.popUpQueue = widget.NewPopUp(ctr, m.MainWindow.Canvas())
|
||||||
|
fynetooltip.AddPopUpToolTipLayer(m.popUpQueue)
|
||||||
|
|
||||||
|
container.NewThemeOverride(m.popUpQueue, myTheme.WithColorTransformOverride(
|
||||||
|
theme.ColorNameOverlayBackground,
|
||||||
|
func(c color.Color) color.Color {
|
||||||
|
c_ := c.(color.NRGBA)
|
||||||
|
c_.A = 245
|
||||||
|
return c_
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
// free popUpQueue if it hasn't been used in awhile
|
// free popUpQueue if it hasn't been used in awhile
|
||||||
go func() {
|
go func() {
|
||||||
@@ -127,7 +151,9 @@ func (m *Controller) ShowPopUpPlayQueue() {
|
|||||||
m.popUpQueueMutex.Lock()
|
m.popUpQueueMutex.Lock()
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
if m.popUpQueueLastUsed < now-120_000 /*2 min*/ {
|
if m.popUpQueueLastUsed < now-120_000 /*2 min*/ {
|
||||||
|
fynetooltip.DestroyPopUpToolTipLayer(m.popUpQueue)
|
||||||
m.popUpQueue = nil
|
m.popUpQueue = nil
|
||||||
|
m.popUpQueueList = nil
|
||||||
m.popUpQueueLastUsed = 0
|
m.popUpQueueLastUsed = 0
|
||||||
m.popUpQueueMutex.Unlock()
|
m.popUpQueueMutex.Unlock()
|
||||||
t.Stop()
|
t.Stop()
|
||||||
@@ -138,31 +164,17 @@ func (m *Controller) ShowPopUpPlayQueue() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
m.popUpQueueLastUsed = time.Now().UnixMilli()
|
m.popUpQueueLastUsed = time.Now().UnixMilli()
|
||||||
popUpQueue := m.popUpQueue
|
popUpQueueList := m.popUpQueueList
|
||||||
|
pop := m.popUpQueue
|
||||||
m.popUpQueueMutex.Unlock()
|
m.popUpQueueMutex.Unlock()
|
||||||
|
|
||||||
npID := ""
|
npID := ""
|
||||||
if np := m.App.PlaybackManager.NowPlaying(); np != nil {
|
if np := m.App.PlaybackManager.NowPlaying(); np != nil {
|
||||||
npID = np.Metadata().ID
|
npID = np.Metadata().ID
|
||||||
}
|
}
|
||||||
popUpQueue.SetNowPlaying(npID)
|
popUpQueueList.SetNowPlaying(npID)
|
||||||
popUpQueue.UnselectAll()
|
popUpQueueList.UnselectAll()
|
||||||
|
|
||||||
title := widget.NewRichTextWithText(lang.L("Play Queue"))
|
|
||||||
title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter
|
|
||||||
title.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = true
|
|
||||||
ctr := container.NewBorder(title, nil, nil, nil,
|
|
||||||
container.NewPadded(m.popUpQueue),
|
|
||||||
)
|
|
||||||
pop := widget.NewPopUp(ctr, m.MainWindow.Canvas())
|
|
||||||
container.NewThemeOverride(pop, myTheme.WithColorTransformOverride(
|
|
||||||
theme.ColorNameOverlayBackground,
|
|
||||||
func(c color.Color) color.Color {
|
|
||||||
c_ := c.(color.NRGBA)
|
|
||||||
c_.A = 245
|
|
||||||
return c_
|
|
||||||
},
|
|
||||||
))
|
|
||||||
m.ClosePopUpOnEscape(pop)
|
m.ClosePopUpOnEscape(pop)
|
||||||
minSize := fyne.NewSize(300, 400)
|
minSize := fyne.NewSize(300, 400)
|
||||||
maxSize := fyne.NewSize(800, 1000)
|
maxSize := fyne.NewSize(800, 1000)
|
||||||
@@ -171,7 +183,7 @@ func (m *Controller) ShowPopUpPlayQueue() {
|
|||||||
fyne.NewSize(canvasSize.Width*0.4, canvasSize.Height*0.5),
|
fyne.NewSize(canvasSize.Width*0.4, canvasSize.Height*0.5),
|
||||||
))
|
))
|
||||||
pop.Resize(size)
|
pop.Resize(size)
|
||||||
popUpQueue.ScrollToNowPlaying() // must come after resize
|
popUpQueueList.ScrollToNowPlaying() // must come after resize
|
||||||
pop.ShowAtPosition(fyne.NewPos(
|
pop.ShowAtPosition(fyne.NewPos(
|
||||||
canvasSize.Width-size.Width-10,
|
canvasSize.Width-size.Width-10,
|
||||||
canvasSize.Height-size.Height-100,
|
canvasSize.Height-size.Height-100,
|
||||||
@@ -528,8 +540,10 @@ func (c *Controller) ShowSettingsDialog(themeUpdateCallbk func(), themeFiles map
|
|||||||
}
|
}
|
||||||
dlg.OnPageNeedsRefresh = c.RefreshPageFunc
|
dlg.OnPageNeedsRefresh = c.RefreshPageFunc
|
||||||
pop := widget.NewModalPopUp(dlg, c.MainWindow.Canvas())
|
pop := widget.NewModalPopUp(dlg, c.MainWindow.Canvas())
|
||||||
|
fynetooltip.AddPopUpToolTipLayer(pop)
|
||||||
dlg.OnDismiss = func() {
|
dlg.OnDismiss = func() {
|
||||||
pop.Hide()
|
pop.Hide()
|
||||||
|
fynetooltip.DestroyPopUpToolTipLayer(pop)
|
||||||
c.doModalClosed()
|
c.doModalClosed()
|
||||||
c.App.SaveConfigFile()
|
c.App.SaveConfigFile()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,37 @@ const (
|
|||||||
Radios
|
Radios
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (p PageName) String() string {
|
||||||
|
switch p {
|
||||||
|
case Album:
|
||||||
|
return "Album"
|
||||||
|
case Albums:
|
||||||
|
return "Albums"
|
||||||
|
case Artist:
|
||||||
|
return "Artist"
|
||||||
|
case Artists:
|
||||||
|
return "Artists"
|
||||||
|
case Genre:
|
||||||
|
return "Genre"
|
||||||
|
case Genres:
|
||||||
|
return "Genres"
|
||||||
|
case Favorites:
|
||||||
|
return "Favorites"
|
||||||
|
case NowPlaying:
|
||||||
|
return "Now Playing"
|
||||||
|
case Playlist:
|
||||||
|
return "Playlist"
|
||||||
|
case Playlists:
|
||||||
|
return "Playlists"
|
||||||
|
case Tracks:
|
||||||
|
return "All Tracks"
|
||||||
|
case Radios:
|
||||||
|
return "Internet Radio Stations"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Page PageName
|
Page PageName
|
||||||
Arg string
|
Arg string
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package dialogs
|
package dialogs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
"github.com/dweymouth/supersonic/ui/layouts"
|
"github.com/dweymouth/supersonic/ui/layouts"
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
"github.com/dweymouth/supersonic/ui/util"
|
"github.com/dweymouth/supersonic/ui/util"
|
||||||
@@ -17,7 +20,8 @@ type GraphicEqualizer struct {
|
|||||||
OnChanged func(band int, gain float64)
|
OnChanged func(band int, gain float64)
|
||||||
OnPreampChanged func(gain float64)
|
OnPreampChanged func(gain float64)
|
||||||
|
|
||||||
container *fyne.Container
|
bandSliders []*eqSlider
|
||||||
|
container *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGraphicEqualizer(preamp float64, bandFreqs []string, bandGains []float64) *GraphicEqualizer {
|
func NewGraphicEqualizer(preamp float64, bandFreqs []string, bandGains []float64) *GraphicEqualizer {
|
||||||
@@ -36,7 +40,8 @@ func (g *GraphicEqualizer) buildSliders(preamp float64, bands []string, bandGain
|
|||||||
layout.NewSpacer(),
|
layout.NewSpacer(),
|
||||||
newCaptionTextSizeLabel("-12", fyne.TextAlignTrailing),
|
newCaptionTextSizeLabel("-12", fyne.TextAlignTrailing),
|
||||||
)
|
)
|
||||||
bandSliders := container.New(layouts.NewGridLayoutWithColumnsAndPadding(len(bands)+2, -16))
|
g.bandSliders = make([]*eqSlider, len(bands))
|
||||||
|
bandSlidersCtr := container.New(layouts.NewGridLayoutWithColumnsAndPadding(len(bands)+2, -16))
|
||||||
pre := newCaptionTextSizeLabel("Pre", fyne.TextAlignCenter)
|
pre := newCaptionTextSizeLabel("Pre", fyne.TextAlignCenter)
|
||||||
preampSlider := newEQSlider()
|
preampSlider := newEQSlider()
|
||||||
preampSlider.SetValue(preamp)
|
preampSlider.SetValue(preamp)
|
||||||
@@ -44,24 +49,28 @@ func (g *GraphicEqualizer) buildSliders(preamp float64, bands []string, bandGain
|
|||||||
if g.OnPreampChanged != nil {
|
if g.OnPreampChanged != nil {
|
||||||
g.OnPreampChanged(f)
|
g.OnPreampChanged(f)
|
||||||
}
|
}
|
||||||
|
preampSlider.UpdateToolTip()
|
||||||
}
|
}
|
||||||
bandSliders.Add(container.NewBorder(nil, pre, nil, nil, preampSlider))
|
preampSlider.UpdateToolTip()
|
||||||
bandSliders.Add(container.NewBorder(nil, widget.NewLabel(""), nil, nil, rng))
|
bandSlidersCtr.Add(container.NewBorder(nil, pre, nil, nil, preampSlider))
|
||||||
|
bandSlidersCtr.Add(container.NewBorder(nil, widget.NewLabel(""), nil, nil, rng))
|
||||||
for i, band := range bands {
|
for i, band := range bands {
|
||||||
s := newEQSlider()
|
s := newEQSlider()
|
||||||
if i < len(bandGains) {
|
if i < len(bandGains) {
|
||||||
s.SetValue(bandGains[i])
|
s.SetValue(bandGains[i])
|
||||||
|
s.UpdateToolTip()
|
||||||
}
|
}
|
||||||
s.OnChanged = func(i int) func(float64) {
|
_i := i
|
||||||
return func(f float64) {
|
s.OnChanged = func(f float64) {
|
||||||
if g.OnChanged != nil {
|
if g.OnChanged != nil {
|
||||||
g.OnChanged(i, f)
|
g.OnChanged(_i, f)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}(i)
|
g.bandSliders[_i].UpdateToolTip()
|
||||||
|
}
|
||||||
l := newCaptionTextSizeLabel(band, fyne.TextAlignCenter)
|
l := newCaptionTextSizeLabel(band, fyne.TextAlignCenter)
|
||||||
c := container.NewBorder(nil, l, nil, nil, s)
|
c := container.NewBorder(nil, l, nil, nil, s)
|
||||||
bandSliders.Add(c)
|
bandSlidersCtr.Add(c)
|
||||||
|
g.bandSliders[i] = s
|
||||||
}
|
}
|
||||||
g.container = container.NewStack(
|
g.container = container.NewStack(
|
||||||
container.NewBorder(nil, widget.NewLabel(""), nil, nil,
|
container.NewBorder(nil, widget.NewLabel(""), nil, nil,
|
||||||
@@ -73,7 +82,7 @@ func (g *GraphicEqualizer) buildSliders(preamp float64, bands []string, bandGain
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bandSliders,
|
bandSlidersCtr,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,23 +99,29 @@ func (g *GraphicEqualizer) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type eqSlider struct {
|
type eqSlider struct {
|
||||||
widget.Slider
|
ttwidget.Slider
|
||||||
tappedAt int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEQSlider() *eqSlider {
|
func newEQSlider() *eqSlider {
|
||||||
s := &eqSlider{
|
s := &eqSlider{
|
||||||
Slider: widget.Slider{
|
Slider: ttwidget.Slider{
|
||||||
Orientation: widget.Vertical,
|
Slider: widget.Slider{
|
||||||
Min: -12,
|
Orientation: widget.Vertical,
|
||||||
Max: 12,
|
Min: -12,
|
||||||
Step: 0.1,
|
Max: 12,
|
||||||
|
Step: 0.1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
s.UpdateToolTip()
|
||||||
s.ExtendBaseWidget(s)
|
s.ExtendBaseWidget(s)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *eqSlider) UpdateToolTip() {
|
||||||
|
s.SetToolTip(fmt.Sprintf("%0.1f dB", s.Value))
|
||||||
|
}
|
||||||
|
|
||||||
// We implement our own double tapping so that the Tapped behavior
|
// We implement our own double tapping so that the Tapped behavior
|
||||||
// can be triggered instantly.
|
// can be triggered instantly.
|
||||||
func (s *eqSlider) DoubleTapped(e *fyne.PointEvent) {
|
func (s *eqSlider) DoubleTapped(e *fyne.PointEvent) {
|
||||||
|
|||||||
+9
-4
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
fynetooltip "github.com/dweymouth/fyne-tooltip"
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/res"
|
"github.com/dweymouth/supersonic/res"
|
||||||
@@ -40,7 +41,7 @@ type MainWindow struct {
|
|||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
|
|
||||||
// needs to bes shown/hidden when switching between servers based on whether they support radio
|
// needs to bes shown/hidden when switching between servers based on whether they support radio
|
||||||
radioBtn *widget.Button
|
radioBtn fyne.CanvasObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, app *backend.App) MainWindow {
|
func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, app *backend.App) MainWindow {
|
||||||
@@ -49,6 +50,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string,
|
|||||||
Window: fyneApp.NewWindow(displayAppName),
|
Window: fyneApp.NewWindow(displayAppName),
|
||||||
theme: theme.NewMyTheme(&app.Config.Theme, app.ThemesDir()),
|
theme: theme.NewMyTheme(&app.Config.Theme, app.ThemesDir()),
|
||||||
}
|
}
|
||||||
|
fynetooltip.SetToolTipTextSizeName(theme.SizeNameSubText)
|
||||||
|
|
||||||
m.theme.NormalFont = app.Config.Application.FontNormalTTF
|
m.theme.NormalFont = app.Config.Application.FontNormalTTF
|
||||||
m.theme.BoldFont = app.Config.Application.FontBoldTTF
|
m.theme.BoldFont = app.Config.Application.FontBoldTTF
|
||||||
@@ -80,7 +82,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string,
|
|||||||
|
|
||||||
m.BottomPanel = NewBottomPanel(app.PlaybackManager, app.ImageManager, m.Controller)
|
m.BottomPanel = NewBottomPanel(app.PlaybackManager, app.ImageManager, m.Controller)
|
||||||
m.container = container.NewBorder(nil, m.BottomPanel, nil, nil, m.BrowsingPane)
|
m.container = container.NewBorder(nil, m.BottomPanel, nil, nil, m.BrowsingPane)
|
||||||
m.Window.SetContent(m.container)
|
m.Window.SetContent(fynetooltip.AddWindowToolTipLayer(m.container, m.Window.Canvas()))
|
||||||
m.setInitialSize()
|
m.setInitialSize()
|
||||||
app.PlaybackManager.OnSongChange(func(item mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
app.PlaybackManager.OnSongChange(func(item mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
@@ -191,8 +193,11 @@ func (m *MainWindow) RunOnServerConnectedTasks(app *backend.App, displayAppName
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, supportsRadio := m.App.ServerManager.Server.(mediaprovider.RadioProvider)
|
_, supportsRadio := m.App.ServerManager.Server.(mediaprovider.RadioProvider)
|
||||||
m.radioBtn.Hidden = !supportsRadio
|
if supportsRadio {
|
||||||
m.radioBtn.Refresh()
|
m.radioBtn.Show()
|
||||||
|
} else {
|
||||||
|
m.radioBtn.Hide()
|
||||||
|
}
|
||||||
|
|
||||||
m.App.SaveConfigFile()
|
m.App.SaveConfigFile()
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ import (
|
|||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/driver/desktop"
|
||||||
"fyne.io/fyne/v2/lang"
|
"fyne.io/fyne/v2/lang"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/res"
|
"github.com/dweymouth/supersonic/res"
|
||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
@@ -252,6 +254,18 @@ func NewTruncatingLabel() *widget.Label {
|
|||||||
return rt
|
return rt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTruncatingTooltipRichText() *ttwidget.RichText {
|
||||||
|
rt := ttwidget.NewRichTextWithText("")
|
||||||
|
rt.Truncation = fyne.TextTruncateEllipsis
|
||||||
|
return rt
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTruncatingTooltipLabel() *ttwidget.Label {
|
||||||
|
rt := ttwidget.NewLabel("")
|
||||||
|
rt.Truncation = fyne.TextTruncateEllipsis
|
||||||
|
return rt
|
||||||
|
}
|
||||||
|
|
||||||
func NewTrailingAlignLabel() *widget.Label {
|
func NewTrailingAlignLabel() *widget.Label {
|
||||||
rt := widget.NewLabel("")
|
rt := widget.NewLabel("")
|
||||||
rt.Alignment = fyne.TextAlignTrailing
|
rt.Alignment = fyne.TextAlignTrailing
|
||||||
@@ -269,6 +283,14 @@ func LocalizeSlice(s []string) []string {
|
|||||||
return sharedutil.MapSlice(s, func(s string) string { return lang.L(s) })
|
return sharedutil.MapSlice(s, func(s string) string { return lang.L(s) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ToolTipRichText struct {
|
||||||
|
ttwidget.RichText
|
||||||
|
|
||||||
|
OnMouseIn func(e *desktop.MouseEvent)
|
||||||
|
OnMouseOut func()
|
||||||
|
OnTapped func(e *fyne.PointEvent)
|
||||||
|
}
|
||||||
|
|
||||||
type HSpace struct {
|
type HSpace struct {
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
@@ -22,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AlbumFilterButton struct {
|
type AlbumFilterButton struct {
|
||||||
widget.Button
|
ttwidget.Button
|
||||||
|
|
||||||
OnChanged func()
|
OnChanged func()
|
||||||
GenreDisabled bool
|
GenreDisabled bool
|
||||||
@@ -37,10 +38,13 @@ type AlbumFilterButton struct {
|
|||||||
func NewAlbumFilterButton(filter mediaprovider.AlbumFilter, fetchGenresFunc func() ([]*mediaprovider.Genre, error)) *AlbumFilterButton {
|
func NewAlbumFilterButton(filter mediaprovider.AlbumFilter, fetchGenresFunc func() ([]*mediaprovider.Genre, error)) *AlbumFilterButton {
|
||||||
a := &AlbumFilterButton{
|
a := &AlbumFilterButton{
|
||||||
filter: filter,
|
filter: filter,
|
||||||
Button: widget.Button{
|
Button: ttwidget.Button{
|
||||||
Icon: theme.NewThemedResource(myTheme.FilterIcon),
|
Button: widget.Button{
|
||||||
|
Icon: theme.NewThemedResource(myTheme.FilterIcon),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
a.SetToolTip(lang.L("Filter albums"))
|
||||||
a.OnTapped = a.showFilterDialog
|
a.OnTapped = a.showFilterDialog
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.genreListChan = make(chan []string)
|
a.genreListChan = make(chan []string)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package widgets
|
|||||||
import (
|
import (
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
@@ -31,7 +32,9 @@ func NewAuxControls(initialVolume int) *AuxControls {
|
|||||||
showQueue: NewIconButton(myTheme.PlayQueueIcon, nil),
|
showQueue: NewIconButton(myTheme.PlayQueueIcon, nil),
|
||||||
}
|
}
|
||||||
a.loop.IconSize = IconButtonSizeSmaller
|
a.loop.IconSize = IconButtonSizeSmaller
|
||||||
|
a.loop.SetToolTip(lang.L("Shuffle"))
|
||||||
a.showQueue.IconSize = IconButtonSizeSmaller
|
a.showQueue.IconSize = IconButtonSizeSmaller
|
||||||
|
a.showQueue.SetToolTip(lang.L("Show play queue"))
|
||||||
a.container = container.NewHBox(
|
a.container = container.NewHBox(
|
||||||
layout.NewSpacer(),
|
layout.NewSpacer(),
|
||||||
container.NewVBox(
|
container.NewVBox(
|
||||||
@@ -125,6 +128,7 @@ func NewVolumeControl(initialVol int) *VolumeControl {
|
|||||||
v := &VolumeControl{}
|
v := &VolumeControl{}
|
||||||
v.ExtendBaseWidget(v)
|
v.ExtendBaseWidget(v)
|
||||||
v.icon = NewIconButton(theme.VolumeUpIcon(), v.toggleMute)
|
v.icon = NewIconButton(theme.VolumeUpIcon(), v.toggleMute)
|
||||||
|
v.icon.SetToolTip(lang.L("Mute"))
|
||||||
v.icon.IconSize = IconButtonSizeSmaller
|
v.icon.IconSize = IconButtonSizeSmaller
|
||||||
v.slider = NewVolumeSlider(100)
|
v.slider = NewVolumeSlider(100)
|
||||||
v.lastVol = initialVol
|
v.lastVol = initialVol
|
||||||
|
|||||||
+51
-19
@@ -1,12 +1,14 @@
|
|||||||
package widgets
|
package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image/color"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/driver/desktop"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
|
||||||
@@ -72,6 +74,7 @@ func (g *FocusList) FocusNeighbor(curItem widget.ListItemID, up bool) {
|
|||||||
var _ fyne.Tappable = (*FocusListRowBase)(nil)
|
var _ fyne.Tappable = (*FocusListRowBase)(nil)
|
||||||
var _ fyne.Widget = (*FocusListRowBase)(nil)
|
var _ fyne.Widget = (*FocusListRowBase)(nil)
|
||||||
var _ fyne.Focusable = (*FocusListRowBase)(nil)
|
var _ fyne.Focusable = (*FocusListRowBase)(nil)
|
||||||
|
var _ desktop.Hoverable = (*FocusListRowBase)(nil)
|
||||||
|
|
||||||
// Base type used for all list rows in widgets such as Tracklist, etc.
|
// Base type used for all list rows in widgets such as Tracklist, etc.
|
||||||
type FocusListRowBase struct {
|
type FocusListRowBase struct {
|
||||||
@@ -81,14 +84,16 @@ type FocusListRowBase struct {
|
|||||||
Content fyne.CanvasObject
|
Content fyne.CanvasObject
|
||||||
Selected bool
|
Selected bool
|
||||||
Focused bool
|
Focused bool
|
||||||
|
hovered bool
|
||||||
|
|
||||||
OnTapped func()
|
OnTapped func()
|
||||||
OnDoubleTapped func()
|
OnDoubleTapped func()
|
||||||
OnFocusNeighbor func(up bool) //TODO: func(up, selecting bool)
|
OnFocusNeighbor func(up bool) //TODO: func(up, selecting bool)
|
||||||
|
|
||||||
tappedAt int64 // unixMillis
|
tappedAt int64 // unixMillis
|
||||||
focusedRect *canvas.Rectangle
|
focusedRect canvas.Rectangle
|
||||||
selectionRect *canvas.Rectangle
|
selectionRect canvas.Rectangle
|
||||||
|
hoverRect canvas.Rectangle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *FocusListRowBase) SetOnTapped(f func()) {
|
func (l *FocusListRowBase) SetOnTapped(f func()) {
|
||||||
@@ -139,12 +144,14 @@ func (l *FocusListRowBase) Tapped(*fyne.PointEvent) {
|
|||||||
|
|
||||||
func (l *FocusListRowBase) FocusGained() {
|
func (l *FocusListRowBase) FocusGained() {
|
||||||
l.Focused = true
|
l.Focused = true
|
||||||
l.Refresh()
|
l.focusedRect.FillColor = theme.HoverColor()
|
||||||
|
l.focusedRect.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *FocusListRowBase) FocusLost() {
|
func (l *FocusListRowBase) FocusLost() {
|
||||||
l.Focused = false
|
l.Focused = false
|
||||||
l.Refresh()
|
l.focusedRect.FillColor = color.Transparent
|
||||||
|
l.focusedRect.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *FocusListRowBase) TypedKey(e *fyne.KeyEvent) {
|
func (l *FocusListRowBase) TypedKey(e *fyne.KeyEvent) {
|
||||||
@@ -180,26 +187,51 @@ func (l *FocusListRowBase) TypedKey(e *fyne.KeyEvent) {
|
|||||||
func (l *FocusListRowBase) TypedRune(r rune) {
|
func (l *FocusListRowBase) TypedRune(r rune) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *FocusListRowBase) MouseIn(e *desktop.MouseEvent) {
|
||||||
|
l.hovered = true
|
||||||
|
l.hoverRect.FillColor = theme.HoverColor()
|
||||||
|
l.hoverRect.Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *FocusListRowBase) MouseMoved(e *desktop.MouseEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *FocusListRowBase) MouseOut() {
|
||||||
|
l.hovered = false
|
||||||
|
l.hoverRect.FillColor = color.Transparent
|
||||||
|
l.hoverRect.Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func (l *FocusListRowBase) Refresh() {
|
func (l *FocusListRowBase) Refresh() {
|
||||||
l.focusedRect.FillColor = theme.HoverColor()
|
l.updateBackgroundRendering()
|
||||||
l.focusedRect.Hidden = !l.Focused
|
|
||||||
l.selectionRect.FillColor = theme.SelectionColor()
|
|
||||||
l.selectionRect.Hidden = !l.Selected
|
|
||||||
l.BaseWidget.Refresh()
|
l.BaseWidget.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *FocusListRowBase) updateBackgroundRendering() {
|
||||||
|
if l.Selected {
|
||||||
|
l.selectionRect.FillColor = theme.SelectionColor()
|
||||||
|
} else {
|
||||||
|
l.selectionRect.FillColor = color.Transparent
|
||||||
|
}
|
||||||
|
if l.Focused {
|
||||||
|
l.focusedRect.FillColor = theme.HoverColor()
|
||||||
|
} else {
|
||||||
|
l.focusedRect.FillColor = color.Transparent
|
||||||
|
}
|
||||||
|
if l.hovered {
|
||||||
|
l.hoverRect.FillColor = theme.HoverColor()
|
||||||
|
} else {
|
||||||
|
l.hoverRect.FillColor = color.Transparent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *FocusListRowBase) CreateRenderer() fyne.WidgetRenderer {
|
func (l *FocusListRowBase) CreateRenderer() fyne.WidgetRenderer {
|
||||||
if l.selectionRect == nil {
|
l.selectionRect.CornerRadius = theme.SelectionRadiusSize()
|
||||||
l.selectionRect = canvas.NewRectangle(theme.SelectionColor())
|
l.focusedRect.CornerRadius = theme.SelectionRadiusSize()
|
||||||
l.selectionRect.CornerRadius = theme.SelectionRadiusSize()
|
l.hoverRect.CornerRadius = theme.SelectionRadiusSize()
|
||||||
l.selectionRect.Hidden = !l.Selected
|
l.updateBackgroundRendering()
|
||||||
}
|
|
||||||
if l.focusedRect == nil {
|
|
||||||
l.focusedRect = canvas.NewRectangle(theme.HoverColor())
|
|
||||||
l.focusedRect.CornerRadius = theme.SelectionRadiusSize()
|
|
||||||
l.focusedRect.Hidden = !l.Focused
|
|
||||||
}
|
|
||||||
return widget.NewSimpleRenderer(
|
return widget.NewSimpleRenderer(
|
||||||
container.NewStack(l.selectionRect, l.focusedRect, l.Content),
|
container.NewStack(&l.selectionRect, &l.focusedRect, &l.hoverRect, l.Content),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
"github.com/dweymouth/supersonic/res"
|
"github.com/dweymouth/supersonic/res"
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
"github.com/dweymouth/supersonic/ui/util"
|
"github.com/dweymouth/supersonic/ui/util"
|
||||||
@@ -142,7 +143,7 @@ type GridViewItem struct {
|
|||||||
|
|
||||||
itemID string
|
itemID string
|
||||||
secondaryIDs []string
|
secondaryIDs []string
|
||||||
primaryText *widget.Hyperlink
|
primaryText *ttwidget.Hyperlink
|
||||||
secondaryText *MultiHyperlink
|
secondaryText *MultiHyperlink
|
||||||
suffix string
|
suffix string
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
@@ -165,7 +166,7 @@ type GridViewItem struct {
|
|||||||
|
|
||||||
func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
|
func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
|
||||||
g := &GridViewItem{
|
g := &GridViewItem{
|
||||||
primaryText: widget.NewHyperlink("", nil),
|
primaryText: ttwidget.NewHyperlink("", nil),
|
||||||
secondaryText: NewMultiHyperlink(),
|
secondaryText: NewMultiHyperlink(),
|
||||||
Cover: newCoverImage(placeholderResource),
|
Cover: newCoverImage(placeholderResource),
|
||||||
}
|
}
|
||||||
@@ -220,6 +221,7 @@ func (g *GridViewItem) Update(model GridViewItemModel) {
|
|||||||
g.itemID = model.ID
|
g.itemID = model.ID
|
||||||
g.secondaryIDs = model.SecondaryIDs
|
g.secondaryIDs = model.SecondaryIDs
|
||||||
g.primaryText.SetText(model.Name)
|
g.primaryText.SetText(model.Name)
|
||||||
|
g.primaryText.SetToolTip(model.Name)
|
||||||
g.secondaryText.BuildSegments(model.Secondary, model.SecondaryIDs)
|
g.secondaryText.BuildSegments(model.Secondary, model.SecondaryIDs)
|
||||||
if g.ShowSuffix {
|
if g.ShowSuffix {
|
||||||
g.secondaryText.Suffix = model.Suffix
|
g.secondaryText.Suffix = model.Suffix
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/driver/desktop"
|
"fyne.io/fyne/v2/driver/desktop"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
|
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
)
|
)
|
||||||
@@ -20,7 +21,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IconButton struct {
|
type IconButton struct {
|
||||||
widget.BaseWidget
|
ttwidget.ToolTipWidget
|
||||||
|
|
||||||
Highlighted bool
|
Highlighted bool
|
||||||
IconSize IconButtonSize
|
IconSize IconButtonSize
|
||||||
@@ -84,7 +85,8 @@ func (i *IconButton) TypedKey(e *fyne.KeyEvent) {
|
|||||||
func (i *IconButton) TypedRune(r rune) {
|
func (i *IconButton) TypedRune(r rune) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IconButton) MouseIn(*desktop.MouseEvent) {
|
func (i *IconButton) MouseIn(e *desktop.MouseEvent) {
|
||||||
|
i.ToolTipWidget.MouseIn(e)
|
||||||
if !i.hovered {
|
if !i.hovered {
|
||||||
defer i.Refresh()
|
defer i.Refresh()
|
||||||
}
|
}
|
||||||
@@ -92,13 +94,15 @@ func (i *IconButton) MouseIn(*desktop.MouseEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *IconButton) MouseOut() {
|
func (i *IconButton) MouseOut() {
|
||||||
|
i.ToolTipWidget.MouseOut()
|
||||||
if i.hovered {
|
if i.hovered {
|
||||||
defer i.Refresh()
|
defer i.Refresh()
|
||||||
}
|
}
|
||||||
i.hovered = false
|
i.hovered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IconButton) MouseMoved(*desktop.MouseEvent) {
|
func (i *IconButton) MouseMoved(e *desktop.MouseEvent) {
|
||||||
|
i.ToolTipWidget.MouseMoved(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IconButton) MinSize() fyne.Size {
|
func (i *IconButton) MinSize() fyne.Size {
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package widgets
|
|||||||
import (
|
import (
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/driver/desktop"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MultiHyperlink struct {
|
type MultiHyperlink struct {
|
||||||
@@ -16,7 +18,9 @@ type MultiHyperlink struct {
|
|||||||
// only if there is enough room
|
// only if there is enough room
|
||||||
Suffix string
|
Suffix string
|
||||||
|
|
||||||
OnTapped func(string)
|
OnMouseIn func(*desktop.MouseEvent)
|
||||||
|
OnMouseOut func()
|
||||||
|
OnTapped func(string)
|
||||||
|
|
||||||
SizeName fyne.ThemeSizeName
|
SizeName fyne.ThemeSizeName
|
||||||
SuffixSizeName fyne.ThemeSizeName
|
SuffixSizeName fyne.ThemeSizeName
|
||||||
@@ -30,7 +34,7 @@ type MultiHyperlink struct {
|
|||||||
//provider *widget.RichText
|
//provider *widget.RichText
|
||||||
|
|
||||||
objects []fyne.CanvasObject
|
objects []fyne.CanvasObject
|
||||||
suffixLabel *widget.RichText
|
suffixLabel *ttwidget.RichText
|
||||||
content *fyne.Container
|
content *fyne.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +140,9 @@ func (c *MultiHyperlink) layoutObjects() {
|
|||||||
c.content.Objects = c.objects[:2*i-1]
|
c.content.Objects = c.objects[:2*i-1]
|
||||||
if i == len(c.Segments) && c.Suffix != "" {
|
if i == len(c.Segments) && c.Suffix != "" {
|
||||||
if c.suffixLabel == nil {
|
if c.suffixLabel == nil {
|
||||||
c.suffixLabel = widget.NewRichTextWithText("· " + c.Suffix)
|
c.suffixLabel = ttwidget.NewRichTextWithText("· " + c.Suffix)
|
||||||
|
c.suffixLabel.OnMouseIn = c.callOnMouseIn
|
||||||
|
c.suffixLabel.OnMouseOut = c.callOnMouseOut
|
||||||
} else {
|
} else {
|
||||||
c.suffixLabel.Segments[0].(*widget.TextSegment).Text = "· " + c.Suffix
|
c.suffixLabel.Segments[0].(*widget.TextSegment).Text = "· " + c.Suffix
|
||||||
}
|
}
|
||||||
@@ -157,14 +163,18 @@ func (c *MultiHyperlink) layoutObjects() {
|
|||||||
|
|
||||||
func (c *MultiHyperlink) updateOrReplaceLabel(obj fyne.CanvasObject, text string) fyne.CanvasObject {
|
func (c *MultiHyperlink) updateOrReplaceLabel(obj fyne.CanvasObject, text string) fyne.CanvasObject {
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
if label, ok := obj.(*widget.RichText); ok {
|
if label, ok := obj.(*ttwidget.RichText); ok {
|
||||||
ts := label.Segments[0].(*widget.TextSegment)
|
ts := label.Segments[0].(*widget.TextSegment)
|
||||||
ts.Text = text
|
ts.Text = text
|
||||||
ts.Style.SizeName = c.sizeName()
|
ts.Style.SizeName = c.sizeName()
|
||||||
|
label.SetToolTip(text)
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l := widget.NewRichTextWithText(text)
|
l := ttwidget.NewRichTextWithText(text)
|
||||||
|
l.SetToolTip(text)
|
||||||
|
l.OnMouseIn = c.callOnMouseIn
|
||||||
|
l.OnMouseOut = c.callOnMouseOut
|
||||||
l.Segments[0].(*widget.TextSegment).Style.SizeName = c.sizeName()
|
l.Segments[0].(*widget.TextSegment).Style.SizeName = c.sizeName()
|
||||||
l.Truncation = fyne.TextTruncateEllipsis
|
l.Truncation = fyne.TextTruncateEllipsis
|
||||||
return l
|
return l
|
||||||
@@ -172,20 +182,34 @@ func (c *MultiHyperlink) updateOrReplaceLabel(obj fyne.CanvasObject, text string
|
|||||||
|
|
||||||
func (c *MultiHyperlink) updateOrReplaceHyperlink(obj fyne.CanvasObject, text, link string) fyne.CanvasObject {
|
func (c *MultiHyperlink) updateOrReplaceHyperlink(obj fyne.CanvasObject, text, link string) fyne.CanvasObject {
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
if l, ok := obj.(*widget.Hyperlink); ok {
|
if l, ok := obj.(*ttwidget.Hyperlink); ok {
|
||||||
l.Text = text
|
l.Text = text
|
||||||
|
l.SetToolTip(text)
|
||||||
l.SizeName = c.sizeName()
|
l.SizeName = c.sizeName()
|
||||||
l.OnTapped = func() { c.onSegmentTapped(link) }
|
l.OnTapped = func() { c.onSegmentTapped(link) }
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l := widget.NewHyperlink(text, nil)
|
l := ttwidget.NewHyperlink(text, nil)
|
||||||
|
l.SetToolTip(text)
|
||||||
l.SizeName = c.sizeName()
|
l.SizeName = c.sizeName()
|
||||||
l.Truncation = fyne.TextTruncateEllipsis
|
l.Truncation = fyne.TextTruncateEllipsis
|
||||||
l.OnTapped = func() { c.onSegmentTapped(link) }
|
l.OnTapped = func() { c.onSegmentTapped(link) }
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) callOnMouseIn(e *desktop.MouseEvent) {
|
||||||
|
if f := c.OnMouseIn; f != nil {
|
||||||
|
f(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MultiHyperlink) callOnMouseOut() {
|
||||||
|
if f := c.OnMouseOut; f != nil {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *MultiHyperlink) newSeparatorLabel() *widget.RichText {
|
func (c *MultiHyperlink) newSeparatorLabel() *widget.RichText {
|
||||||
rt := widget.NewRichTextWithText(", ")
|
rt := widget.NewRichTextWithText(", ")
|
||||||
rt.Segments[0].(*widget.TextSegment).Style.SizeName = c.sizeName()
|
rt.Segments[0].(*widget.TextSegment).Style.SizeName = c.sizeName()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Shows the current album art, track name, artist name, and album name
|
// Shows the current album art, track name, artist name, and album name
|
||||||
@@ -26,7 +27,7 @@ type NowPlayingCard struct {
|
|||||||
|
|
||||||
trackName *OptionHyperlink
|
trackName *OptionHyperlink
|
||||||
artistName *MultiHyperlink
|
artistName *MultiHyperlink
|
||||||
albumName *widget.Hyperlink
|
albumName *ttwidget.Hyperlink
|
||||||
cover *ImagePlaceholder
|
cover *ImagePlaceholder
|
||||||
menu *widget.PopUpMenu
|
menu *widget.PopUpMenu
|
||||||
ratingMenu *fyne.MenuItem
|
ratingMenu *fyne.MenuItem
|
||||||
@@ -46,7 +47,7 @@ func NewNowPlayingCard() *NowPlayingCard {
|
|||||||
n := &NowPlayingCard{
|
n := &NowPlayingCard{
|
||||||
trackName: NewOptionHyperlink(),
|
trackName: NewOptionHyperlink(),
|
||||||
artistName: NewMultiHyperlink(),
|
artistName: NewMultiHyperlink(),
|
||||||
albumName: widget.NewHyperlink("", nil),
|
albumName: ttwidget.NewHyperlink("", nil),
|
||||||
}
|
}
|
||||||
n.ExtendBaseWidget(n)
|
n.ExtendBaseWidget(n)
|
||||||
n.cover = NewImagePlaceholder(myTheme.TracksIcon, 85)
|
n.cover = NewImagePlaceholder(myTheme.TracksIcon, 85)
|
||||||
@@ -135,20 +136,23 @@ func (n *NowPlayingCard) CreateRenderer() fyne.WidgetRenderer {
|
|||||||
|
|
||||||
func (n *NowPlayingCard) Update(track mediaprovider.MediaItem) {
|
func (n *NowPlayingCard) Update(track mediaprovider.MediaItem) {
|
||||||
if track == nil {
|
if track == nil {
|
||||||
n.trackName.SetText("")
|
n.trackName.SetTextAndToolTip("")
|
||||||
n.artistName.BuildSegments([]string{}, []string{})
|
n.artistName.BuildSegments([]string{}, []string{})
|
||||||
n.albumName.SetText("")
|
n.albumName.SetText("")
|
||||||
|
n.albumName.SetToolTip("")
|
||||||
n.cover.Hidden = true
|
n.cover.Hidden = true
|
||||||
} else {
|
} else {
|
||||||
n.cover.Hidden = false
|
n.cover.Hidden = false
|
||||||
n.trackName.SetText(track.Metadata().Name)
|
n.trackName.SetTextAndToolTip(track.Metadata().Name)
|
||||||
if tr, ok := track.(*mediaprovider.Track); ok {
|
if tr, ok := track.(*mediaprovider.Track); ok {
|
||||||
n.artistName.BuildSegments(tr.ArtistNames, tr.ArtistIDs)
|
n.artistName.BuildSegments(tr.ArtistNames, tr.ArtistIDs)
|
||||||
n.albumName.SetText(tr.Album)
|
n.albumName.SetText(tr.Album)
|
||||||
|
n.albumName.SetToolTip(tr.Album)
|
||||||
n.cover.PlaceholderIcon = myTheme.TracksIcon
|
n.cover.PlaceholderIcon = myTheme.TracksIcon
|
||||||
} else {
|
} else {
|
||||||
n.artistName.BuildSegments([]string{}, []string{})
|
n.artistName.BuildSegments([]string{}, []string{})
|
||||||
n.albumName.SetText("")
|
n.albumName.SetText("")
|
||||||
|
n.albumName.SetToolTip("")
|
||||||
n.cover.PlaceholderIcon = myTheme.RadioIcon
|
n.cover.PlaceholderIcon = myTheme.RadioIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import (
|
|||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OptionHyperlink is a widget that displays a "vertical dots"/"more" button
|
// OptionHyperlink is a widget that displays a "vertical dots"/"more" button
|
||||||
// to the right of the text, which can show a menu.
|
// to the right of the text, which can show a menu.
|
||||||
type OptionHyperlink struct {
|
type OptionHyperlink struct {
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
h *widget.Hyperlink
|
h *ttwidget.Hyperlink
|
||||||
b *IconButton
|
b *IconButton
|
||||||
|
|
||||||
OnShowMenu func(btnPos fyne.Position)
|
OnShowMenu func(btnPos fyne.Position)
|
||||||
@@ -21,7 +22,7 @@ type OptionHyperlink struct {
|
|||||||
|
|
||||||
func NewOptionHyperlink() *OptionHyperlink {
|
func NewOptionHyperlink() *OptionHyperlink {
|
||||||
o := &OptionHyperlink{
|
o := &OptionHyperlink{
|
||||||
h: widget.NewHyperlink("", nil),
|
h: ttwidget.NewHyperlink("", nil),
|
||||||
}
|
}
|
||||||
o.h.Truncation = fyne.TextTruncateEllipsis
|
o.h.Truncation = fyne.TextTruncateEllipsis
|
||||||
o.b = NewIconButton(theme.MoreVerticalIcon(), func() {
|
o.b = NewIconButton(theme.MoreVerticalIcon(), func() {
|
||||||
@@ -34,8 +35,9 @@ func NewOptionHyperlink() *OptionHyperlink {
|
|||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OptionHyperlink) SetText(text string) {
|
func (o *OptionHyperlink) SetTextAndToolTip(text string) {
|
||||||
o.h.SetText(text)
|
o.h.SetText(text)
|
||||||
|
o.h.SetToolTip(text)
|
||||||
o.updatePreferredWidth()
|
o.updatePreferredWidth()
|
||||||
o.BaseWidget.Refresh()
|
o.BaseWidget.Refresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
@@ -128,8 +129,11 @@ func NewPlayerControls() *PlayerControls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pc.prev = NewIconButton(theme.MediaSkipPreviousIcon(), func() {})
|
pc.prev = NewIconButton(theme.MediaSkipPreviousIcon(), func() {})
|
||||||
|
pc.prev.SetToolTip(lang.L("Previous"))
|
||||||
pc.next = NewIconButton(theme.MediaSkipNextIcon(), func() {})
|
pc.next = NewIconButton(theme.MediaSkipNextIcon(), func() {})
|
||||||
|
pc.next.SetToolTip(lang.L("Next"))
|
||||||
pc.playpause = NewIconButton(theme.MediaPlayIcon(), func() {})
|
pc.playpause = NewIconButton(theme.MediaPlayIcon(), func() {})
|
||||||
|
pc.playpause.SetToolTip(lang.L("Play"))
|
||||||
pc.playpause.IconSize = IconButtonSizeBigger
|
pc.playpause.IconSize = IconButtonSizeBigger
|
||||||
|
|
||||||
buttons := container.NewHBox(layout.NewSpacer(), pc.prev, pc.playpause, pc.next, layout.NewSpacer())
|
buttons := container.NewHBox(layout.NewSpacer(), pc.prev, pc.playpause, pc.next, layout.NewSpacer())
|
||||||
@@ -165,8 +169,10 @@ func (pc *PlayerControls) OnPlayPause(f func()) {
|
|||||||
func (pc *PlayerControls) SetPlaying(playing bool) {
|
func (pc *PlayerControls) SetPlaying(playing bool) {
|
||||||
if playing {
|
if playing {
|
||||||
pc.playpause.SetIcon(theme.MediaPauseIcon())
|
pc.playpause.SetIcon(theme.MediaPauseIcon())
|
||||||
|
pc.playpause.SetToolTip(lang.L("Pause"))
|
||||||
} else {
|
} else {
|
||||||
pc.playpause.SetIcon(theme.MediaPlayIcon())
|
pc.playpause.SetIcon(theme.MediaPlayIcon())
|
||||||
|
pc.playpause.SetToolTip(lang.L("Play"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -15,6 +15,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
@@ -436,7 +437,7 @@ type PlayQueueListRow struct {
|
|||||||
playingIcon fyne.CanvasObject
|
playingIcon fyne.CanvasObject
|
||||||
num *widget.Label
|
num *widget.Label
|
||||||
cover *ImagePlaceholder
|
cover *ImagePlaceholder
|
||||||
title *widget.Label
|
title *ttwidget.Label
|
||||||
artist *MultiHyperlink
|
artist *MultiHyperlink
|
||||||
time *widget.Label
|
time *widget.Label
|
||||||
}
|
}
|
||||||
@@ -447,14 +448,18 @@ func NewPlayQueueListRow(playQueueList *PlayQueueList, im *backend.ImageManager,
|
|||||||
playQueueList: playQueueList,
|
playQueueList: playQueueList,
|
||||||
num: widget.NewLabel(""),
|
num: widget.NewLabel(""),
|
||||||
cover: NewImagePlaceholder(myTheme.TracksIcon, playQueueListThumbnailSize),
|
cover: NewImagePlaceholder(myTheme.TracksIcon, playQueueListThumbnailSize),
|
||||||
title: util.NewTruncatingLabel(),
|
title: util.NewTruncatingTooltipLabel(),
|
||||||
artist: NewMultiHyperlink(),
|
artist: NewMultiHyperlink(),
|
||||||
time: util.NewTrailingAlignLabel(),
|
time: util.NewTrailingAlignLabel(),
|
||||||
}
|
}
|
||||||
p.ExtendBaseWidget(p)
|
p.ExtendBaseWidget(p)
|
||||||
|
|
||||||
p.cover.ScaleMode = canvas.ImageScaleFastest
|
p.cover.ScaleMode = canvas.ImageScaleFastest
|
||||||
|
p.title.OnMouseIn = p.MouseIn
|
||||||
|
p.title.OnMouseOut = p.MouseOut
|
||||||
p.artist.OnTapped = playQueueList.onArtistTapped
|
p.artist.OnTapped = playQueueList.onArtistTapped
|
||||||
|
p.artist.OnMouseIn = p.MouseIn
|
||||||
|
p.artist.OnMouseOut = p.MouseOut
|
||||||
p.OnDoubleTapped = func() {
|
p.OnDoubleTapped = func() {
|
||||||
playQueueList.onPlayTrackAt(p.ItemID())
|
playQueueList.onPlayTrackAt(p.ItemID())
|
||||||
}
|
}
|
||||||
@@ -490,15 +495,12 @@ func (p *PlayQueueListRow) TappedSecondary(e *fyne.PointEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *PlayQueueListRow) Update(tm *util.TrackListModel, rowNum int) {
|
func (p *PlayQueueListRow) Update(tm *util.TrackListModel, rowNum int) {
|
||||||
changed := false
|
|
||||||
if tm.Selected != p.Selected {
|
if tm.Selected != p.Selected {
|
||||||
p.Selected = tm.Selected
|
p.Selected = tm.Selected
|
||||||
changed = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if num := strconv.Itoa(rowNum); p.num.Text != num {
|
if num := strconv.Itoa(rowNum); p.num.Text != num {
|
||||||
p.num.Text = num
|
p.num.Text = num
|
||||||
changed = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update info that can change if this row is bound to
|
// Update info that can change if this row is bound to
|
||||||
@@ -514,9 +516,9 @@ func (p *PlayQueueListRow) Update(tm *util.TrackListModel, rowNum int) {
|
|||||||
p.EnsureUnfocused()
|
p.EnsureUnfocused()
|
||||||
p.trackID = meta.ID
|
p.trackID = meta.ID
|
||||||
p.title.Text = meta.Name
|
p.title.Text = meta.Name
|
||||||
|
p.title.SetToolTip(meta.Name)
|
||||||
p.artist.BuildSegments(meta.Artists, meta.ArtistIDs)
|
p.artist.BuildSegments(meta.Artists, meta.ArtistIDs)
|
||||||
p.time.Text = util.SecondsToMMSS(float64(meta.Duration))
|
p.time.Text = util.SecondsToMMSS(float64(meta.Duration))
|
||||||
changed = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render whether track is playing or not
|
// Render whether track is playing or not
|
||||||
@@ -529,10 +531,11 @@ func (p *PlayQueueListRow) Update(tm *util.TrackListModel, rowNum int) {
|
|||||||
} else {
|
} else {
|
||||||
p.Content.(*fyne.Container).Objects[0] = container.NewCenter(p.num)
|
p.Content.(*fyne.Container).Objects[0] = container.NewCenter(p.num)
|
||||||
}
|
}
|
||||||
changed = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if changed {
|
// we always need to refresh in case of light/dark change
|
||||||
p.Refresh()
|
// even if no info changed in the update, since the
|
||||||
}
|
// PlayQueueList is used in the pop up queue which may be
|
||||||
|
// hidden and re-shown after a theme variant change
|
||||||
|
p.Refresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"fyne.io/fyne/v2/layout"
|
"fyne.io/fyne/v2/layout"
|
||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
|
ttwidget "github.com/dweymouth/fyne-tooltip/widget"
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
myTheme "github.com/dweymouth/supersonic/ui/theme"
|
||||||
"github.com/dweymouth/supersonic/ui/util"
|
"github.com/dweymouth/supersonic/ui/util"
|
||||||
@@ -151,7 +152,7 @@ type tracklistRowBase struct {
|
|||||||
playCount int
|
playCount int
|
||||||
|
|
||||||
num *widget.Label
|
num *widget.Label
|
||||||
name *widget.RichText // for bold support
|
name *ttwidget.RichText
|
||||||
artist *MultiHyperlink
|
artist *MultiHyperlink
|
||||||
album *MultiHyperlink // for disabled support, if albumID is ""
|
album *MultiHyperlink // for disabled support, if albumID is ""
|
||||||
composer *MultiHyperlink
|
composer *MultiHyperlink
|
||||||
@@ -161,9 +162,9 @@ type tracklistRowBase struct {
|
|||||||
rating *StarRating
|
rating *StarRating
|
||||||
bitrate *widget.Label
|
bitrate *widget.Label
|
||||||
plays *widget.Label
|
plays *widget.Label
|
||||||
comment *widget.Label
|
comment *ttwidget.Label
|
||||||
size *widget.Label
|
size *widget.Label
|
||||||
path *widget.Label
|
path *ttwidget.Label
|
||||||
|
|
||||||
// must be injected by extending widget
|
// must be injected by extending widget
|
||||||
setColVisibility func(int, bool) bool
|
setColVisibility func(int, bool) bool
|
||||||
@@ -274,13 +275,21 @@ func NewCompactTracklistRow(tracklist *Tracklist, playingIcon fyne.CanvasObject)
|
|||||||
func (t *tracklistRowBase) create(tracklist *Tracklist) {
|
func (t *tracklistRowBase) create(tracklist *Tracklist) {
|
||||||
t.tracklist = tracklist
|
t.tracklist = tracklist
|
||||||
t.num = util.NewTrailingAlignLabel()
|
t.num = util.NewTrailingAlignLabel()
|
||||||
t.name = util.NewTruncatingRichText()
|
t.name = util.NewTruncatingTooltipRichText()
|
||||||
|
t.name.OnMouseIn = t.MouseIn
|
||||||
|
t.name.OnMouseOut = t.MouseOut
|
||||||
t.artist = NewMultiHyperlink()
|
t.artist = NewMultiHyperlink()
|
||||||
t.artist.OnTapped = tracklist.onArtistTapped
|
t.artist.OnTapped = tracklist.onArtistTapped
|
||||||
|
t.artist.OnMouseIn = t.MouseIn
|
||||||
|
t.artist.OnMouseOut = t.MouseOut
|
||||||
t.album = NewMultiHyperlink()
|
t.album = NewMultiHyperlink()
|
||||||
t.album.OnTapped = func(id string) { tracklist.onAlbumTapped(id) }
|
t.album.OnTapped = func(id string) { tracklist.onAlbumTapped(id) }
|
||||||
|
t.album.OnMouseIn = t.MouseIn
|
||||||
|
t.album.OnMouseOut = t.MouseOut
|
||||||
t.composer = NewMultiHyperlink()
|
t.composer = NewMultiHyperlink()
|
||||||
t.composer.OnTapped = func(id string) { tracklist.onArtistTapped(id) }
|
t.composer.OnTapped = func(id string) { tracklist.onArtistTapped(id) }
|
||||||
|
t.composer.OnMouseIn = t.MouseIn
|
||||||
|
t.composer.OnMouseOut = t.MouseOut
|
||||||
t.dur = util.NewTrailingAlignLabel()
|
t.dur = util.NewTrailingAlignLabel()
|
||||||
t.year = util.NewTrailingAlignLabel()
|
t.year = util.NewTrailingAlignLabel()
|
||||||
favorite := NewFavoriteIcon()
|
favorite := NewFavoriteIcon()
|
||||||
@@ -291,10 +300,14 @@ func (t *tracklistRowBase) create(tracklist *Tracklist) {
|
|||||||
t.rating.StarSize = 16
|
t.rating.StarSize = 16
|
||||||
t.rating.OnRatingChanged = t.setTrackRating
|
t.rating.OnRatingChanged = t.setTrackRating
|
||||||
t.plays = util.NewTrailingAlignLabel()
|
t.plays = util.NewTrailingAlignLabel()
|
||||||
t.comment = util.NewTruncatingLabel()
|
t.comment = util.NewTruncatingTooltipLabel()
|
||||||
|
t.comment.OnMouseIn = t.MouseIn
|
||||||
|
t.comment.OnMouseOut = t.MouseOut
|
||||||
t.bitrate = util.NewTrailingAlignLabel()
|
t.bitrate = util.NewTrailingAlignLabel()
|
||||||
t.size = util.NewTrailingAlignLabel()
|
t.size = util.NewTrailingAlignLabel()
|
||||||
t.path = util.NewTruncatingLabel()
|
t.path = util.NewTruncatingTooltipLabel()
|
||||||
|
t.path.OnMouseIn = t.MouseIn
|
||||||
|
t.path.OnMouseOut = t.MouseOut
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tracklistRowBase) SetOnTappedSecondary(f func(*fyne.PointEvent, int)) {
|
func (t *tracklistRowBase) SetOnTappedSecondary(f func(*fyne.PointEvent, int)) {
|
||||||
@@ -319,6 +332,7 @@ func (t *tracklistRowBase) Update(tm *util.TrackListModel, rowNum int) {
|
|||||||
t.trackID = id
|
t.trackID = id
|
||||||
|
|
||||||
t.name.Segments[0].(*widget.TextSegment).Text = tr.Title
|
t.name.Segments[0].(*widget.TextSegment).Text = tr.Title
|
||||||
|
t.name.SetToolTip(tr.Title)
|
||||||
t.artist.BuildSegments(tr.ArtistNames, tr.ArtistIDs)
|
t.artist.BuildSegments(tr.ArtistNames, tr.ArtistIDs)
|
||||||
t.album.BuildSegments([]string{tr.Album}, []string{tr.AlbumID})
|
t.album.BuildSegments([]string{tr.Album}, []string{tr.AlbumID})
|
||||||
t.composer.BuildSegments(tr.ComposerNames, tr.ComposerIDs)
|
t.composer.BuildSegments(tr.ComposerNames, tr.ComposerIDs)
|
||||||
@@ -326,9 +340,11 @@ func (t *tracklistRowBase) Update(tm *util.TrackListModel, rowNum int) {
|
|||||||
t.year.Text = strconv.Itoa(tr.Year)
|
t.year.Text = strconv.Itoa(tr.Year)
|
||||||
t.plays.Text = strconv.Itoa(int(tr.PlayCount))
|
t.plays.Text = strconv.Itoa(int(tr.PlayCount))
|
||||||
t.comment.Text = tr.Comment
|
t.comment.Text = tr.Comment
|
||||||
|
t.comment.SetToolTip(tr.Comment)
|
||||||
t.bitrate.Text = strconv.Itoa(tr.BitRate)
|
t.bitrate.Text = strconv.Itoa(tr.BitRate)
|
||||||
t.size.Text = util.BytesToSizeString(tr.Size)
|
t.size.Text = util.BytesToSizeString(tr.Size)
|
||||||
t.path.Text = tr.FilePath
|
t.path.Text = tr.FilePath
|
||||||
|
t.path.SetToolTip(tr.FilePath)
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user