Skip to content

Commit 8c32a95

Browse files
antfuLittleSoundnekomeowww
authored
feat!: LT code for transmit (#2)
Co-authored-by: Rizumu Ayaka <[email protected]> Co-authored-by: Neko Ayaka <[email protected]>
1 parent 4bfa0be commit 8c32a95

15 files changed

+909
-467
lines changed

app/components/Collapsable.vue

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script lang="ts" setup>
2+
import { watchEffect } from 'vue'
3+
4+
const props = defineProps<{
5+
default?: boolean
6+
label?: string
7+
}>()
8+
const isVisible = defineModel<boolean>({ default: false })
9+
watchEffect(() => {
10+
if (props.default != null) {
11+
isVisible.value = !!props.default
12+
}
13+
})
14+
</script>
15+
16+
<template>
17+
<div flex="~ col" border="~ gray/25 rounded-lg" divide="y dashed gray/25" max-w-150 of-hidden shadow-sm>
18+
<button
19+
flex items-center justify-between px2 py1 text-sm
20+
@click="isVisible = !isVisible"
21+
>
22+
<span>
23+
<slot name="label">
24+
{{ props.label ?? 'Inspect' }}
25+
</slot></span> <span op50>{{ isVisible ? '▲' : '▼' }}</span>
26+
</button>
27+
<div v-if="isVisible">
28+
<slot />
29+
</div>
30+
</div>
31+
</template>

app/components/Generate.vue

+35-32
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,53 @@
11
<script lang="ts" setup>
2-
import { encode, renderSVG } from 'uqr'
2+
import type { EncodedBlock } from '~~/utils/lt-code'
3+
import { blockToBinary, createEncoder } from '~~/utils/lt-code'
4+
import { fromUint8Array } from 'js-base64'
5+
import { renderSVG } from 'uqr'
36
47
const props = withDefaults(defineProps<{
5-
data: string[]
8+
data: Uint8Array
69
speed: number
710
}>(), {
811
speed: 250,
912
})
1013
11-
const ecc = 'L' as const
12-
const minVersion = computed(() => encode(props.data[0]! || '', { ecc }).version)
13-
const svgList = computed(() => props.data.map(content => renderSVG(content, {
14-
border: 1,
15-
ecc,
16-
minVersion: minVersion.value,
17-
})))
18-
const activeIndex = ref(0)
19-
watch(() => props.data, () => activeIndex.value = 0)
14+
const count = ref(0)
15+
const encoder = createEncoder(props.data, 1000)
16+
const svg = ref<string>()
17+
const block = shallowRef<EncodedBlock>()
2018
21-
let intervalId: any
22-
function initInterval() {
23-
intervalId = setInterval(() => {
24-
activeIndex.value = (activeIndex.value + 1) % svgList.value.length
25-
}, props.speed)
26-
}
27-
watch(() => props.speed, () => {
28-
intervalId && clearInterval(intervalId)
29-
initInterval()
30-
}, { immediate: true })
31-
onUnmounted(() => intervalId && clearInterval(intervalId))
19+
const renderTime = ref(0)
20+
const framePerSecond = computed(() => 1000 / renderTime.value)
21+
22+
onMounted(() => {
23+
let frame = performance.now()
24+
25+
useIntervalFn(() => {
26+
count.value++
27+
const data = encoder.fountain().next().value
28+
block.value = data
29+
const binary = blockToBinary(data)
30+
const str = fromUint8Array(binary)
31+
svg.value = renderSVG(str, { border: 1 })
32+
const now = performance.now()
33+
renderTime.value = now - frame
34+
frame = now
35+
}, () => props.speed)
36+
})
3237
</script>
3338

3439
<template>
35-
<div flex flex-col items-center>
36-
<p mb-4>
37-
{{ activeIndex }}/{{ svgList.length }}
40+
<div flex flex-col items-center pb-20>
41+
<p mb-4 w-full of-x-auto ws-nowrap font-mono>
42+
Indices: {{ block?.indices }}<br>
43+
Total: {{ block?.k }}<br>
44+
Bytes: {{ ((block?.bytes || 0) / 1024).toFixed(2) }} KB<br>
45+
Bitrate: {{ ((block?.bytes || 0) / 1024 * framePerSecond).toFixed(2) }} Kbps<br>
46+
Frame Count: {{ count }}<br>
47+
FPS: {{ framePerSecond.toFixed(2) }}
3848
</p>
3949
<div class="relative h-full w-full">
4050
<div
41-
class="arc aspect-square" absolute inset-0
42-
:style="{ '--deg': `${(activeIndex + 1) * 360 / svgList.length}deg` }"
43-
/>
44-
<div
45-
v-for="svg, idx of svgList"
46-
:key="idx"
47-
:class="{ hidden: idx !== activeIndex }"
4851
class="aspect-square [&>svg]:h-full [&>svg]:w-full"
4952
h-full w-full
5053
v-html="svg"

0 commit comments

Comments
 (0)