diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f013995..1c5e95a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,35 @@ All notable GoSentry changes are recorded in this file. +## 0.10.2 - 2026-06-25 + +**Condensed details/settings panels and a window that shrinks to 720p.** + +**Jobs details panel:** +- Job metadata is laid out in two columns (Folder/Schedule, Command/Arguments, + Run mode/Overlap policy, Last run/Next run, State/Statistics), roughly halving + the block height. +- Metadata rows are stacked with a tight, negative-gap layout so the interval + between rows is no longer oversized. +- The command-output area's minimum height was reduced so the details pane can + get shorter; long output still scrolls. +- The "Selected job activity" panel is now sized to exactly fit + `maxJobActivityRows`, derived from `widget.List`'s own row metrics, so all + three rows are visible without a scrollbar regardless of theme or DPI. + +**Settings tab:** +- The form is wrapped in a vertical scroll so it no longer dictates the window's + minimum height (tab containers size to the tallest tab); it scrolls on short + screens instead. +- Label-only sections (Application, Queue, About) are condensed, while + separators and the editable Storage fields keep normal spacing so dividers + have breathing room and entry boxes stay visibly separated. + +**Window sizing:** +- Together these changes drop the minimum window height from ~891px to ~570px, + so the window can be resized noticeably shorter and fits comfortably on 720p + screens. + ## 0.10.1 - 2026-06-24 **Refactoring:** diff --git a/src/app/version.go b/src/app/version.go index 7030beb..13b285c 100644 --- a/src/app/version.go +++ b/src/app/version.go @@ -3,4 +3,4 @@ package app // Version is the application version shown in the GUI and used by build // scripts in artifact names. It is a var rather than a const so release builds // can override it with Go ldflags when CI tags a build. -var Version = "0.10.1" +var Version = "0.10.2" diff --git a/src/ui/settings_view.go b/src/ui/settings_view.go index f9089d9..7c98878 100644 --- a/src/ui/settings_view.go +++ b/src/ui/settings_view.go @@ -123,37 +123,59 @@ func settingsView(w fyne.Window, svc *app.Service) fyne.CanvasObject { settingsStatus.SetText("Saved") }) - // The settings form is a tall fixed-height column. Wrapping it in a vertical - // scroll keeps its minimum height small so it does not dictate the whole - // window's minimum height (AppTabs sizes to the tallest tab); on short 720p - // screens the window can shrink and the form scrolls instead. - return container.NewVScroll(container.NewPadded(container.New(compactVBoxLayout{spacing: settingsRowSpacing}, - widget.NewLabelWithStyle("Application", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), - settingsRowWithStatus("Autostart", startOnLogin, autostartStatus), - settingsRow("Tray", container.New(minWidthLayout{width: settingsControlWidth}, minimizeToTray)), - settingsRow("Notifications", container.New(minWidthLayout{width: settingsControlWidth}, notifications)), + // The form is grouped into sections in an outer VBox. The outer box keeps the + // theme's normal padding, so the separators and the editable Storage fields + // get proper breathing room; only the label-only sections are condensed with + // the tight settingsSection spacing. Wrapping the whole thing in a vertical + // scroll keeps its minimum height small so it does not dictate the window's + // minimum height (AppTabs sizes to the tallest tab) and it scrolls on short + // 720p screens. + return container.NewVScroll(container.NewPadded(container.NewVBox( + settingsSection("Application", + settingsRowWithStatus("Autostart", startOnLogin, autostartStatus), + settingsRow("Tray", container.New(minWidthLayout{width: settingsControlWidth}, minimizeToTray)), + settingsRow("Notifications", container.New(minWidthLayout{width: settingsControlWidth}, notifications)), + ), widget.NewSeparator(), - widget.NewLabelWithStyle("Queue", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), - settingsRow("Execution mode", container.New(minWidthLayout{width: settingsControlWidth}, executionModeSelect)), - settingsRow("Default overlap policy", container.New(minWidthLayout{width: settingsControlWidth}, overlapPolicySelect)), + settingsSection("Queue", + settingsRow("Execution mode", container.New(minWidthLayout{width: settingsControlWidth}, executionModeSelect)), + settingsRow("Default overlap policy", container.New(minWidthLayout{width: settingsControlWidth}, overlapPolicySelect)), + ), widget.NewSeparator(), - widget.NewLabelWithStyle("Storage", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), - settingsRow("Config YAML", widget.NewLabel(store.Paths.ConfigPath)), - settingsRow("Jobs directory", container.NewBorder(nil, nil, nil, jobsDirBrowse, jobsDir)), - settingsRow("Logs directory", container.NewBorder(nil, nil, nil, logsDirBrowse, logsDir)), - settingsRow("Max log files", maxLogFiles), - settingsRow("Max log age days", maxLogAgeDays), + // Storage holds editable entry fields. It uses the default VBox spacing + // (not the condensed section layout) so the entry boxes keep a visible + // gap between them instead of merging into one block. + container.NewVBox( + widget.NewLabelWithStyle("Storage", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), + settingsRow("Config YAML", widget.NewLabel(store.Paths.ConfigPath)), + settingsRow("Jobs directory", container.NewBorder(nil, nil, nil, jobsDirBrowse, jobsDir)), + settingsRow("Logs directory", container.NewBorder(nil, nil, nil, logsDirBrowse, logsDir)), + settingsRow("Max log files", maxLogFiles), + settingsRow("Max log age days", maxLogAgeDays), + ), saveSettings, settingsStatus, widget.NewSeparator(), - widget.NewLabelWithStyle("About", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), - settingsRow("GoSentry", widget.NewLabel(app.Version)), - settingsRow("Go", widget.NewLabel(runtime.Version())), - settingsRow("Fyne", widget.NewLabel(fyneVersion())), - settingsRow("Repository", widget.NewHyperlink(projectRepositoryURL, mustParseURL(projectRepositoryURL))), + settingsSection("About", + settingsRow("GoSentry", widget.NewLabel(app.Version)), + settingsRow("Go", widget.NewLabel(runtime.Version())), + settingsRow("Fyne", widget.NewLabel(fyneVersion())), + settingsRow("Repository", widget.NewHyperlink(projectRepositoryURL, mustParseURL(projectRepositoryURL))), + ), ))) } +// settingsSection groups a bold header above its rows using the tight +// settingsRowSpacing so a block of label rows reads as one compact unit. The +// caller keeps separators and entry-heavy sections in the surrounding VBox so +// they retain the theme's normal spacing. +func settingsSection(title string, rows ...fyne.CanvasObject) fyne.CanvasObject { + children := make([]fyne.CanvasObject, 0, len(rows)+1) + children = append(children, widget.NewLabelWithStyle(title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true})) + children = append(children, rows...) + return container.New(compactVBoxLayout{spacing: settingsRowSpacing}, children...) +} + func fyneVersion() string { info, ok := debug.ReadBuildInfo() if !ok {