This commit is contained in:
Trit0 2025-06-30 20:43:07 -04:00
parent 49ddcfe130
commit 0b0e6af52a
16 changed files with 244 additions and 31 deletions

4
app.go
View File

@ -63,3 +63,7 @@ func (a *App) LoadGames() []models.Game {
games = provider.GetConjureGameInfo()
return games
}
func (a *App) LoadImage(gameId string, imageSrc string) provider.FileBlob {
return *provider.LoadImage(gameId, imageSrc)
}

View File

@ -0,0 +1,31 @@
<template>
<div
:key="game.Id"
:class="[
'transition-transform transform cursor-pointer rounded-lg overflow-hidden border-4',
selected ? 'scale-110 border-blue-500' : 'scale-100 border-transparent'
]"
>
<LocalImage
:src="game.ThumbnailPath"
class="h-32 w-48 object-cover"
:alt="game.Game"
:key="game.Id"
/>
</div>
</template>
<style scoped>
</style>
<script setup lang="ts">
import { models } from "../../wailsjs/go/models";
import Game = models.Game;
import LocalImage from "./LocalImage.vue";
defineProps<{
game: Game
selected: boolean
}>()
</script>

View File

@ -2,21 +2,12 @@
<div class="relative h-[170px]">
<Transition :name="`carousel-${direction}`" mode="out-in">
<div :key="selectedTag" class="w-full py-4 px-6 flex overflow-x-auto space-x-4 items-end transition-inner">
<div
<GameCard
v-for="game in games"
:key="game.Id"
:game="game"
:selected="game.Id === selectedGame?.Id"
@click="$emit('selectGame', game)"
:class="[
'transition-transform transform cursor-pointer rounded-lg overflow-hidden border-4',
game.Id === selectedGame.Id ? 'scale-110 border-blue-500' : 'scale-100 border-transparent'
]"
>
<img
:src="game.ThumbnailPath"
class="h-32 w-48 object-cover"
:alt="game.Game"
/>
</div>
/>
</div>
<!-- Give the whole carousel a key based on selectedTag to trigger transition -->
<!-- <div :key="selectedTag" class="flex gap-4 w-full transition-inner">-->
@ -36,6 +27,7 @@
import { models } from "../../wailsjs/go/models";
import Game = models.Game;
import GameCard from "./GameCard.vue";
defineProps<{
games: Game[],

View File

@ -0,0 +1,29 @@
<template>
<img
:src="blobUrl"
:alt="alt"
>
</template>
<style scoped>
</style>
<script setup lang="ts">
import { ref, watch } from "vue";
import { ImageManager } from "../utils/image-manager";
defineProps<{
key: string
src: string
alt: string
}>()
const blobUrl = ref<string | null>(null);
watch(() => props.imageUrl, async (newUrl) => {
blobUrl.value = await ImageManager.getBlob(key, newUrl);
}, { immediate: true });
console.log(src)
</script>

View File

@ -0,0 +1,21 @@
import {LoadImage} from "../../wailsjs/go/main/App";
import * as path from "node:path";
export class ImageManager {
static Dictionary: {[key: string]: string} = {}
public static async getImage(gameId: string, src: string): Promise<string> {
const id = path.join(gameId, src);
if (this.Dictionary[id])
return this.Dictionary[id]
const fileBlob = await LoadImage(gameId, src);
const bytes = new Uint8Array(fileBlob.Data);
const blob = new Blob([bytes], {type: fileBlob.MimeType });
const url = URL.createObjectURL(blob);
this.Dictionary[id] = url
return url;
}
}

View File

@ -1,7 +1,10 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';
import {provider} from '../models';
export function LoadGames():Promise<Array<models.Game>>;
export function LoadImage(arg1:string,arg2:string):Promise<provider.FileBlob>;
export function StartGame(arg1:string):Promise<void>;

View File

@ -6,6 +6,10 @@ export function LoadGames() {
return window['go']['main']['App']['LoadGames']();
}
export function LoadImage(arg1, arg2) {
return window['go']['main']['App']['LoadImage'](arg1, arg2);
}
export function StartGame(arg1) {
return window['go']['main']['App']['StartGame'](arg1);
}

View File

@ -45,3 +45,24 @@ export namespace models {
}
export namespace provider {
export class FileBlob {
Name: string;
MimeType: string;
Data: number[];
static createFrom(source: any = {}) {
return new FileBlob(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.Name = source["Name"];
this.MimeType = source["MimeType"];
this.Data = source["Data"];
}
}
}

0
frontend/wailsjs/runtime/package.json Normal file → Executable file
View File

0
frontend/wailsjs/runtime/runtime.d.ts vendored Normal file → Executable file
View File

0
frontend/wailsjs/runtime/runtime.js Normal file → Executable file
View File

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.22.0
toolchain go1.23.5
require (
github.com/karalabe/hid v1.0.0
github.com/wailsapp/wails/v2 v2.9.2
gopkg.in/yaml.v3 v3.0.1
)

2
go.sum
View File

@ -11,6 +11,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo=
github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=

View File

@ -1,10 +1,9 @@
package inputs
import (
"encoding/binary"
"fmt"
"os"
"time"
"github.com/karalabe/hid"
)
type JoystickEvent struct {
@ -21,29 +20,84 @@ const (
)
func Start() {
// Open the joystick device file
file, err := os.Open("/dev/input/js0")
if err != nil {
fmt.Println("Error opening joystick:", err)
return
fmt.Println("Opening devices")
const vendorID = 0x0079
const productID = 0x0006
// Enumerate all matching devices
devices := hid.Enumerate(vendorID, productID)
if len(devices) == 0 {
fmt.Printf("Device with VID:PID %04X:%04X not found", vendorID, productID)
return
}
defer file.Close()
// Continuously read joystick events
for _, d := range devices {
fmt.Printf("Found: %s - VID:%04X PID:%04X\n", d.Product, d.VendorID, d.ProductID)
}
// Open the first matching device
device, err := devices[0].Open()
if err != nil {
fmt.Printf("Failed to open device: %v", err)
return
}
defer device.Close()
fmt.Println("Reading data... Press Ctrl+C to exit")
buf := make([]byte, 32) // Adjust size if needed
for {
var e JoystickEvent
err := binary.Read(file, binary.LittleEndian, &e)
_, err := device.Read(buf)
if err != nil {
fmt.Println("Error reading joystick event:", err)
fmt.Printf("Read error: %v", err)
return
}
// Handle the event
handleJoystickEvent(e)
// For debugging: print raw data
// fmt.Printf("Raw: % X\n", buf[:n])
// Sleep to avoid flooding output
time.Sleep(10 * time.Millisecond)
// Example: decode joystick + button state
x := buf[0] // Horizontal axis (0255)
y := buf[1] // Vertical axis (0255)
buttons := buf[6] // Buttons as bitfield
// fmt.Printf("Joystick X: %d, Y: %d, Buttons: %08b\n", x, y, buttons)
if buttons != 0 {
fmt.Printf("Button was pressed! %d\n", buttons)
}
if x != 127 || y != 127 {
fmt.Printf("Joystick moved! %d - %d\n", x, y)
}
}
fmt.Println("Out")
// Open the joystick device file
// file, err := os.Open("/dev/input/js0")
// if err != nil {
// fmt.Println("Error opening joystick:", err)
// return
// }
// defer file.Close()
// // Continuously read joystick events
// for {
// var e JoystickEvent
// err := binary.Read(file, binary.LittleEndian, &e)
// if err != nil {
// fmt.Println("Error reading joystick event:", err)
// return
// }
// // Handle the event
// handleJoystickEvent(e)
// // Sleep to avoid flooding output
// time.Sleep(10 * time.Millisecond)
// }
}
// handleJoystickEvent processes joystick events.

View File

@ -0,0 +1,53 @@
package provider
import (
"conjure-os/lib/config"
"mime"
"net/http"
"os"
"path/filepath"
)
func LoadImage(gameId string, imageSrc string) *FileBlob {
imagePath := filepath.Join(config.GetDefaultConjureGamesDirectory(), gameId, imageSrc)
blob, err := GetFileBlob(imagePath)
if err != nil {
panic(err)
}
return blob
}
type FileBlob struct {
Name string
MimeType string
Data []byte
}
func GetFileBlob(path string) (*FileBlob, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
// Try to guess MIME type from content
mimeType := http.DetectContentType(data)
// Fallback to extension-based detection
if mimeType == "application/octet-stream" {
ext := filepath.Ext(path)
if ext != "" {
if t := mime.TypeByExtension(ext); t != "" {
mimeType = t
}
}
}
name := filepath.Base(path)
return &FileBlob{
Name: name,
MimeType: mimeType,
Data: data,
}, nil
}

View File

@ -206,8 +206,6 @@ func GetConjureGameInfo() []models.Game {
metadata, err := io.ReadAll(rc)
game := parseGameInfo([]byte(escapeBackslashes(string(metadata))))
fmt.Println(game.ThumbnailPath)
game.ThumbnailPath = filepath.Join(conjBase, game.ThumbnailPath)
game.ImagePath = filepath.Join(conjBase, game.ImagePath)
games = append(games, game)
check(err)
}