Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*

gogallery
gogallery

__debug*
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"mode": "auto",
"cwd": "${workspaceFolder}",
"program": "main.go",
// "args": ["serve"]
// "args": [""]
}
]
}
5 changes: 3 additions & 2 deletions pkg/ai/capition.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ const basePrompt = `
You are a helpful assistant.
You will be given an image and I need a title and a caption for it.
Please provide a short title and a detailed caption for the image.
The Captions should be descriptive and engaging, providing context and details about the image.
Make sure to include any relevant information that would help someone understand the image better.
The caption should include any relevant information that would help someone understand the image better.
But also and some creative flair to make it engaging for social media posts.
Specifically, the caption should be suitable for Instagram. But not include hashtags.
`

type AIClient interface {
Expand Down
4 changes: 3 additions & 1 deletion pkg/datastore/Exif.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ func (u *Picture) CreateExif() error {
u.FocalLength = tags["FocalLength"]
}

u.Name = tags["DocumentName"]
if tags["DocumentName"] != "" {
u.Name = tags["DocumentName"]
}
u.Caption = tags["ImageDescription"]

u.ISO = tags["ISOSpeedRatings"]
Expand Down
25 changes: 25 additions & 0 deletions pkg/datastore/album.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,28 @@ func RemoveAlbumFromSlice(albums []Album, target Album) []Album {
}
return albums
}

func (c *AlbumCollection) RemoveInvalidAlbums() error {
c.Lock()
defer c.Unlock()

// Get all albums
albums, err := c.GetAll()
if err != nil {
fmt.Println("Error fetching albums:", err)
return err
}

for _, album := range albums {
// Check if the album directory exists
if _, err := os.Stat(album.Path); os.IsNotExist(err) {
// If it doesn't exist, delete the album from the database
if err := c.DB.Delete(&Album{}, "id = ?", album.Id).Error; err != nil {
fmt.Println("Error deleting album:", err)
} else {
fmt.Printf("Deleted album: %s\n", album.Path)
}
}
}
return nil
}
9 changes: 9 additions & 0 deletions pkg/datastore/file_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func createAlbum(fInfo os.FileInfo, path string) Album {
ModTime: info.ModTime,
Parent: filepath.Base(filepath.Dir(path)),
ParentPath: (filepath.Dir(path)),
Path: path,
}
}

Expand Down Expand Up @@ -97,6 +98,7 @@ func (db *DataStore) ScanPath(path string) error {
db.Pictures.BatchInsert(pictures)
db.Albums.BatchInsert(albums)
db.updateAlbumProfiles(albumUpdates)
db.PerformCleanup()

// log.Println("Scanning Complete")
return nil
Expand Down Expand Up @@ -157,3 +159,10 @@ func (db *DataStore) updateAlbumProfiles(albumUpdates []albumUpdate) {
})
}
}

func (db *DataStore) PerformCleanup() {
log.Println("Performing cleanup of old pictures and albums")
db.Pictures.RemoveInvalidPictures()
db.Albums.RemoveInvalidAlbums()
log.Println("Cleanup complete")
}
18 changes: 18 additions & 0 deletions pkg/datastore/pictures.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,21 @@ func (p *Picture) Load() (image.Image, error) {
}
return img, nil
}

