Skip to content

Commit

Permalink
refactor: massive refactor on configuration logic and some minor adju…
Browse files Browse the repository at this point in the history
…stments on performance
  • Loading branch information
Elias-Gill committed Jan 29, 2025
1 parent 3d8d1b3 commit 355f065
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 129 deletions.
91 changes: 52 additions & 39 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package config
import (
"encoding/json"
"fmt"
"log"
"os"
"path"

"fyne.io/fyne/v2"
"github.com/elias-gill/walldo-in-go/wallpaper"
Expand All @@ -19,9 +21,9 @@ const (
)

type Configuration struct {
WallpfillMode modes.FillStyle `json:"FillStyle"`
GridSize GridSize `json:"GridSize"`
Paths []string `json:"Paths"`
WallpfillMode modes.FillStyle `json:"FillStyle"`
GridSize GridSize `json:"GridSize"`
WallpaperFolders []string `json:"Paths"`

cachePath string
configPath string
Expand All @@ -31,54 +33,53 @@ type Configuration struct {
window fyne.Window
}

var conf Configuration = initConfig()
var Config Configuration

func initConfig() Configuration {
cache, err := os.UserCacheDir()
func InitConfig(window fyne.Window, fyneSettings fyne.Settings) {
cacheDir, err := os.UserCacheDir()
if err != nil {
panic("Cannot locate cache directory")
log.Fatal("Cannot locate cache directory")
}

home, err := os.UserConfigDir()
configDir, err := os.UserConfigDir()
if err != nil {
panic("Cannot locate user config directory")
log.Fatal("Cannot locate user config directory")
}

aux := Configuration{
configPath: home + "/walldo/",
cachePath: cache + "/walldo/",
configFile: home + "/walldo/" + "config.json",
conf := Configuration{
configPath: path.Join(configDir, "walldo"),
cachePath: path.Join(cacheDir, "walldo"),
configFile: path.Join(configDir, "walldo", "config.json"),
}

err = os.MkdirAll(aux.configPath, 0o770)
err = os.MkdirAll(conf.configPath, 0o770)
if err != nil {
panic("Cannot create config directory " + err.Error())
log.Fatal("Cannot create config directory " + err.Error())
}

err = os.MkdirAll(aux.cachePath, 0o770)
err = os.MkdirAll(conf.cachePath, 0o770)
if err != nil {
panic("Cannot create cache directory " + err.Error())
log.Fatal("Cannot create cache directory " + err.Error())
}

/*
Merge users configuration. NOTE: as the default values for fill mode and
grid size are integers, they have a default value of 0
*/
// Open the file if it exists, or create it if it does not exist
file, err := os.OpenFile(aux.configFile, os.O_RDWR|os.O_CREATE, 0755)
file, err := os.OpenFile(conf.configFile, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(fmt.Sprintf("Cannot open or create config file: %v", err))
log.Fatalf("Cannot open or create config file: %v", err)
}
defer file.Close()

json.NewDecoder(file).Decode(&aux)
// Merge users config to default
json.NewDecoder(file).Decode(&conf)

return aux
// Update global config
Config = conf
Config.fyneSettings = fyneSettings
}

func WriteConfig() {
func PersistConfig() {
// Open the file (create if it doesn't exist, truncate if it does)
file, err := os.Create(conf.configFile)
file, err := os.Create(Config.configFile)
if err != nil {
fmt.Printf("could not create the configuration file: %s", err.Error())
return
Expand All @@ -90,48 +91,60 @@ func WriteConfig() {
encoder.SetIndent("", " ") // Pretty-print with indentation

// Encode the struct to JSON and write it to the file
if err := encoder.Encode(conf); err != nil {
if err := encoder.Encode(Config); err != nil {
fmt.Printf("Could not encode JSON data: %s", err.Error())
}
}

func SetGridSize(s GridSize) {
conf.GridSize = s
Config.GridSize = s
}

func GetGridSize() GridSize {
return conf.GridSize
return Config.GridSize
}

func GetPaths() []string {
return conf.Paths
func GetWallpaperSearchPaths() []string {
return Config.WallpaperFolders
}

func SetPaths(s []string) {
conf.Paths = s
Config.WallpaperFolders = s
}

func SetWallpFillMode(m modes.FillStyle) {
conf.WallpfillMode = m
Config.WallpfillMode = m
wallpaper.SetMode(m)
}

func GetWallpFillMode() modes.FillStyle {
return conf.WallpfillMode
return Config.WallpfillMode
}

func GetFyneSettings() fyne.Settings {
return conf.fyneSettings
return Config.fyneSettings
}

func SetFyneSettings(s fyne.Settings) {
conf.fyneSettings = s
Config.fyneSettings = s
}

func SetWindow(w fyne.Window) {
conf.window = w
Config.window = w
}

func GetWindow() fyne.Window {
return conf.window
return Config.window
}

func GetCachePath() string {
return Config.cachePath
}

func GetConfigPath() string {
return Config.configPath
}

func GetConfigFile() string {
return Config.configFile
}
3 changes: 2 additions & 1 deletion gui/fuzzy_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"fyne.io/fyne/v2/widget"
"github.com/elias-gill/walldo-in-go/config"
"github.com/elias-gill/walldo-in-go/fuzzyEngine/matching"
"github.com/elias-gill/walldo-in-go/utils"
"github.com/elias-gill/walldo-in-go/wallpaper"
)

Expand Down Expand Up @@ -40,7 +41,7 @@ func NewFuzzyDialog() {
func(entry string) {
var imagesList []string

for _, v := range config.ListImages() {
for _, v := range utils.ListImages() {
imagesList = append(imagesList, v.Path)
}

Expand Down
131 changes: 68 additions & 63 deletions gui/grid.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package gui
import (
"log"
"runtime"
"strings"
"sync"

"fyne.io/fyne/v2"
Expand All @@ -12,75 +11,75 @@ import (
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
"github.com/elias-gill/walldo-in-go/config"
"github.com/elias-gill/walldo-in-go/utils"
"github.com/elias-gill/walldo-in-go/wallpaper"
)

type card struct {
image config.Image
type wallpaperCard struct {
image utils.Image
container *fyne.Container
button *widget.Button
}

type wallpapersGrid struct {
container *fyne.Container
grid *fyne.Container
images []card
// Store a reference to the button for when refreshing the grid
applyButton *widget.Button
}

func NewImageGrid() *wallpapersGrid {
grid := container.NewWithoutLayout()
type wallpaperGallery struct {
// Holds the main container that wraps the entire scrollable gallery UI
rootContainer *fyne.Container

return &wallpapersGrid{
grid: grid,
container: container.New(
layout.NewPaddedLayout(),
container.NewScroll(grid)),
}
}
// Arranges image cards in a fluid grid layout. Separated from rootContainer to
// enable asynchronously image loading and refreshing.
gridLayout *fyne.Container

func (w wallpapersGrid) GetContent() *fyne.Container {
return w.container
cards []wallpaperCard
}

func (c *wallpapersGrid) RefreshImgGrid() {
c.grid.RemoveAll()
c.images = []card{}

images := config.ListImages()

for _, img := range images {
card := newEmptyFrame(img)

c.images = append(c.images, card)

c.grid.Add(card.container)
func NewGallery() *wallpaperGallery {
grid := container.NewWithoutLayout()
rootContainer := container.New(
layout.NewPaddedLayout(),
container.NewScroll(grid))

c.grid.Layout = layout.NewGridWrapLayout(
fyne.NewSize(gridScale()),
)
c.grid.Refresh()
return &wallpaperGallery{
gridLayout: grid,
rootContainer: rootContainer,
}

go c.fillContainers()
}

// NOTE: keep this as a separate function
// Creates a new empty card.
func newEmptyFrame(image config.Image) card {
button := widget.NewButton("", func() {
err := wallpaper.SetWallpaper(strings.Clone(image.Path))
if err != nil {
log.Println(err.Error())
// Repopulates the wallpaper gallery by clearing existing items,
// creating placeholders, and asynchronously loading images.
func (w *wallpaperGallery) RefreshGallery() {
w.gridLayout.RemoveAll()
w.cards = []wallpaperCard{}

// Generate placeholder cards for images before they are rendered
for _, img := range utils.ListImages() {
imgCopy := img.Path
button := widget.NewButton("", func() {
err := wallpaper.SetWallpaper(imgCopy)
if err != nil {
log.Println(err.Error())
}
})
cont := container.NewStack(button)

// Construct an empty image card
card := wallpaperCard{
image: img,
container: cont,
applyButton: button,
}
})
w.cards = append(w.cards, card)

cont := container.NewStack(button)

return card{
image: image,
container: cont,
button: button,
w.gridLayout.Add(card.container)
w.gridLayout.Layout = layout.NewGridWrapLayout(fyne.NewSize(gridScale()))
}

// Refresh the UI to reflect the updated grid layout
w.gridLayout.Refresh()

// Start filling the placeholders with images asynchronously
go w.fillContainers()
}

/*
Expand All @@ -89,18 +88,18 @@ Generates the thumbnail for the card and refresh the container.
Creates as many threads as ceil(cpus/2), so the app runs faster but the
cpu does not get overwhelmed.
*/
func (c wallpapersGrid) fillContainers() {
hilos := int(runtime.NumCPU()/2)
if hilos <= 0 {
hilos = 1
}
func (c wallpaperGallery) fillContainers() {
threads := int(runtime.NumCPU() / 2)
if threads <= 0 {
threads = 1
}

log.Println("\n Usando ", hilos, " Hilos")
log.Println("\n Usando ", threads, " Hilos")

wg := sync.WaitGroup{}

for k := range c.images {
card := c.images[k]
for k := range c.cards {
card := c.cards[k]

wg.Add(1)

Expand All @@ -112,20 +111,26 @@ func (c wallpapersGrid) fillContainers() {
image.FillMode = canvas.ImageFillContain

// With the max layout we can overlap the button and the thumbnail
card.container.Add(card.button)
card.container.Add(card.applyButton)
card.container.Add(image)
card.container.Refresh()

wg.Done()
}(&wg)

// generate only as many thumbnails as number of cpus-2
if k%(hilos) == 0 {
if k%(threads) == 0 {
wg.Wait()
}
}
}

// Returns the scrollable container that holds the wallpaperGallery
func (w wallpaperGallery) View() *fyne.Container {
return w.rootContainer
}

// Transform GridSize enums from config to actual pixel size values
// TODO: refactor this and the hole config model
func gridScale() (float32, float32) {
switch config.GetGridSize() {
case config.LARGE:
Expand Down
2 changes: 1 addition & 1 deletion gui/path_picker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/elias-gill/walldo-in-go/config"
)

// generates and show a new path picker from the file system.
// Generates and show a new path picker from the file system.
func NewPathPicker(win fyne.Window, callback func(string)) {
picker := dialog.NewFolderOpen(func(uri fyne.ListableURI, err error) {
if err != nil {
Expand Down
Loading

0 comments on commit 355f065

Please sign in to comment.