Skip to content

Commit

Permalink
add support for pool backgrounds to device stream
Browse files Browse the repository at this point in the history
  • Loading branch information
swantzter committed Jul 10, 2023
1 parent 3a481a6 commit 4023443
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 21 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"dependencies": {
"@apollo/client": "^3.7.17",
"@github/time-elements": "^3.1.2",
"@ropescore/components": "^1.6.3",
"@ropescore/components": "^1.7.0",
"@sentry/tracing": "^7.57.0",
"@sentry/vue": "^7.57.0",
"@vue/apollo-composable": "^4.0.0-beta.8",
Expand Down
18 changes: 15 additions & 3 deletions src/components/SpeedLiveScore.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
<template>
<div
class="border border-black bg-white dark:border-gray-600 dark:bg-black dark:text-white flex items-center justify-center relative"
class="border border-black bg-white dark:border-gray-600 dark:bg-black dark:text-white flex items-center justify-center relative overflow-hidden"
:class="{
'bg-green-100': scoresheet?.__typename === 'MarkScoresheet' && scoresheet?.completedAt,
'dark:bg-green-900': scoresheet?.__typename === 'MarkScoresheet' && scoresheet?.completedAt,
'bg-gray-300': entry?.didNotSkipAt,
'dark:bg-dark-500': entry?.didNotSkipAt
}"
>
<div v-if="bgUrl" class="absolute bottom-0 right-0 left-0 max-h-[75%]">
<img :src="bgUrl" alt=" ">
<div class="absolute inset-0 flag-bg" />
</div>
<div class="absolute inset-0 full-bg" />
<div
class="font-bold text-8xl absolute top-0 left-2 text-gray-600 dark:text-gray-400"
>
Expand All @@ -20,11 +26,11 @@
{{ entry.participant.name }}
</div>
<div v-if="!entry?.didNotSkipAt" class="font-semibold tabular-nums w-full text-center font-mono custom-size">
<div v-if="!entry?.didNotSkipAt" class="z-1 font-semibold tabular-nums w-full text-center font-mono custom-size">
{{ tally?.step ?? 0 }}
</div>
<div class="absolute bottom-2 left-2 text-gray-500">
<div class="absolute top-2 right-2 text-gray-500">
<div v-if="deviceId">
{{ deviceId }}
</div>
Expand Down Expand Up @@ -67,6 +73,10 @@ const props = defineProps({
cols: {
type: Number,
default: null
},
bgUrl: {
type: String,
default: undefined
}
})
Expand All @@ -88,3 +98,5 @@ const fontSize = computed(() => {
line-height: 1;
}
</style>
<style src="./flag-bg.css"></style>
2 changes: 1 addition & 1 deletion src/components/SystemSettingsFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const newName = ref('')
label="System Name"
dense
:disabled="auth.loadingUpdate.value"
@update:model-value="newName = $event"
@update:model-value="newName = $event ?? ''"

Check failure on line 42 in src/components/SystemSettingsFooter.vue

View workflow job for this annotation

GitHub Actions / lint

Type 'string | number' is not assignable to type 'string'.
/>
<text-button color="blue" dense :loading="auth.loadingUpdate.value">
Update
Expand Down
18 changes: 15 additions & 3 deletions src/components/TimingLiveScore.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
<template>
<div
class="border border-black bg-white dark:border-gray-600 dark:bg-black dark:text-white flex items-center justify-center relative"
class="border border-black bg-white dark:border-gray-600 dark:bg-black dark:text-white flex items-center justify-center relative overflow-hidden"
:class="{
'bg-green-100': scoresheet?.__typename === 'MarkScoresheet' && scoresheet?.completedAt,
'dark:bg-green-900': scoresheet?.__typename === 'MarkScoresheet' && scoresheet?.completedAt,
'bg-gray-300': entry?.didNotSkipAt,
'dark:bg-dark-500': entry?.didNotSkipAt
}"
>
<div v-if="bgUrl" class="absolute bottom-0 right-0 left-0 max-h-[75%]">
<img :src="bgUrl" alt=" ">
<div class="absolute inset-0 flag-bg" />
</div>
<div class="absolute inset-0 full-bg" />
<div
class="font-bold text-8xl absolute top-0 left-2 text-gray-600 dark:text-gray-400"
>
Expand All @@ -20,11 +26,11 @@
{{ entry.participant.name }}
</div>
<div v-if="!entry?.didNotSkipAt" class="font-semibold tabular-nums w-full text-center font-mono custom-size">
<div v-if="!entry?.didNotSkipAt" class="z-1 font-semibold tabular-nums w-full text-center font-mono custom-size">
{{ tally?.seconds ?? 0 }}
</div>
<div class="absolute bottom-2 left-2 text-gray-500">
<div class="absolute top-2 right-2 text-gray-500">
<div v-if="deviceId">
{{ deviceId }}
</div>
Expand Down Expand Up @@ -67,6 +73,10 @@ const props = defineProps({
cols: {
type: Number,
default: null
},
bgUrl: {
type: String,
default: undefined
}
})
Expand All @@ -88,3 +98,5 @@ const fontSize = computed(() => {
line-height: 1;
}
</style>
<style src="./flag-bg.css"></style>
32 changes: 32 additions & 0 deletions src/components/flag-bg.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.custom-size {
text-shadow: 0 0 .5em black;
}

.flag-bg {
background: linear-gradient(0deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, .9) 80%,
rgba(0, 0, 0, 1) 100%);
}

