diff --git a/backend/app.go b/backend/app.go index d4c53a0..7ad8109 100644 --- a/backend/app.go +++ b/backend/app.go @@ -46,6 +46,8 @@ type App struct { appName string appVersionTag string configFile string + + isFirstLaunch bool // set by config file reader bgrndCtx context.Context cancel context.CancelFunc } @@ -119,14 +121,23 @@ func StartupApp(appName, displayAppName, appVersionTag, configFile, latestReleas return a, nil } +func (a *App) IsFirstLaunch() bool { + return a.isFirstLaunch +} + func (a *App) readConfig() { configdir.MakePath(configdir.LocalConfig(a.appName)) cfgPath := a.configPath() + var cfgExists bool + if _, err := os.Stat(cfgPath); err == nil { + cfgExists = true + } + a.isFirstLaunch = !cfgExists cfg, err := ReadConfigFile(cfgPath, a.appVersionTag) if err != nil { log.Printf("Error reading app config file: %v", err) cfg = DefaultConfig(a.appVersionTag) - if _, err := os.Stat(cfgPath); err == nil { + if cfgExists { backupCfgName := fmt.Sprintf("%s.bak", a.configFile) log.Printf("Config file may be malformed: copying to %s", backupCfgName) _ = util.CopyFile(cfgPath, path.Join(configdir.LocalConfig(a.appName), backupCfgName)) diff --git a/backend/config.go b/backend/config.go index 5c7e02c..effe782 100644 --- a/backend/config.go +++ b/backend/config.go @@ -25,6 +25,7 @@ type AppConfig struct { WindowWidth int WindowHeight int LastCheckedVersion string + LastLaunchedVersion string EnableSystemTray bool CloseToSystemTray bool StartupPage string @@ -128,6 +129,7 @@ func DefaultConfig(appVersionTag string) *Config { WindowWidth: 1000, WindowHeight: 800, LastCheckedVersion: appVersionTag, + LastLaunchedVersion: "", EnableSystemTray: true, CloseToSystemTray: false, StartupPage: "Albums", diff --git a/main.go b/main.go index 6a6db2c..d52ff7f 100644 --- a/main.go +++ b/main.go @@ -14,17 +14,10 @@ import ( "fyne.io/fyne/v2/app" ) -const ( - appname = "supersonic" - displayName = "Supersonic" - appVersion = "0.6.0" - appVersionTag = "v" + appVersion - configFile = "config.toml" - latestReleaseURL = "https://github.com/dweymouth/supersonic/releases/latest" -) +const configFile = "config.toml" func main() { - myApp, err := backend.StartupApp(appname, displayName, appVersionTag, configFile, latestReleaseURL) + myApp, err := backend.StartupApp(res.AppName, res.DisplayName, res.AppVersionTag, configFile, res.LatestReleaseURL) if err != nil { log.Fatalf("fatal startup error: %v", err.Error()) } @@ -40,7 +33,7 @@ func main() { if h <= 1 { h = 800 } - mainWindow := ui.NewMainWindow(fyneApp, appname, displayName, appVersion, myApp, fyne.NewSize(w, h)) + mainWindow := ui.NewMainWindow(fyneApp, res.AppName, res.DisplayName, res.AppVersion, myApp, fyne.NewSize(w, h)) myApp.OnReactivate = mainWindow.Show myApp.OnExit = func() { saveWindowSize(myApp.Config, mainWindow.Window) diff --git a/res/metadata.go b/res/metadata.go new file mode 100644 index 0000000..2391d40 --- /dev/null +++ b/res/metadata.go @@ -0,0 +1,39 @@ +package res + +import ( + "fmt" + "runtime" +) + +const ( + AppName = "supersonic" + DisplayName = "Supersonic" + AppVersion = "0.6.0" + AppVersionTag = "v" + AppVersion + ConfigFile = "config.toml" + GithubURL = "https://github.com/dweymouth/supersonic" + LatestReleaseURL = GithubURL + "/releases/latest" + KofiURL = "https://ko-fi.com/dweymouth" +) + +func shortcutKey() string { + if runtime.GOOS == "darwin" { + return "Cmd" + } + return "Ctrl" +} + +var ( + WhatsAdded = fmt.Sprintf(` +### Added +* New "Quick search" feature to search entire library from anywhere (%s+G shortcut) +* Support for loading WEBP images +* UI Refresh from migrating to Fyne 2.4 +* New [custom theme](https://github.com/dweymouth/supersonic/wiki/Custom-Themes) color keys: Hyperlink and PageHeader (theme file syntax "0.2") +* Added playback setting to force-disable server transcoding`, shortcutKey()) + + WhatsFixed = ` +### Fixed +* UI hang when playback slow to begin after clicking on grid view play buttons +* Crash when removing from the currently playing track to end of play queue` +) diff --git a/ui/dialogs/aboutdialog.go b/ui/dialogs/aboutdialog.go index 7e10ba8..fb1ecbe 100644 --- a/ui/dialogs/aboutdialog.go +++ b/ui/dialogs/aboutdialog.go @@ -66,8 +66,8 @@ func (a *AboutDialog) buildMainTabContainer(version string) *fyne.Container { ts := license.Segments[0].(*widget.TextSegment) ts.Style.TextStyle.Bold = true ts.Style.Alignment = fyne.TextAlignCenter - ghUrl, _ := url.Parse("https://github.com/dweymouth/supersonic") - kofiUrl, _ := url.Parse("https://ko-fi.com/dweymouth") + ghUrl, _ := url.Parse(res.GithubURL) + kofiUrl, _ := url.Parse(res.KofiURL) githubKofi := container.NewCenter( container.New(&layouts.HboxCustomPadding{DisableThemePad: true, ExtraPad: -10}, widget.NewHyperlink("Github page", ghUrl), diff --git a/ui/dialogs/whatsnewdialog.go b/ui/dialogs/whatsnewdialog.go new file mode 100644 index 0000000..da53c63 --- /dev/null +++ b/ui/dialogs/whatsnewdialog.go @@ -0,0 +1,51 @@ +package dialogs + +import ( + "net/url" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "github.com/dweymouth/supersonic/res" + "github.com/dweymouth/supersonic/ui/layouts" +) + +type WhatsNewDialog struct { + widget.BaseWidget +} + +func NewWhatsNewDialog() *WhatsNewDialog { + w := &WhatsNewDialog{} + w.ExtendBaseWidget(w) + return w +} + +func (w *WhatsNewDialog) CreateRenderer() fyne.WidgetRenderer { + objects := container.NewVBox() + if res.WhatsAdded != "" { + added := widget.NewRichTextFromMarkdown(res.WhatsAdded) + added.Wrapping = fyne.TextWrapWord + objects.Add(added) + } + if res.WhatsFixed != "" { + fixed := widget.NewRichTextFromMarkdown(res.WhatsFixed) + fixed.Wrapping = fyne.TextWrapWord + objects.Add(fixed) + } + + ghUrl, _ := url.Parse(res.GithubURL) + kofiUrl, _ := url.Parse(res.KofiURL) + githubKofi := container.NewCenter( + container.New(&layouts.HboxCustomPadding{DisableThemePad: true, ExtraPad: -10}, + widget.NewHyperlink("Github page", ghUrl), + widget.NewLabel("ยท"), + widget.NewHyperlink("Support the project", kofiUrl))) + objects.Add(githubKofi) + + c := container.NewVScroll(objects) + return widget.NewSimpleRenderer(c) +} + +func (w *WhatsNewDialog) MinSize() fyne.Size { + return fyne.NewSize(400, 250) +} diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 65ffd26..5524459 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -10,6 +10,7 @@ import ( "github.com/dweymouth/supersonic/res" "github.com/dweymouth/supersonic/ui/browsing" "github.com/dweymouth/supersonic/ui/controller" + "github.com/dweymouth/supersonic/ui/dialogs" "github.com/dweymouth/supersonic/ui/os" "github.com/dweymouth/supersonic/ui/theme" @@ -93,8 +94,13 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, app.ServerManager.OnServerConnected(func() { m.BrowsingPane.EnableNavigationButtons() m.Router.NavigateTo(m.StartupPage()) - // check if found new version on startup - if t := app.UpdateChecker.VersionTagFound(); t != "" && t != app.Config.Application.LastCheckedVersion { + // check if launching new version, else if found available update on startup + if l := app.Config.Application.LastLaunchedVersion; app.VersionTag() != l { + if !app.IsFirstLaunch() { + m.ShowWhatsNewDialog() + } + m.App.Config.Application.LastLaunchedVersion = app.VersionTag() + } else if t := app.UpdateChecker.VersionTagFound(); t != "" && t != app.Config.Application.LastCheckedVersion { if t != app.VersionTag() { m.ShowNewVersionDialog(displayAppName, t) } @@ -202,6 +208,10 @@ func (m *MainWindow) ShowNewVersionDialog(appName, versionTag string) { }) } +func (m *MainWindow) ShowWhatsNewDialog() { + dialog.ShowCustom("What's new in "+res.AppVersion, "Close", dialogs.NewWhatsNewDialog(), m.Window) +} + func (m *MainWindow) addNavigationButtons() { m.BrowsingPane.AddNavigationButton(theme.NowPlayingIcon, func() { m.Router.NavigateTo(controller.NowPlayingRoute(""))