go-xkcdreader/xkcdreader/app.go
surtur 0fc49afc6b
All checks were successful
continuous-integration/drone/push Build is passing
go: add current comic logic
2022-07-14 22:17:26 +02:00

271 lines
6.0 KiB
Go

// Copyright 2022 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: GPL-3.0-or-later
package xkcdreader
import (
"log"
"os"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/data/binding"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"git.dotya.ml/wanderer/go-xkcdreader/cmd"
"git.dotya.ml/wanderer/go-xkcdreader/xkcdreader/xkcd"
)
const appGreeting = "welcome to go-xkcdreader"
var (
a fyne.App
latestComic = xkcd.GetLatest()
currentComic = latestComic
cc xkcdcomic
)
// RunApp performs sets up and runs the main application.
func RunApp() {
// initialize the fyne application
newApp()
goxkcdreader := getApp()
w := goxkcdreader.NewWindow(cmd.GetAppName())
// mark this window as the main window
w.SetMaster()
centered := container.New(
layout.NewHBoxLayout(),
layout.NewSpacer(),
makeGreeting(),
layout.NewSpacer(),
)
w.SetContent(container.New(
layout.NewVBoxLayout(),
makeToolbar(),
centered,
makeTabs(),
))
w.Resize(fyne.NewSize(400, 400))
w.ShowAndRun()
}
func newApp() {
a = app.New()
log.Println("Created a new fyne application")
}
func getApp() fyne.App {
return a
}
// makeGreeting creates a greeting label.
func makeGreeting() *widget.Label {
w := widget.NewLabel(appGreeting)
w.TextStyle.Monospace = true
return w
}
func makeToolbar() *widget.Toolbar {
toolbar := widget.NewToolbar(
widget.NewToolbarSpacer(),
widget.NewToolbarAction(theme.HelpIcon(), func() {
log.Println("Display help")
}),
widget.NewToolbarAction(theme.SettingsIcon(), func() {
log.Println("Display settings")
}),
widget.NewToolbarAction(theme.InfoIcon(), aboutWindow),
)
return toolbar
}
func makeTabs() *container.AppTabs {
tabs := container.NewAppTabs(
container.NewTabItem("browse", makeBrowseUI()),
container.NewTabItem("what if?", widget.NewLabel("serious answers to absurd questions and absurd advice for common concerns from xkcd's Randall Munroe")),
container.NewTabItemWithIcon("search", theme.SearchIcon(), makeSearchTab()),
)
return tabs
}
func makeBrowseUI() *fyne.Container {
err := setCurrentComicBinding()
if err != nil {
log.Println(err)
}
cc.pic = getImg(currentComic.Img, false)
// container for the image and surrounding elements
imgC := container.New(
layout.NewHBoxLayout(),
widget.NewButtonWithIcon("", theme.NavigateBackIcon(), func() {
log.Println("Previous comic")
showPrevious()
cc.refreshComicPic(getImg(currentComic.Img, false))
}),
layout.NewSpacer(),
container.NewCenter(
// TODO(me): dynamically replace placeholder text with image once
// fetched...
// widget.NewLabel("img placeholder"),
cc.pic,
),
layout.NewSpacer(),
widget.NewButtonWithIcon("", theme.NavigateNextIcon(), func() {
log.Println("Next comic")
showNext()
}),
)
year := widget.NewLabelWithData(comicCurrent.year)
month := widget.NewLabelWithData(comicCurrent.month)
day := widget.NewLabelWithData(comicCurrent.day)
title := widget.NewLabelWithData(comicCurrent.title)
num := widget.NewLabelWithData(
binding.IntToString(comicCurrent.num),
)
altText := widget.NewLabelWithData(comicCurrent.alt)
title.TextStyle.Bold = true
num.TextStyle.Monospace = true
altText.TextStyle.Italic = true
altText.Wrapping = fyne.TextTruncate
altText.Alignment = fyne.TextAlignCenter
browseUI := container.New(
layout.NewVBoxLayout(),
// layout.NewSpacer(),
container.NewCenter(
container.NewVBox(
///&widget.Label{
/// Text: "published on " +
/// fmt.Sprint(
/// currentComic.Year, "-",
/// currentComic.Month, "-",
/// currentComic.Day,
/// ),
/// TextStyle: fyne.TextStyle{Italic: true},
///},
container.NewHBox(
year, month, day,
),
container.NewHBox(
///&widget.Label{
/// Text: currentComic.Title,
/// TextStyle: fyne.TextStyle{Bold: true},
///},
///&widget.Label{
/// Text: "(#" + fmt.Sprint(currentComic.Num) + ")",
/// TextStyle: fyne.TextStyle{Monospace: true},
///},
title,
num,
),
),
),
imgC,
// layout.NewSpacer(),
container.NewCenter(
// comic "alt text"
///&widget.Label{
/// Text: currentComic.Alt,
/// TextStyle: fyne.TextStyle{Italic: true},
///},
// container.NewCenter(
// container.NewAdaptiveGrid(
// 1,
// layout.NewSpacer(),
altText,
layout.NewSpacer(),
// ),
),
layout.NewSpacer(),
)
return browseUI
}
// getComicLatest fetches latest comic, updates latestComic if necessary.
func getComicLatest() {
comic := xkcd.GetLatest()
if comic == nil {
// TODO(me): properly handle the situation (i.e. bail early)
log.Println("error getting latest comic")
}
// update latesComic, if necessary
if latestComic != comic {
latestComic = comic
}
}
// get img from filesystem, resize it and return as *canvas.Image.
func getImg(imgURI string, local bool) *canvas.Image {
if local {
_, err := os.Stat(imgURI)
// properly handle error, perhaps panic?...don't panic, I know..
if err != nil {
log.Println("failed to read file " + imgURI)
return canvas.NewImageFromFile("")
}
img := canvas.NewImageFromFile(imgURI)
img.SetMinSize(
fyne.Size{
Height: 383,
Width: 273,
},
)
img.ScaleMode = canvas.ImageScaleSmooth
img.FillMode = canvas.ImageFillContain
return img
}
preImg, err := storage.ParseURI(imgURI)
if err != nil {
log.Printf("error parsing comic URI: %q", err.Error())
}
// get the actual image
img := canvas.NewImageFromURI(preImg)
log.Println("getImg: img name: ", img.Resource.Name())
if img.Resource == nil {
log.Println("error fetching the image file of the latest comic")
}
// set basic img properties
img.SetMinSize(
fyne.Size{
// subject to change, this is what I consider to be sane defaults
// atm...
Height: 650,
Width: 750,
},
)
img.ScaleMode = canvas.ImageScaleSmooth
img.FillMode = canvas.ImageFillContain
return img
}