Skip to content

Commit

Permalink
Add about dialog and window for helping apps make a pretty about scre…
Browse files Browse the repository at this point in the history
…en (#87)

Co-authored-by: Jacob Alzén <jacalz@tutanota.com>
  • Loading branch information
andydotxyz and Jacalz committed Mar 26, 2024
1 parent 61d0ff4 commit 3ba9170
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,23 @@ m := NewMap()

![](img/map.png)

## Dialogs

### About

A cool parallax about dialog that pulls data from the app metadata and includes
some markup content and links at the bottom of the window/dialog.

```go
docURL, _ := url.Parse("https://docs.fyne.io")
links := []*widget.Hyperlink{
widget.NewHyperlink("Docs", docURL),
}
dialog.ShowAboutWindow("Some **cool** stuff", links, a)
```

![](img/about.png)

## Data Binding

Community contributed data sources for binding.
Expand Down
4 changes: 4 additions & 0 deletions cmd/fyne-x/FyneApp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Details]
Icon = "Icon.png"
Version = "0.1.0"
Build = 5
Binary file added cmd/fyne-x/Icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions cmd/fyne-x/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"net/url"

"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
"fyne.io/x/fyne/dialog"
)

func main() {
a := app.New()
w := a.NewWindow("Fyne-x demo")

docURL, _ := url.Parse("https://docs.fyne.io")
links := []*widget.Hyperlink{
widget.NewHyperlink("Docs", docURL),
}
w.SetContent(container.NewGridWithColumns(1,
widget.NewButton("About", func() {
dialog.ShowAbout("Some **cool** stuff", links, a, w)
}),
widget.NewButton("About window", func() {
dialog.ShowAboutWindow("Some **cool** stuff", links, a)
}),
))

w.ShowAndRun()
}
175 changes: 175 additions & 0 deletions dialog/about.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package dialog

import (
"image/color"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)

// NewAbout creates a parallax about dialog using the app metadata along with the
// markdown content and links passed into this method.
// You should call Show on the returned dialog to display it.
func NewAbout(content string, links []*widget.Hyperlink, a fyne.App, w fyne.Window) dialog.Dialog {
d := dialog.NewCustom("About", "OK", aboutContent(content, links, a), w)
d.Resize(fyne.NewSize(400, 360))

return d
}

// NewAboutWindow creates a parallax about window using the app metadata along with the
// markdown content and links passed into this method.
// You should call Show on the returned window to display it.
func NewAboutWindow(content string, links []*widget.Hyperlink, a fyne.App) fyne.Window {
w := a.NewWindow("About")
w.SetContent(aboutContent(content, links, a))
w.Resize(fyne.NewSize(360, 300))

return w
}

// ShowAbout opens a parallax about dialog using the app metadata along with the
// markdown content and links passed into this method.
func ShowAbout(content string, links []*widget.Hyperlink, a fyne.App, w fyne.Window) {
d := NewAbout(content, links, a, w)
d.Show()
}

// ShowAboutWindow opens a parallax about window using the app metadata along with the
// markdown content and links passed into this method.
func ShowAboutWindow(content string, links []*widget.Hyperlink, a fyne.App) {
w := NewAboutWindow(content, links, a)
w.Show()
}

func aboutContent(content string, links []*widget.Hyperlink, a fyne.App) fyne.CanvasObject {
rich := widget.NewRichTextFromMarkdown(content)
footer := aboutFooter(links)

logo := canvas.NewImageFromResource(a.Metadata().Icon)
logo.FillMode = canvas.ImageFillContain
logo.SetMinSize(fyne.NewSize(128, 128))

appData := widget.NewRichTextFromMarkdown(
"## " + a.Metadata().Name + "\n**Version:** " + a.Metadata().Version)
centerText(appData)
space := canvas.NewRectangle(color.Transparent)
space.SetMinSize(fyne.NewSquareSize(theme.Padding() * 4))
body := container.NewVBox(
space,
logo,
appData,
container.NewCenter(rich))
scroll := container.NewScroll(body)

bgColor := withAlpha(theme.BackgroundColor(), 0xe0)
shadowColor := withAlpha(theme.BackgroundColor(), 0x33)

underlay := canvas.NewImageFromResource(a.Metadata().Icon)
bg := canvas.NewRectangle(bgColor)
underlayer := underLayout{}
slideBG := container.New(underlayer, underlay)
footerBG := canvas.NewRectangle(shadowColor)
watchTheme(bg, footerBG, a)

underlay.Resize(fyne.NewSize(512, 512))
scroll.OnScrolled = func(p fyne.Position) {
underlayer.offset = -p.Y / 3
underlayer.Layout(slideBG.Objects, slideBG.Size())
}

bgClip := container.NewScroll(slideBG)
bgClip.Direction = container.ScrollNone
return container.NewStack(container.New(unpad{top: true}, bgClip, bg),
container.NewBorder(nil,
container.NewStack(footerBG, footer), nil, nil,
container.New(unpad{top: true, bottom: true}, scroll)))
}

func aboutFooter(links []*widget.Hyperlink) fyne.CanvasObject {
footer := container.NewHBox(layout.NewSpacer())
for i, a := range links {
footer.Add(a)
if i < len(links)-1 {
footer.Add(widget.NewLabel("-"))
}
}
footer.Add(layout.NewSpacer())

return footer
}

func centerText(rich *widget.RichText) {
for _, s := range rich.Segments {
if text, ok := s.(*widget.TextSegment); ok {
text.Style.Alignment = fyne.TextAlignCenter
}
}
}

func watchTheme(bg, footer *canvas.Rectangle, a fyne.App) {
listen := make(chan fyne.Settings)
fyne.CurrentApp().Settings().AddChangeListener(listen)
go func() {
for range listen {
bgColor := withAlpha(theme.BackgroundColor(), 0xe0)
bg.FillColor = bgColor
bg.Refresh()

shadowColor := withAlpha(theme.BackgroundColor(), 0x33)
footer.FillColor = shadowColor
footer.Refresh()
}
}()
}

func withAlpha(c color.Color, alpha uint8) color.Color {
r, g, b, _ := c.RGBA()
return color.NRGBA{R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(b >> 8), A: alpha}
}

type underLayout struct {
offset float32
}

func (u underLayout) Layout(objs []fyne.CanvasObject, size fyne.Size) {
under := objs[0]
left := size.Width/2 - under.Size().Width/2
under.Move(fyne.NewPos(left, u.offset-50))
}

func (u underLayout) MinSize(_ []fyne.CanvasObject) fyne.Size {
return fyne.Size{}
}

type unpad struct {
top, bottom bool
}

func (u unpad) Layout(objs []fyne.CanvasObject, s fyne.Size) {
pad := theme.Padding()
var pos fyne.Position
if u.top {
pos.Y = -pad
}
size := s
if u.top {
size.Height += pad
}
if u.bottom {
size.Height += pad
}
for _, o := range objs {
o.Move(pos)
o.Resize(size)
}
}

func (u unpad) MinSize(_ []fyne.CanvasObject) fyne.Size {
return fyne.NewSize(100, 100)
}
Binary file added img/about-dialog.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/about.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3ba9170

Please sign in to comment.