+
+
+
+
+
-
{style} is here
-
-
+
-
-
+
+
+ {#each commonColors as c}
+
handleSelectColor(c)}
+ on:keydown={() => handleSelectColor(c)}
+ class="mt-5 cursor-default border-2 transition-all hover:opacity-70 rounded-full pt-9 text-center w-[100px] h-[100px] ml-5"
+ >
+ {/each}
+
+
+
+
+
+
+
+ {#each colors as color}
+
(colors = colors.filter((c) => c !== color))}
+ on:keydown={() => (colors = colors.filter((c) => c !== color))}
+ style="background-color: {color}"
+ class="mt-5 cursor-default border-2 transition-all hover:opacity-70 rounded-full pt-9 text-center w-[100px] h-[100px] ml-5"
+ >
+ {/each}
+
+
+
+
+
+
+
diff --git a/frontend/src/pages/Setting.svelte b/frontend/src/pages/Setting.svelte
index a141b7e..80310de 100644
--- a/frontend/src/pages/Setting.svelte
+++ b/frontend/src/pages/Setting.svelte
@@ -79,6 +79,15 @@
message = error;
}
};
+
+ function setImageCategory(query: string) {
+ imageCategory = query;
+ }
+
+ function handleRemoveWhiteSpace(event) {
+ const value = event.target.value;
+ event.target.value = value.replace(/\s/g, '');
+ }
@@ -86,16 +95,18 @@
Configuration
Selected directory path
+ {defaultPath}
+
+
+ Suggestions:
+ setImageCategory('nature')}
+ on:keydown={() => setImageCategory('nature')}
+ >
+ nature,
+ setImageCategory('landscape')}
+ on:keydown={() => setImageCategory('landscape')}>landscape,
+ setImageCategory('lamborghini')}
+ on:keydown={() => setImageCategory('lamborghini')}
+ >lamborghini,
+ setImageCategory('tokyo')}
+ on:keydown={() => setImageCategory('tokyo')}
+ >
+ tokyo,
+ setImageCategory('africa')}
+ on:keydown={() => setImageCategory('africa')}>africa
+
-
+ /> -->
+
+
@@ -212,4 +270,10 @@
.selection label {
display: block;
}
+
+ select,
+ input {
+ appearance: none;
+ -webkit-appearance: none;
+ }
diff --git a/frontend/src/store/app.ts b/frontend/src/store/app.ts
index 46facf4..6534c1c 100644
--- a/frontend/src/store/app.ts
+++ b/frontend/src/store/app.ts
@@ -1,3 +1,6 @@
import { writable } from 'svelte/store';
export const imagePathStore = writable('');
+
+
+
diff --git a/frontend/src/utilities/util.ts b/frontend/src/utilities/util.ts
new file mode 100644
index 0000000..685cca9
--- /dev/null
+++ b/frontend/src/utilities/util.ts
@@ -0,0 +1,6 @@
+import { imagePathStore } from "../store/app";
+
+export const dispatcher = (value: string) => {
+ imagePathStore.set(value);
+}
+
diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts
index f27dc47..588cc3a 100755
--- a/frontend/wailsjs/go/models.ts
+++ b/frontend/wailsjs/go/models.ts
@@ -1,3 +1,20 @@
+export namespace api {
+
+ export class RGBA {
+
+
+ static createFrom(source: any = {}) {
+ return new RGBA(source);
+ }
+
+ constructor(source: any = {}) {
+ if ('string' === typeof source) source = JSON.parse(source);
+
+ }
+ }
+
+}
+
export namespace main {
export class Conf {
diff --git a/internal/api/unsplash.go b/internal/api/unsplash.go
index 33522c8..677a0fb 100644
--- a/internal/api/unsplash.go
+++ b/internal/api/unsplash.go
@@ -1,6 +1,7 @@
package api
import (
+ "context"
"encoding/json"
"fmt"
"io"
@@ -10,8 +11,7 @@ import (
"strconv"
"strings"
"sync"
-
- log "github.com/sirupsen/logrus"
+ "time"
)
type UnleaseService struct {
@@ -41,6 +41,15 @@ type ImageConfig struct {
Path string
}
+type RGBA struct {
+ R int
+ G int
+ B int
+ A int
+}
+
+const timeout = 60 * time.Second
+
func NewUnsplashService(apikey string, path string) *UnleaseService {
return &UnleaseService{
apikey: apikey,
@@ -54,6 +63,8 @@ func (u *UnleaseService) GetImages(imgConf ImageConfig) error {
imgCount := imgConf.TotalDownloadImage
maxImage := strconv.Itoa(imgCount)
accessKey := u.apikey
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
var imagePath string = u.path
@@ -61,35 +72,62 @@ func (u *UnleaseService) GetImages(imgConf ImageConfig) error {
fmt.Println("Download...")
fmt.Println(url)
- result, err := getImage(url)
+ result, err := getImage(ctx, url)
if err != nil {
return err
}
var wg sync.WaitGroup
+
+ errCh := make(chan error, len(result))
+
for key, v := range result {
wg.Add(1)
struri := v.User.Links.Html
parsedURL, err := neturl.Parse(struri)
if err != nil {
- fmt.Println("Error parsing URL:", err)
+ return fmt.Errorf("Error parsing URL: %v", err)
}
path := parsedURL.Path
parts := strings.Split(path, "/")
username := parts[len(parts)-1]
- go download(v.Urls.Full, key, &wg, imagePath, username)
+ go (func() {
+ defer wg.Done()
+ if err := download(ctx, v.Urls.Full, key, imagePath, username); err != nil {
+ errCh <- err
+ }
+ })()
}
wg.Wait()
- return nil
+ close(errCh)
+
+ select {
+ case err := <-errCh:
+ return err
+ default:
+ return nil
+ }
}
-func getImage(url string) ([]Image, error) {
- resp, err := http.Get(url)
+func getImage(ctx context.Context, url string) ([]Image, error) {
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
+
+ client := http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("[GetImage]: request failed: %w", err)
+ }
+ defer resp.Body.Close()
+ // Check if the response status is OK
+ if resp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
+ }
+
var p []Image
if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
return nil, err
@@ -97,27 +135,43 @@ func getImage(url string) ([]Image, error) {
return p, nil
}
-func download(image string, index int, wg *sync.WaitGroup, IMAGE_DIR string, upr string) {
- defer wg.Done()
- resp, err := http.Get(image)
+func download(ctx context.Context, image string, index int, IMAGE_DIR string, upr string) error {
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, image, nil)
if err != nil {
- log.Fatal(err)
+ return err
+ }
+
+ client := http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return fmt.Errorf("[Download]: request failed: %v", err)
}
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
+ }
+
fn := fmt.Sprintf("%s/picasa_%v_%s.jpg", IMAGE_DIR, index, upr)
info := fmt.Sprintf("Downloading: %s", fn)
fmt.Println(info)
- defer resp.Body.Close()
f, err := os.Create(fn)
// fmt.Sprintf("%s/%v.jpg", IMAGE_DIR, index))
if err != nil {
- log.Fatal(err)
+ return err
}
+
defer f.Close()
_, err = io.Copy(f, resp.Body)
+
if err != nil {
- log.Fatal(err)
+ return err
}
+
fmt.Println("Downloaded to: ", f.Name())
+
+ return nil
}
diff --git a/internal/service.go b/internal/service.go
index 35ab6f6..c0997ce 100644
--- a/internal/service.go
+++ b/internal/service.go
@@ -3,17 +3,15 @@ package internal
import (
"desktop/internal/api"
"fmt"
+ "github.com/fogleman/gg"
"image/color"
"image/png"
- "log"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"strings"
-
- "github.com/fogleman/gg"
)
func GetImagesFromDir() []string {
@@ -40,14 +38,15 @@ func GetImagesFromDir() []string {
}
-func FetchImages(conf api.ImageConfig) {
+func FetchImages(conf api.ImageConfig) error {
apikey := conf.Apikey
sp := conf.Path
svc := api.NewImageDownload("unsplash", sp, apikey)
err := svc.GetImages(conf)
if err != nil {
- log.Fatal(err.Error())
+ return err
}
+ return nil
}
func WallpaperEvent(path string) {
@@ -68,7 +67,7 @@ func GetAllFilesInDir(dir string) ([]string, error) {
return err
}
- if !info.IsDir() && isImageFile(path) {
+ if !info.IsDir() && isImageFile(path) && info.Size() > 0 {
if isImageFile(info.Name()) {
images = append(images, path)
}
@@ -92,11 +91,15 @@ func isImageFile(file string) bool {
return false
}
-func GenerateGradientImage() error {
+func GenerateGradientImage(c1 api.RGBA, c2 api.RGBA) error {
+
w, h := 1900, 1200
dc := gg.NewContext(w, h)
- stc := color.RGBA{255, 0, 0, 255}
- endc := color.RGBA{0, 0, 255, 255}
+ // stc := color.RGBA{255, 0, 0, 255}
+ // endc := color.RGBA{0, 0, 255, 255}
+
+ stc := color.RGBA{uint8(c1.R), uint8(c1.G), uint8(c1.B), uint8(c1.A)}
+ endc := color.RGBA{uint8(c2.R), uint8(c2.G), uint8(c2.B), uint8(c2.A)}
for y := 0; y < h; y++ {
t := float64(y) / float64(h)
@@ -104,7 +107,7 @@ func GenerateGradientImage() error {
g := uint8((1-t)*float64(stc.G) + t*float64(endc.G))
b := uint8((1-t)*float64(stc.B) + t*float64(endc.B))
// a := uint8((1-t)*float64(stc.A) + t*float64(endc.A))
-
+ //
dc.SetRGB(float64(r)/255, float64(g)/255, float64(b)/255)
dc.DrawLine(0, float64(y), float64(w), float64(y))
dc.Stroke()
@@ -119,23 +122,64 @@ func GenerateGradientImage() error {
return png.Encode(f, dc.Image())
}
-func HexToRGB(hex string) (int, int, int, error) {
- // Remove the '#' if present
- hex = strings.TrimPrefix(hex, "#")
-
- // Parse hex values
- r, err := strconv.ParseInt(hex[0:2], 16, 32)
- if err != nil {
- return 0, 0, 0, err
+func HexToRGBA(hex string) (api.RGBA, error) {
+ if len(hex) > 0 && hex[0] == '#' {
+ hex = hex[1:]
}
- g, err := strconv.ParseInt(hex[2:4], 16, 32)
- if err != nil {
- return 0, 0, 0, err
+
+ var r, g, b, a int
+
+ switch len(hex) {
+ case 6: // #RRGGBB
+ r64, err := strconv.ParseInt(hex[0:2], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+ g64, err := strconv.ParseInt(hex[2:4], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+ b64, err := strconv.ParseInt(hex[4:6], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+
+ r, g, b, a = int(r64), int(g64), int(b64), 255 // Default alpha to 255
+
+ fmt.Println(r, g, b, a)
+ case 8: // #RRGGBBAA
+ r64, err := strconv.ParseInt(hex[0:2], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+ g64, err := strconv.ParseInt(hex[2:4], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+ b64, err := strconv.ParseInt(hex[4:6], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+ a64, err := strconv.ParseInt(hex[6:8], 16, 8)
+ if err != nil {
+ return api.RGBA{}, err
+ }
+
+ r, g, b, a = int(r64), int(g64), int(b64), int(a64)
+ fmt.Println(r, g, b, a)
+
+ default:
+ return api.RGBA{}, fmt.Errorf("invalid hex color format")
}
- b, err := strconv.ParseInt(hex[4:6], 16, 32)
- if err != nil {
- return 0, 0, 0, err
+
+ fmt.Println(r, g, b, a)
+
+ res := api.RGBA{
+ R: r,
+ G: g,
+ B: b,
+ A: a,
}
- return int(r), int(g), int(b), nil
+ return res, nil
}