This commit is contained in:
parent
fc43c8df96
commit
e2064dba6c
Binary file not shown.
@ -5,6 +5,3 @@
|
||||
|
||||
<PrimeToast position="bottom-center" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
<span>Volume</span>
|
||||
<span>{{ volume }}</span>
|
||||
</div>
|
||||
<PrimeSlider v-model="volume" class="mt-4" :min="0" :max="1000" :step="5" />
|
||||
<PrimeSlider v-model="volume" class="mt-4" :min="0" :max="1000" :step="volume < 200 ? 5 : 25" />
|
||||
</div>
|
||||
</template>
|
||||
</PrimeMenu>
|
||||
|
||||
@ -1,12 +1,17 @@
|
||||
import { createGlobalState } from '@vueuse/core'
|
||||
import { useClients } from '~/composables/use-clients'
|
||||
|
||||
export const useApp = createGlobalState(() => {
|
||||
const { clients } = useClients()
|
||||
const mediasoup = useMediasoup()
|
||||
const toast = useToast()
|
||||
|
||||
const inputMuted = ref(false)
|
||||
const outputMuted = ref(false)
|
||||
|
||||
const me = computed(() => mediasoup.clients.value.find(client => client.isMe))
|
||||
const previousInputMuted = ref(inputMuted.value)
|
||||
|
||||
const me = computed(() => clients.value.find(client => client.isMe))
|
||||
|
||||
function muteInput() {
|
||||
inputMuted.value = true
|
||||
@ -38,15 +43,36 @@ export const useApp = createGlobalState(() => {
|
||||
muteOutput()
|
||||
}
|
||||
|
||||
watch(inputMuted, async (state) => {
|
||||
if (state)
|
||||
watch(inputMuted, async (inputMuted) => {
|
||||
if (inputMuted) {
|
||||
await mediasoup.muteMic()
|
||||
else
|
||||
}
|
||||
else {
|
||||
if (outputMuted.value) {
|
||||
outputMuted.value = false
|
||||
}
|
||||
await mediasoup.unmuteMic()
|
||||
}
|
||||
|
||||
const toastText = inputMuted ? 'Microphone muted' : 'Microphone activated'
|
||||
toast.add({ severity: 'info', summary: toastText, closable: false, life: 1000 })
|
||||
})
|
||||
|
||||
watch(outputMuted, (outputMuted) => {
|
||||
if (outputMuted) {
|
||||
previousInputMuted.value = inputMuted.value
|
||||
muteInput()
|
||||
}
|
||||
else {
|
||||
inputMuted.value = previousInputMuted.value
|
||||
}
|
||||
|
||||
const toastText = outputMuted ? 'Sound muted' : 'Sound resumed'
|
||||
toast.add({ severity: 'info', summary: toastText, closable: false, life: 1000 })
|
||||
})
|
||||
|
||||
return {
|
||||
clients: mediasoup.clients,
|
||||
clients,
|
||||
me,
|
||||
inputMuted,
|
||||
muteInput,
|
||||
|
||||
58
client/app/composables/use-clients.ts
Normal file
58
client/app/composables/use-clients.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import type { ChadClient, UpdatedClient } from '#shared/types'
|
||||
import { createGlobalState } from '@vueuse/core'
|
||||
|
||||
export const useClients = createGlobalState(() => {
|
||||
const signaling = useSignaling()
|
||||
const toast = useToast()
|
||||
|
||||
const clients = shallowRef<ChadClient[]>([])
|
||||
|
||||
watch(signaling.socket, (socket) => {
|
||||
if (!socket)
|
||||
return
|
||||
|
||||
socket.on('clientChanged', (clientId: ChadClient['id'], updatedClient: UpdatedClient) => {
|
||||
const client = getClient(clientId)
|
||||
updateClient(clientId, updatedClient)
|
||||
|
||||
if (updatedClient.username)
|
||||
toast.add({ severity: 'info', summary: `${client?.username} is now ${updatedClient.username}`, closable: false, life: 1000 })
|
||||
})
|
||||
})
|
||||
|
||||
function getClient(clientId: ChadClient['id']) {
|
||||
return clients.value.find(client => client.id === clientId)
|
||||
}
|
||||
|
||||
function addClient(...client: ChadClient[]) {
|
||||
clients.value.push(...client)
|
||||
|
||||
triggerRef(clients)
|
||||
}
|
||||
|
||||
function removeClient(clientId: ChadClient['id']) {
|
||||
clients.value = clients.value.filter(client => client.id !== clientId)
|
||||
}
|
||||
|
||||
function updateClient(clientId: ChadClient['id'], updatedClient: UpdatedClient) {
|
||||
const clientIdx = clients.value.findIndex(client => client.id === clientId)
|
||||
|
||||
if (clientIdx === -1)
|
||||
return
|
||||
|
||||
clients.value[clientIdx] = {
|
||||
...clients.value[clientIdx],
|
||||
...updatedClient,
|
||||
} as ChadClient
|
||||
|
||||
triggerRef(clients)
|
||||
}
|
||||
|
||||
return {
|
||||
clients,
|
||||
getClient,
|
||||
addClient,
|
||||
removeClient,
|
||||
updateClient,
|
||||
}
|
||||
})
|
||||
@ -18,8 +18,11 @@ const ICE_SERVERS: RTCIceServer[] = [
|
||||
]
|
||||
|
||||
export const useMediasoup = createSharedComposable(() => {
|
||||
const preferences = usePreferences()
|
||||
const toast = useToast()
|
||||
|
||||
const signaling = useSignaling()
|
||||
const { addClient, removeClient } = useClients()
|
||||
const preferences = usePreferences()
|
||||
|
||||
const device = shallowRef<mediasoupClient.Device>()
|
||||
const rtpCapabilities = shallowRef<mediasoupClient.types.RtpCapabilities>()
|
||||
@ -30,8 +33,6 @@ export const useMediasoup = createSharedComposable(() => {
|
||||
const webcamProducer = shallowRef<mediasoupClient.types.Producer>()
|
||||
const shareProducer = shallowRef<mediasoupClient.types.Producer>()
|
||||
|
||||
const clients = shallowRef<ChadClient[]>([])
|
||||
|
||||
const consumers = shallowRef<Map<string, mediasoupClient.types.Consumer>>(new Map())
|
||||
const producers = shallowRef<Map<string, mediasoupClient.types.Producer>>(new Map())
|
||||
|
||||
@ -121,21 +122,24 @@ export const useMediasoup = createSharedComposable(() => {
|
||||
})
|
||||
}
|
||||
|
||||
clients.value = (await signaling.socket.value.emitWithAck('join', {
|
||||
const joinedClients = (await signaling.socket.value.emitWithAck('join', {
|
||||
username: preferences.username.value,
|
||||
rtpCapabilities: rtpCapabilities.value,
|
||||
})).map(transformClient)
|
||||
|
||||
addClient(...joinedClients)
|
||||
|
||||
toast.add({ severity: 'success', summary: 'Joined', closable: false, life: 1000 })
|
||||
|
||||
await enableMic()
|
||||
})
|
||||
|
||||
socket.on('newPeer', (client) => {
|
||||
clients.value.push(transformClient(client))
|
||||
triggerRef(clients)
|
||||
addClient(transformClient(client))
|
||||
})
|
||||
|
||||
socket.on('peerClosed', (id) => {
|
||||
clients.value = clients.value.filter(client => client.id !== id)
|
||||
removeClient(id)
|
||||
})
|
||||
|
||||
socket.on(
|
||||
@ -317,7 +321,6 @@ export const useMediasoup = createSharedComposable(() => {
|
||||
|
||||
return {
|
||||
init,
|
||||
clients,
|
||||
consumers,
|
||||
producers,
|
||||
sendTransport,
|
||||
|
||||
@ -3,6 +3,8 @@ import { createSharedComposable } from '@vueuse/core'
|
||||
import { io } from 'socket.io-client'
|
||||
|
||||
export const useSignaling = createSharedComposable(() => {
|
||||
const toast = useToast()
|
||||
|
||||
const socket = shallowRef<Socket>()
|
||||
|
||||
const connected = ref(false)
|
||||
@ -35,6 +37,13 @@ export const useSignaling = createSharedComposable(() => {
|
||||
})
|
||||
}, { immediate: true, flush: 'sync' })
|
||||
|
||||
watch(connected, (connected) => {
|
||||
if (connected)
|
||||
toast.add({ severity: 'success', summary: 'Connected', closable: false, life: 1000 })
|
||||
else
|
||||
toast.add({ severity: 'error', summary: 'Disconnected', closable: false, life: 1000 })
|
||||
}, { immediate: true })
|
||||
|
||||
onScopeDispose(() => {
|
||||
socket.value?.close()
|
||||
})
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-auto-animate class="grid grid-cols-2 h-screen">
|
||||
<div class="flex flex-col shadow-xl shadow-surface-950 overflow-y-hidden z-10">
|
||||
<div class="flex flex-col shadow-xl shadow-surface-950 overflow-y-hidden">
|
||||
<AppHeader title="Шальные сиськи 18+">
|
||||
<template #right>
|
||||
<PrimeButtonGroup class="ml-auto">
|
||||
|
||||
@ -18,14 +18,19 @@ definePageMeta({
|
||||
name: 'Preferences',
|
||||
})
|
||||
|
||||
const signaling = useSignaling()
|
||||
const { username } = usePreferences()
|
||||
const toast = useToast()
|
||||
|
||||
const localUsername = ref(username.value)
|
||||
|
||||
function save() {
|
||||
async function save() {
|
||||
if (localUsername.value && localUsername.value !== username.value) {
|
||||
username.value = localUsername.value
|
||||
|
||||
toast.add({ severity: 'success', summary: 'Saved', life: 3000 })
|
||||
await signaling.socket.value?.emitWithAck('updateClient', { username })
|
||||
}
|
||||
|
||||
toast.add({ severity: 'success', summary: 'Saved', life: 1000, closable: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -3,7 +3,7 @@ import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-09-29',
|
||||
devtools: { enabled: true },
|
||||
devtools: { enabled: true, vueDevTools: true },
|
||||
ssr: false,
|
||||
modules: [
|
||||
'@nuxt/fonts',
|
||||
|
||||
@ -8,3 +8,5 @@ export interface ChadClient extends RemoteClient {
|
||||
inputMuted?: boolean
|
||||
outputMuted?: boolean
|
||||
}
|
||||
|
||||
export type UpdatedClient = Omit<ChadClient, 'id' | 'isMe'>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user