sounds, better files

This commit is contained in:
2024-08-18 19:11:41 +00:00
parent 9ed2f70701
commit 08489ed67b
86 changed files with 4226 additions and 86 deletions

View File

@@ -0,0 +1,192 @@
<template>
<div
class="remote-screen"
:class="{ 'remote-screen--dragover': isDragOver }"
:style="{ aspectRatio: `${imageSink?.resolution?.width ?? 1}/${imageSink?.resolution?.height ?? 1}` }"
@drop="onDrop"
@dragover.prevent
@dragleave="isDragOver = false"
@dragenter="isDragOver = true"
@wheel.prevent="onWheel"
@mousedown="onMouseDown"
>
<div class="remote-screen__info">
{{ screen.name }} ({{ imageSink?.resolution?.width ?? '?' }}x{{ imageSink?.resolution?.height ?? '?' }})
<span style="position:absolute;right:0.25rem;"></span>
</div>
<div class="remote-screen__loading" v-if="isLoading"><span></span></div>
<div class="remote-screen__connect" v-if="!screen.isConnected">
<button @click="screen.connect()">Connect</button>
</div>
<canvas
ref="canvas"
style="max-width: 100%;"
:style="{
// transform: `scale(${scale / 100}) translate(${(x)}%, ${(y)}%)`,
}"
/>
</div>
</template>
<script setup lang="ts">
import {computed, inject, ref, watch} from 'vue';
import {ImageSink, RemoteDevice} from '../../model/Remote/types';
import {MountedFsSymbol} from '../../model/injectionSymbols';
import {VirtualFile} from '../../model/FileSystem/types';
import {useLoading} from '../../helpers/withLoading';
import {useMouseDragging} from '../../helpers/mouseDragging';
const props = defineProps<{
screen: RemoteDevice;
}>();
const imageSink = computed(() => props.screen.imageSink as ImageSink);
const fileSystem = inject(MountedFsSymbol)!;
const canvas = ref<HTMLCanvasElement>();
const isDragOver = ref(false);
const scale = ref(100);
const {isLoading, withLoading} = useLoading();
const {onMouseDown, x, y} = useMouseDragging()
function onWheel(event: WheelEvent) {
scale.value = Math.max(10, Math.min(1000, scale.value + event.deltaY / 100));
console.log('scroll', event.deltaY, scale.value);
}
watch(() => [x.value, y.value, scale.value], () => {
imageSink.value?.transform?.({
x: x.value,
y: y.value,
scale: scale.value / 100,
});
})
async function drawImage(blob: Blob) {
if (blob.type.startsWith('image/')) {
const url = URL.createObjectURL(blob);
const img = new Image();
img.onload = () => {
const ctx = canvas.value!.getContext('2d')!;
canvas.value!.width = img.width;
canvas.value!.height = img.height;
ctx.drawImage(img, 0, 0);
}
img.src = url;
} else if (blob.type.startsWith('video/')) {
const url = URL.createObjectURL(blob);
const video = document.createElement('video');
video.muted = true;
video.autoplay = true;
video.src = url;
video.oncanplaythrough = () => {
const ctx = canvas.value!.getContext('2d')!;
canvas.value!.width = video.videoWidth;
canvas.value!.height = video.videoHeight;
ctx.drawImage(video, 0, 0);
video.pause();
}
}
}
async function loadFile(meta: VirtualFile, file: Blob) {
await withLoading(async () => {
await Promise.all([
imageSink.value?.transferFile(meta, file),
drawImage(file),
])
await imageSink.value?.show(meta);
})
}
async function onDrop(event: DragEvent) {
event.preventDefault();
isDragOver.value = false;
const file = event.dataTransfer?.files?.[0];
if (file) {
const meta = {
type: 'file',
source: 'drop',
path: [] as string[],
name: file.name,
mimeType: file.type
} as const;
await loadFile(meta, file)
} else if (event.dataTransfer?.getData('application/json')) {
const meta = JSON.parse(event.dataTransfer?.getData('application/json'));
if (meta.type === 'file') {
const file = await fileSystem.download(meta);
await loadFile(meta, file);
}
}
console.log('files', event.dataTransfer?.files);
console.log('drop', event.dataTransfer?.getData('application/json'));
}
</script>
<style>
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.remote-screen {
position: relative;
display: inline-block;
border: 2px solid white;
border-radius: 4px;
background-color: black;
aspect-ratio: 16 / 9;
overflow: hidden;
max-height: 100%;
}
.remote-screen__info {
position: absolute;
top: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
padding: 4px;
text-align: center;
}
.remote-screen__loading {
pointer-events: none;
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
color: white;
background-color: rgba(0, 0, 0, 0.5);
span {
transform-origin: 44% 54%;
animation: spin 1000ms linear infinite;
}
}
.remote-screen__connect {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
padding: 4px;
text-align: center;
}
.remote-screen--dragover {
border-color: orange;
}
</style>