func (p *PictureCollection) RemoveInvalidPictures() error {
var invalidPics []Picture
pictures, _ := p.GetAll()
for _, pic := range pictures {
if _, err := os.Stat(pic.Path); os.IsNotExist(err) {
invalidPics = append(invalidPics, pic)
}
}
if len(invalidPics) > 0 {
p.Lock()
defer p.Unlock()
if err := p.DB.Delete(&invalidPics).Error; err != nil {
return fmt.Errorf("failed to remove invalid pictures: %w", err)
}
}
return nil
}
7 changes: 4 additions & 3 deletions pkg/pipeline/IndexPagePipeluine.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ func (r *RenderPipeline) BuildIndex(w io.Writer) {

albums, _ := r.Albums.GetLatestAlbums()
indexPage.Albums = make([]datastore.AlbumNode, 3)
for i, alb := range albums {
if i >= 3 {
//Skip the first album as it is the featured album
for i := 1; i < len(albums); i++ {
if i >= 4 {
break
}
indexPage.Albums[i] = alb.ToAlbumNode()
indexPage.Albums[i-1] = albums[i].ToAlbumNode()
}

if len(images) > 0 {
Expand Down
8 changes: 5 additions & 3 deletions pkg/ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ func App() error {

galleryPage := pages.NewGalleryPage(db)
settingsPage := pages.NewSettingsPage(db)
collectionPage := pages.NewCollectionPage(db)
tasksPage := pages.NewTasksPage(db, server)

pages := map[string]pages.Page{
"Gallery": galleryPage,
"Settings": settingsPage,
"Tasks": tasksPage,
"Gallery": galleryPage,
"Settings": settingsPage,
"Tasks": tasksPage,
"Collections": collectionPage,
}

var navBar *fyne.Container
Expand Down
144 changes: 144 additions & 0 deletions pkg/ui/components/CollectionEdit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package components

import (
"bytes"
"gogallery/pkg/config"
"gogallery/pkg/datastore"
"io"
"log"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)

type CollectionAlbumContainer struct {
*datastore.DataStore
selectedAlbum datastore.Album // Reference to the currently selected album
titleEntry *widget.Entry
image *canvas.Image // Placeholder for the image to be displayed
imageStack *fyne.Container // Direct reference to the image stack
container fyne.CanvasObject // Reference to the sidebar container for refresh
OnUpdate func() // Callback for album update
}

func NewCollectionAlbumContainer(db *datastore.DataStore, selectedAlbum datastore.Album) *CollectionAlbumContainer {
titleEntry := widget.NewEntry()
titleEntry.SetPlaceHolder("Enter album title")

// Use a placeholder image instead of nil to avoid layout issues on Windows
placeholder := canvas.NewRectangle(nil)
placeholder.SetMinSize(fyne.NewSize(600, 400))
img := canvas.NewImageFromImage(nil)
img.FillMode = canvas.ImageFillContain
img.SetMinSize(fyne.NewSize(600, 400)) // More reasonable default
imageStack := container.NewStack(placeholder)

return &CollectionAlbumContainer{
DataStore: db,
selectedAlbum: selectedAlbum,
titleEntry: titleEntry,
image: img,
imageStack: imageStack,
}
}

func (c *CollectionAlbumContainer) loadImage(pic datastore.Picture) {

file, err := c.ImageCache.Get(pic.Id, config.JPEG, "small")
if err != nil {
log.Println("Error loading image from cache:", err)
return
}
data, err := io.ReadAll(file)
if err != nil {
log.Println("Error reading image file:", err)
return
}
log.Printf("[Sidebar] Loaded image bytes: %d for %s", len(data), pic.Name)
if len(data) < 16 {
log.Println("[Sidebar] Image data too small or empty, not displaying.")
return
}

newImg := canvas.NewImageFromReader(bytes.NewReader(data), pic.Name)
newImg.FillMode = canvas.ImageFillContain
width := float32(500)
if pic.AspectRatio > 0 {
height := width / pic.AspectRatio
newImg.SetMinSize(fyne.NewSize(width, height))
newImg.Resize(fyne.NewSize(width, height))
} else {
newImg.SetMinSize(fyne.NewSize(width, 300))
newImg.Resize(fyne.NewSize(width, 300))
}

if c.imageStack != nil {
c.imageStack.Objects = []fyne.CanvasObject{newImg}
c.imageStack.Refresh()
}
c.image = newImg
c.imageStack.Refresh()
}

func (c *CollectionAlbumContainer) Layout() fyne.CanvasObject {

if pic, err := c.DataStore.Pictures.FindById(c.selectedAlbum.ProfileId); err == nil {
c.loadImage(pic)
}
c.titleEntry.SetText(c.selectedAlbum.Name)

var imageOptions []string
imageMap := make(map[string]datastore.Picture)
selectedImage := c.selectedAlbum.ProfileId
if pics, err := c.Pictures.FindByField("album", c.selectedAlbum.Id); err == nil {
imageOptions = make([]string, len(pics))
for i, pic := range pics {
imageOptions[i] = pic.Name
imageMap[pic.Name] = pic
if pic.Id == c.selectedAlbum.ProfileId {
selectedImage = pic.Name // Set the selected image name
}
}
}

imageSelect := widget.NewSelect(imageOptions, func(selected string) {
selectedImage = imageMap[selected].Id
if pic, exists := imageMap[selected]; exists {
c.loadImage(pic)
}
})
imageSelect.Selected = selectedImage

// EXIF info section (populated in ShowImage)
form := widget.NewForm(
widget.NewFormItem("Title", c.titleEntry),
widget.NewFormItem("Feature Image", imageSelect),
)

form.OnSubmit = func() {
c.selectedAlbum.Name = c.titleEntry.Text
c.selectedAlbum.ProfileId = selectedImage
if err := c.DataStore.Albums.Update(c.selectedAlbum.Id, c.selectedAlbum); err != nil {
log.Println("Error updating album name:", err)
return
}
log.Printf("Updated album name to: %s", c.selectedAlbum.Name)
fyne.CurrentApp().SendNotification(&fyne.Notification{
Title: "Album Updated",
Content: "The album details have been saved successfully.",
})
if c.OnUpdate != nil {
c.OnUpdate() // Call the update callback if set
}
}

scrollContent := container.NewVBox(
c.imageStack,
form,
)

c.container = container.NewVScroll(scrollContent)
return c.container
}
Loading
Loading