.full-bg {
background: linear-gradient(0deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, .9) 50%,
rgba(0, 0, 0, 1) 100%);
}

img {
position: relative;
}

img[alt]:after {
content: ' ';
display: block;
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: black;
}
3 changes: 2 additions & 1 deletion src/hooks/stream-pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ interface StreamPool {

interface ServoPoolBackgroundsConfig {
system: 'servo'
url: string
baseUrl: string
competitionId?: number
}

interface DeviceStreamSettings {
Expand Down
67 changes: 64 additions & 3 deletions src/views/DeviceStreamLive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
:tally="tallies[pool.deviceId]?.tally"
:device-id="pool.deviceId"
:cols="cols"
:bg-url="poolBgUrl(pool.label || idx + 1)"
/>
<timing-live-score
v-else-if="tallies[pool.deviceId]?.info?.judgeType === 'T'"
:pool="pool.label || idx + 1"
:tally="tallies[pool.deviceId]?.tally"
:device-id="pool.deviceId"
:cols="cols"
:bg-url="poolBgUrl(pool.label || idx + 1)"
/>
<unsupported-competition-event
v-else
Expand All @@ -37,12 +39,12 @@
</template>
<script lang="ts" setup>
import { computed, reactive, watch } from 'vue'
import { computed, reactive, ref, watch } from 'vue'
import { type DeviceStreamJudgeInfo, type DeviceStreamMarkAddedSubscription, useDeviceStreamMarkAddedSubscription } from '../graphql/generated'
import { type ScoreTally, type Mark } from '../helpers'
import { useAuth } from '../hooks/auth'
import { useDeviceStreamPools } from '../hooks/stream-pools'
import { useHead } from '@vueuse/head'
import { useFetch, useTimeoutPoll } from '@vueuse/core'
import DeviceNotSet from '../components/DeviceNotSet.vue'
import SpeedLiveScore from '../components/SpeedLiveScore.vue'
Expand All @@ -53,7 +55,6 @@ useHead({
title: '📺 Device Stream (Live)'
})
const auth = useAuth()
const { pools, settings } = useDeviceStreamPools()
const cols = computed(() => {
Expand Down Expand Up @@ -114,6 +115,66 @@ function markStreamWatcher (res: DeviceStreamMarkAddedSubscription | null | unde
watch(markStreamSubscription.result, markStreamWatcher)
watch(markStreamSubscriptionAlt.result, markStreamWatcher)
const poolBackgrounds = ref<Array<{ poolLabel: number, bgUrl?: string }>>([])
function poolBgUrl (poolLabel: number) {
return poolBackgrounds.value.find(pb => `${pb.poolLabel}` === `${poolLabel}`)?.bgUrl
}
const servoPollUrl = ref<string>('')
interface ServoHeatPoolInfo {
PROGRAM: 'ON' | ''
Station: number
HeatNumber: string
Event: string
Team: string
TeamCountryCode: string
TeamCountryName: string
TeamCountryFlagUrl: string
[nameKey: `Part${number}`]: string
[lastNameKey: `Part${number}_Last`]: string
}
const servoCurrentHeatFetch = useFetch(servoPollUrl, {
headers: {
accept: 'application/json'
}
}, {
immediate: false
}).get().json<ServoHeatPoolInfo[]>()
watch(servoCurrentHeatFetch.data, heatInfo => {
if (heatInfo == null) {
poolBackgrounds.value = []
return
}
poolBackgrounds.value = heatInfo.map(hi => ({
poolLabel: hi.Station,
bgUrl: hi.TeamCountryFlagUrl ?? (hi.TeamCountryCode ? `/flags/${hi.TeamCountryCode}.svg` : undefined)
}))
})
const servoPoll = useTimeoutPoll(() => {
servoCurrentHeatFetch.execute()
}, 10_000, { immediate: false })
watch(() => settings.value.poolBackgrounds, poolBackgrounds => {
// start by just disabling all polling
servoPoll.pause()
if (poolBackgrounds?.system === 'servo' && poolBackgrounds.competitionId != null) {
let url
try {
url = new URL(`/api/v1/competitions/${poolBackgrounds.competitionId}/info/current`, poolBackgrounds.baseUrl)
} catch {
return
}
servoPollUrl.value = url.href
servoPoll.resume()
}
}, { immediate: true })
</script>
<style scoped>
Expand Down
42 changes: 40 additions & 2 deletions src/views/DeviceStreamSetup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,31 @@
</table>
<form id="request-share" @submit.prevent="requestShare.mutate({ deviceId: newDeviceId })" />

<h2 class="text-xl">
Pool Backgrounds
</h2>
<div>
<select-field
:model-value="settings.poolBackgrounds?.system"
label="Pool Backgrounds System"
:data-list="['servo']"
@update:model-value="setPoolBackgroundsSystem($event)"

Check failure on line 98 in src/views/DeviceStreamSetup.vue

View workflow job for this annotation

GitHub Actions / lint

Argument of type 'string | number' is not assignable to parameter of type 'string | undefined'.
/>
<text-field
v-if="settings.poolBackgrounds?.system === 'servo'"
v-model="settings.poolBackgrounds.baseUrl"
label="Servo Scoring Base URL"
type="url"
/>
<number-field
v-if="settings.poolBackgrounds?.system === 'servo'"
v-model="settings.poolBackgrounds.competitionId"
label="Servo Scoring Competition ID"
:min="0"
:step="1"
/>
</div>
<h2 class="mt-4 text-xl">
Pools
</h2>
Expand Down Expand Up @@ -114,11 +139,13 @@
<tr v-for="(pool, idx) of pools" :key="idx">
<td>{{ idx + 1 }}</td>
<td>
<text-field
<number-field
:model-value="pool.label"
dense
label="Pool Label"
type="number"
:step="1"
:min="1"
@update:model-value="pool.label = $event"
/>
</td>
Expand Down Expand Up @@ -156,7 +183,7 @@ import { useDeviceStreamPools } from '../hooks/stream-pools'
import { DeviceStreamShareStatus, useRequestStreamShareMutation, useUserStreamSharesQuery } from '../graphql/generated'
import { useHead } from '@vueuse/head'
import { TextButton, TextField, SelectField, ButtonLink } from '@ropescore/components'
import { TextButton, TextField, SelectField, ButtonLink, NumberField } from '@ropescore/components'
import IconLoading from 'virtual:icons/mdi/loading'
useHead({
Expand Down Expand Up @@ -187,6 +214,17 @@ requestShare.onDone(() => {
const { pools, settings } = useDeviceStreamPools()
function setPoolBackgroundsSystem (system: string | undefined) {
if (system === 'servo' && settings.value.poolBackgrounds?.system !== 'servo') {
settings.value.poolBackgrounds = {
system: 'servo',
baseUrl: 'https://scoring.ijru.sport'
}
} else {
settings.value.poolBackgrounds = null
}
}
// Remove devices you no longer have access to from pools
sharesQuery.onResult(res => {
if (res.data?.me?.__typename !== 'User') return
Expand Down

0 comments on commit 4023443

Please sign in to comment.