all repos — emessage @ 312f91c8b7e25ecd3446038beca95872642f3d45

The EMessage email client

images.go (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
package main

import (
	"encoding/base64"
	"errors"
	"fmt"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/wailsapp/wails/v2/pkg/runtime"
	"gorm.io/gorm"
)

type DisplayImage struct {
	gorm.Model
	MIMEType string
	Content  []byte
}

type ImageResponse struct {
	DataURI string
	Base64  string
}

func (app *App) PickContactImage(contact Contact) (*ImageResponse, error) {
	filePath, err := runtime.OpenFileDialog(app.ctx, runtime.OpenDialogOptions{
		Title: "Select Contact Photo",
		Filters: []runtime.FileFilter{
			{
				DisplayName: "Images (*.png;*.jpg;*.jpeg;*.gif)",
				Pattern:     "*.png;*.jpg;*.jpeg;*.gif",
			},
		},
	})
	if err != nil {
		return nil, fmt.Errorf("file dialog failed: %w", err)
	}
	if filePath == "" {
		return nil, nil
	}

	data, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to read file: %w", err)
	}

	ext := strings.ToLower(filepath.Ext(filePath))
	mimeType := mime.TypeByExtension(ext)
	if mimeType == "" {
		mimeType = "image/png"
	}

	base64Str := base64.StdEncoding.EncodeToString(data)
	dataURI := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Str)

	return &ImageResponse{DataURI: dataURI, Base64: base64Str}, nil
}

func (app *App) GetContactImage(contact Contact) (*ImageResponse, error) {
	if contact.ID == 0 {
		return nil, nil
	}

	var img DisplayImage
	if err := app.DB.Where("id = ?", contact.DisplayImageID).First(&img).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, err
	}

	if len(img.Content) == 0 {
		return nil, nil
	}

	encoded := base64.StdEncoding.EncodeToString(img.Content)
	dataURI := fmt.Sprintf("data:%s;base64,%s", img.MIMEType, encoded)

	return &ImageResponse{
		DataURI: dataURI,
		Base64:  encoded,
	}, nil
}

func (app *App) SaveContactImage(contactID uint, base64Str string) error {
	if base64Str == "" {
		return nil
	}

	data, err := base64.StdEncoding.DecodeString(base64Str)
	if err != nil {
		return fmt.Errorf("invalid base64 image data: %w", err)
	}

	mimeType := http.DetectContentType(data)

	var contact Contact
	if err := app.DB.First(&contact, contactID).Error; err != nil {
		return fmt.Errorf("contact %d not found: %w", contactID, err)
	}

	img := DisplayImage{
		MIMEType: mimeType,
		Content:  data,
	}
	if contact.DisplayImageID != 0 {
		img.Model = gorm.Model{ID: contact.DisplayImageID}
	}

	if err := app.DB.Session(&gorm.Session{FullSaveAssociations: true}).
		Save(&img).Error; err != nil {
		return fmt.Errorf("failed to save image: %w", err)
	}

	contact.DisplayImageID = img.ID
	if err := app.DB.Save(&contact).Error; err != nil {
		return fmt.Errorf("failed to link image to contact: %w", err)
	}

	return nil
}