show dialog on later version found
This commit is contained in:
@@ -36,6 +36,10 @@ type App struct {
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (a *App) VersionTag() string {
|
||||
return a.appVersionTag
|
||||
}
|
||||
|
||||
func StartupApp(appName, appVersionTag, configFile, latestReleaseURL string) (*App, error) {
|
||||
a := &App{appName: appName, appVersionTag: appVersionTag, configFile: configFile}
|
||||
a.bgrndCtx, a.cancel = context.WithCancel(context.Background())
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UpdateChecker struct {
|
||||
OnUpdatedVersionFound func(releaseURL string)
|
||||
OnUpdatedVersionFound func()
|
||||
|
||||
foundUpdate bool
|
||||
versionTagFound string
|
||||
latestReleaseURL string
|
||||
appVersionTag string
|
||||
lastCheckedTag *string
|
||||
@@ -41,17 +42,21 @@ func (u *UpdateChecker) Start(ctx context.Context, interval time.Duration) {
|
||||
}()
|
||||
}
|
||||
|
||||
func (u *UpdateChecker) UpdateAvailable() bool {
|
||||
return u.foundUpdate
|
||||
func (u *UpdateChecker) VersionTagFound() string {
|
||||
return u.versionTagFound
|
||||
}
|
||||
|
||||
func (u *UpdateChecker) LatestReleaseURL() *url.URL {
|
||||
url, _ := url.Parse(u.latestReleaseURL)
|
||||
return url
|
||||
}
|
||||
|
||||
func (u *UpdateChecker) checkForUpdate() {
|
||||
t := u.latestVersionTag()
|
||||
if t != "" && t != *u.lastCheckedTag {
|
||||
u.foundUpdate = true
|
||||
*u.lastCheckedTag = t
|
||||
u.versionTagFound = t
|
||||
if u.OnUpdatedVersionFound != nil {
|
||||
u.OnUpdatedVersionFound(u.latestReleaseURL)
|
||||
u.OnUpdatedVersionFound()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,16 @@ type ReloadFunc func()
|
||||
type CurPageFunc func() Route
|
||||
|
||||
type Controller struct {
|
||||
// if not nil, this popup should be hidden when escape is pressed
|
||||
EscapablePopUp *widget.PopUp
|
||||
|
||||
AppVersion string
|
||||
MainWindow fyne.Window
|
||||
App *backend.App
|
||||
NavHandler NavigationHandler
|
||||
CurPageFunc CurPageFunc
|
||||
ReloadFunc ReloadFunc
|
||||
|
||||
escapablePopUp *widget.PopUp
|
||||
haveModal bool
|
||||
runOnModalClosed func()
|
||||
}
|
||||
|
||||
func (m *Controller) NavigateTo(route Route) {
|
||||
@@ -41,7 +42,26 @@ func (m *Controller) NavigateTo(route Route) {
|
||||
}
|
||||
|
||||
func (m *Controller) ClosePopUpOnEscape(pop *widget.PopUp) {
|
||||
m.EscapablePopUp = pop
|
||||
m.escapablePopUp = pop
|
||||
}
|
||||
|
||||
func (m *Controller) CloseEscapablePopUp() {
|
||||
if m.escapablePopUp != nil {
|
||||
m.escapablePopUp.Hide()
|
||||
m.escapablePopUp = nil
|
||||
m.doModalClosed()
|
||||
}
|
||||
}
|
||||
|
||||
// If there is currently no modal popup managed by the Controller visible,
|
||||
// then run f (which should create and show a modal dialog) immediately.
|
||||
// else run f when the current modal dialog workflow has ended.
|
||||
func (m *Controller) QueueShowModalFunc(f func()) {
|
||||
if m.haveModal {
|
||||
m.runOnModalClosed = f
|
||||
} else {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Controller) ShowPopUpImage(img image.Image) {
|
||||
@@ -110,6 +130,7 @@ func (m *Controller) PromptForFirstServer() {
|
||||
if m.testConnectionAndUpdateDialogText(d) {
|
||||
// connection is good
|
||||
pop.Hide()
|
||||
m.doModalClosed()
|
||||
server := m.App.Config.AddServer(d.Nickname, d.Host, d.Username, d.LegacyAuth)
|
||||
if err := m.App.ServerManager.SetServerPassword(server, d.Password); err != nil {
|
||||
log.Printf("error setting keyring credentials: %v", err)
|
||||
@@ -120,6 +141,7 @@ func (m *Controller) PromptForFirstServer() {
|
||||
d.EnableSubmit()
|
||||
}()
|
||||
}
|
||||
m.haveModal = true
|
||||
pop.Show()
|
||||
}
|
||||
|
||||
@@ -144,6 +166,7 @@ func (m *Controller) DoAddTracksToPlaylistWorkflow(trackIDs []string) {
|
||||
dlg.OnCanceled = pop.Hide
|
||||
dlg.OnSubmit = func(playlistChoice int, newPlaylistName string) {
|
||||
pop.Hide()
|
||||
m.doModalClosed()
|
||||
if playlistChoice < 0 {
|
||||
m.App.ServerManager.Server.CreatePlaylistWithTracks(
|
||||
trackIDs, map[string]string{"name": newPlaylistName})
|
||||
@@ -152,6 +175,7 @@ func (m *Controller) DoAddTracksToPlaylistWorkflow(trackIDs []string) {
|
||||
pls[playlistChoice].ID, trackIDs, nil /*tracksToRemove*/)
|
||||
}
|
||||
}
|
||||
m.haveModal = true
|
||||
pop.Show()
|
||||
}
|
||||
|
||||
@@ -159,7 +183,10 @@ func (m *Controller) DoEditPlaylistWorkflow(playlist *subsonic.Playlist) {
|
||||
dlg := dialogs.NewEditPlaylistDialog(playlist)
|
||||
pop := widget.NewModalPopUp(dlg, m.MainWindow.Canvas())
|
||||
m.ClosePopUpOnEscape(pop)
|
||||
dlg.OnCanceled = pop.Hide
|
||||
dlg.OnCanceled = func() {
|
||||
pop.Hide()
|
||||
m.doModalClosed()
|
||||
}
|
||||
dlg.OnDeletePlaylist = func() {
|
||||
pop.Hide()
|
||||
dialog.ShowCustomConfirm("Confirm Delete Playlist", "OK", "Cancel", layout.NewSpacer(), /*custom content*/
|
||||
@@ -167,6 +194,7 @@ func (m *Controller) DoEditPlaylistWorkflow(playlist *subsonic.Playlist) {
|
||||
if !ok {
|
||||
pop.Show()
|
||||
} else {
|
||||
m.doModalClosed()
|
||||
go func() {
|
||||
if err := m.App.ServerManager.Server.DeletePlaylist(playlist.ID); err != nil {
|
||||
log.Printf("error deleting playlist: %s", err.Error())
|
||||
@@ -180,6 +208,7 @@ func (m *Controller) DoEditPlaylistWorkflow(playlist *subsonic.Playlist) {
|
||||
}
|
||||
dlg.OnUpdateMetadata = func() {
|
||||
pop.Hide()
|
||||
m.doModalClosed()
|
||||
go func() {
|
||||
err := m.App.ServerManager.Server.UpdatePlaylist(playlist.ID, map[string]string{
|
||||
"name": dlg.Name,
|
||||
@@ -194,6 +223,7 @@ func (m *Controller) DoEditPlaylistWorkflow(playlist *subsonic.Playlist) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
m.haveModal = true
|
||||
pop.Show()
|
||||
}
|
||||
|
||||
@@ -208,6 +238,7 @@ func (c *Controller) DoConnectToServerWorkflow(server *backend.ServerConfig) {
|
||||
dlg.SetOnClosed(func() {
|
||||
c.PromptForLoginAndConnect()
|
||||
})
|
||||
c.haveModal = true
|
||||
dlg.Show()
|
||||
}
|
||||
}
|
||||
@@ -230,6 +261,7 @@ func (m *Controller) PromptForLoginAndConnect() {
|
||||
} else {
|
||||
pop.Hide()
|
||||
m.trySetPasswordAndConnectToServer(server, password)
|
||||
m.doModalClosed()
|
||||
}
|
||||
d.EnableSubmit()
|
||||
}()
|
||||
@@ -249,20 +281,26 @@ func (m *Controller) PromptForLoginAndConnect() {
|
||||
server.Username = editD.Username
|
||||
server.LegacyAuth = editD.LegacyAuth
|
||||
m.trySetPasswordAndConnectToServer(server, editD.Password)
|
||||
m.doModalClosed()
|
||||
}
|
||||
d.EnableSubmit()
|
||||
}()
|
||||
}
|
||||
editPop.Show()
|
||||
}
|
||||
m.haveModal = true
|
||||
pop.Show()
|
||||
}
|
||||
|
||||
func (c *Controller) ShowAboutDialog() {
|
||||
dlg := dialogs.NewAboutDialog(c.AppVersion)
|
||||
pop := widget.NewModalPopUp(dlg, c.MainWindow.Canvas())
|
||||
dlg.OnDismiss = pop.Hide
|
||||
dlg.OnDismiss = func() {
|
||||
pop.Hide()
|
||||
c.doModalClosed()
|
||||
}
|
||||
c.ClosePopUpOnEscape(pop)
|
||||
c.haveModal = true
|
||||
pop.Show()
|
||||
}
|
||||
|
||||
@@ -299,3 +337,11 @@ func (c *Controller) testConnectionAndUpdateDialogText(dlg *dialogs.AddEditServe
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Controller) doModalClosed() {
|
||||
c.haveModal = false
|
||||
if c.runOnModalClosed != nil {
|
||||
c.runOnModalClosed()
|
||||
c.runOnModalClosed = nil
|
||||
}
|
||||
}
|
||||
|
||||
+28
-4
@@ -2,6 +2,7 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"supersonic/backend"
|
||||
"supersonic/res"
|
||||
"supersonic/ui/browsing"
|
||||
@@ -10,7 +11,9 @@ import (
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/driver/desktop"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/dweymouth/go-subsonic/subsonic"
|
||||
)
|
||||
|
||||
@@ -79,6 +82,14 @@ func NewMainWindow(fyneApp fyne.App, appName, appVersion string, app *backend.Ap
|
||||
app.ServerManager.OnServerConnected(func() {
|
||||
m.BrowsingPane.EnableNavigationButtons()
|
||||
m.Router.NavigateTo(HomePage)
|
||||
// check if found new version on startup
|
||||
if t := app.UpdateChecker.VersionTagFound(); t != "" && t != app.Config.Application.LastCheckedVersion {
|
||||
m.ShowNewVersionDialog(appName, t)
|
||||
}
|
||||
// register callback for the ongoing periodic update check
|
||||
m.App.UpdateChecker.OnUpdatedVersionFound = func() {
|
||||
m.ShowNewVersionDialog(appName, m.App.UpdateChecker.VersionTagFound())
|
||||
}
|
||||
})
|
||||
app.ServerManager.OnLogout(func() {
|
||||
m.BrowsingPane.DisableNavigationButtons()
|
||||
@@ -94,6 +105,22 @@ func NewMainWindow(fyneApp fyne.App, appName, appVersion string, app *backend.Ap
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MainWindow) ShowNewVersionDialog(appName, versionTag string) {
|
||||
contentStr := fmt.Sprintf("A new version of %s (%s) is available",
|
||||
appName, versionTag)
|
||||
m.Controller.QueueShowModalFunc(func() {
|
||||
dialog.ShowCustomConfirm("A new version is available",
|
||||
"Go to release page", "Skip this version",
|
||||
widget.NewLabel(contentStr), func(show bool) {
|
||||
if show {
|
||||
fyne.CurrentApp().OpenURL(m.App.UpdateChecker.LatestReleaseURL())
|
||||
}
|
||||
m.App.Config.Application.LastCheckedVersion = versionTag
|
||||
log.Printf("reset version: %s", m.App.Config.Application.LastCheckedVersion)
|
||||
}, m.Window)
|
||||
})
|
||||
}
|
||||
|
||||
func (m *MainWindow) addNavigationButtons() {
|
||||
m.BrowsingPane.AddNavigationButton(res.ResHeadphonesInvertPng, func() {
|
||||
m.Router.NavigateTo(controller.NowPlayingRoute())
|
||||
@@ -153,10 +180,7 @@ func (m *MainWindow) addShortcuts() {
|
||||
m.Canvas().SetOnTypedKey(func(e *fyne.KeyEvent) {
|
||||
switch e.Name {
|
||||
case fyne.KeyEscape:
|
||||
if m.Controller.EscapablePopUp != nil {
|
||||
m.Controller.EscapablePopUp.Hide()
|
||||
m.Controller.EscapablePopUp = nil
|
||||
}
|
||||
m.Controller.CloseEscapablePopUp()
|
||||
case fyne.KeySpace:
|
||||
m.App.Player.PlayPause()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user