5 Commits

Author SHA1 Message Date
595354b7f0 Merge pull request 'shareFps' (#9) from shareFps into master
Reviewed-on: #9
2026-01-12 07:23:51 +00:00
Nadar
d08b011596 shareFps 2026-01-12 10:22:56 +03:00
12ce381abd minor update
All checks were successful
Deploy / publish-web (push) Successful in 46s
2025-12-27 02:52:17 +06:00
2d30ac2863 minor update
All checks were successful
Deploy / publish-web (push) Successful in 44s
2025-12-27 02:49:39 +06:00
0f218c1519 button colors 2025-12-27 01:58:01 +06:00
11 changed files with 55 additions and 18 deletions

Binary file not shown.

View File

@@ -31,17 +31,17 @@ body {
.p-select-overlay { .p-select-overlay {
/* Force dropdown width to match computed min-width from PrimeVue internals. */ /* Force dropdown width to match computed min-width from PrimeVue internals. */
width: 0; width: 0 !important;
} }
.p-select-label { .p-select-label {
width: 0; width: 0 !important;
overflow: hidden; overflow: hidden !important;
text-overflow: ellipsis; text-overflow: ellipsis !important;
} }
.p-select-option-label { .p-select-option-label {
min-width: 0; min-width: 0 !important;
overflow: hidden; overflow: hidden !important;
text-overflow: ellipsis; text-overflow: ellipsis !important;
} }

View File

@@ -16,9 +16,7 @@ declare module 'vue' {
PrimeDivider: typeof import('primevue/divider')['default'] PrimeDivider: typeof import('primevue/divider')['default']
PrimeFloatLabel: typeof import('primevue/floatlabel')['default'] PrimeFloatLabel: typeof import('primevue/floatlabel')['default']
PrimeInputText: typeof import('primevue/inputtext')['default'] PrimeInputText: typeof import('primevue/inputtext')['default']
PrimeMenu: typeof import('primevue/menu')['default']
PrimePassword: typeof import('primevue/password')['default'] PrimePassword: typeof import('primevue/password')['default']
PrimeProgressBar: typeof import('primevue/progressbar')['default']
PrimeScrollPanel: typeof import('primevue/scrollpanel')['default'] PrimeScrollPanel: typeof import('primevue/scrollpanel')['default']
PrimeSelect: typeof import('primevue/select')['default'] PrimeSelect: typeof import('primevue/select')['default']
PrimeSelectButton: typeof import('primevue/selectbutton')['default'] PrimeSelectButton: typeof import('primevue/selectbutton')['default']

View File

@@ -27,7 +27,7 @@
<PrimeBadge v-if="isMe" severity="secondary" value="You" size="small" class="shrink-0" /> <PrimeBadge v-if="isMe" severity="secondary" value="You" size="small" class="shrink-0" />
</div> </div>
<Component :is="expanded ? ChevronUp : ChevronDown" v-if="!isMe" :size="20" /> <Component :is="expanded ? ChevronUp : ChevronDown" v-if="!isMe" :size="20" class="text-muted-color" />
</div> </div>
<CollapseTransition v-if="!isMe"> <CollapseTransition v-if="!isMe">

View File

@@ -12,7 +12,17 @@ export const useApp = createGlobalState(() => {
const ready = ref(false) const ready = ref(false)
const isTauri = computed(() => '__TAURI_INTERNALS__' in window) const isTauri = computed(() => '__TAURI_INTERNALS__' in window)
const commitSha = __COMMIT_SHA__ const commitSha = __COMMIT_SHA__
const version = computedAsync(() => isTauri.value ? getVersion() : 'web', '-') const version = computedAsync(() => {
if (import.meta.dev) {
return 'dev'
}
else if (isTauri.value) {
return getVersion()
}
else {
return 'web'
}
}, '-')
const inputMuted = computed(() => { const inputMuted = computed(() => {
return !!mediasoup.micProducer.value?.paused return !!mediasoup.micProducer.value?.paused

View File

@@ -29,11 +29,25 @@ export const useFullscreenVideo = createGlobalState(() => {
videoEl.value = el videoEl.value = el
} }
stream.getTracks().forEach(t =>
t.addEventListener('ended', hide),
)
videoEl.value.addEventListener('ended', hide)
await videoEl.value.requestFullscreen() await videoEl.value.requestFullscreen()
} }
function hide() { function hide() {
if (!videoEl.value)
return
(videoEl.value.srcObject as MediaStream).getTracks().forEach(t =>
t.removeEventListener('ended', hide),
)
videoEl.value.removeEventListener('ended', hide)
videoEl.value?.remove() videoEl.value?.remove()
videoEl.value = undefined
} }
useEventListener(document, 'fullscreenchange', () => { useEventListener(document, 'fullscreenchange', () => {

View File

@@ -317,7 +317,7 @@ export const useMediasoup = createSharedComposable(() => {
if (!device.value) if (!device.value)
return return
const stream = await getShareStream() const stream = await getShareStream(preferences.shareFps.value)
const track = stream.getVideoTracks()[0] const track = stream.getVideoTracks()[0]

View File

@@ -19,6 +19,8 @@ export const usePreferences = createGlobalState(() => {
const noiseSuppression = useLocalStorage('NOISE_SUPPRESSION', true) const noiseSuppression = useLocalStorage('NOISE_SUPPRESSION', true)
const echoCancellation = useLocalStorage('ECHO_CANCELLATION', true) const echoCancellation = useLocalStorage('ECHO_CANCELLATION', true)
const shareFps = useLocalStorage('SHARE_FPS', 30)
const toggleInputHotkey = ref<SyncedPreferences['toggleInputHotkey']>('') const toggleInputHotkey = ref<SyncedPreferences['toggleInputHotkey']>('')
const toggleOutputHotkey = ref<SyncedPreferences['toggleOutputHotkey']>('') const toggleOutputHotkey = ref<SyncedPreferences['toggleOutputHotkey']>('')
@@ -57,6 +59,7 @@ export const usePreferences = createGlobalState(() => {
autoGainControl, autoGainControl,
noiseSuppression, noiseSuppression,
echoCancellation, echoCancellation,
shareFps,
toggleInputHotkey, toggleInputHotkey,
toggleOutputHotkey, toggleOutputHotkey,
inputDeviceExist, inputDeviceExist,

View File

@@ -4,24 +4,24 @@
class="flex items-center justify-between gap-2 rounded-xl p-3 bg-surface-950" class="flex items-center justify-between gap-2 rounded-xl p-3 bg-surface-950"
> >
<div class="inline-flex items-center gap-3"> <div class="inline-flex items-center gap-3">
<PrimeBadge v-if="isTauri" class="opacity-50" severity="secondary" :value="version" size="small" /> <PrimeBadge class="opacity-50" severity="secondary" :value="version" size="small" />
<PrimeBadge :severity="connected ? 'success' : 'danger' " /> <PrimeBadge :severity="connected ? 'success' : 'danger' " />
</div> </div>
<PrimeButtonGroup class="ml-auto"> <PrimeButtonGroup class="ml-auto">
<PrimeButton outlined @click="toggleInput"> <PrimeButton :severity="inputMuted ? 'info' : undefined" outlined @click="toggleInput">
<template #icon> <template #icon>
<Component :is="inputMuted ? MicOff : Mic" /> <Component :is="inputMuted ? MicOff : Mic" />
</template> </template>
</PrimeButton> </PrimeButton>
<PrimeButton outlined @click="toggleOutput"> <PrimeButton :severity="outputMuted ? 'info' : undefined" outlined @click="toggleOutput">
<template #icon> <template #icon>
<Component :is="outputMuted ? VolumeOff : Volume2" /> <Component :is="outputMuted ? VolumeOff : Volume2" />
</template> </template>
</PrimeButton> </PrimeButton>
</PrimeButtonGroup> </PrimeButtonGroup>
<PrimeButton outlined @click="toggleShare"> <PrimeButton :severity="sharingEnabled ? 'success' : undefined" outlined @click="toggleShare">
<template #icon> <template #icon>
<Component :is="sharingEnabled ? ScreenShareOff : ScreenShare" /> <Component :is="sharingEnabled ? ScreenShareOff : ScreenShare" />
</template> </template>
@@ -72,7 +72,6 @@ import {
} from 'lucide-vue-next' } from 'lucide-vue-next'
const { const {
isTauri,
version, version,
clients, clients,
inputMuted, inputMuted,

View File

@@ -47,6 +47,18 @@
<!-- <label for="outputDevice">Output device</label> --> <!-- <label for="outputDevice">Output device</label> -->
<!-- </PrimeFloatLabel> --> <!-- </PrimeFloatLabel> -->
<PrimeDivider align="left">
Video
</PrimeDivider>
<div>
<div class="flex justify-between text-sm mb-3">
<span>FPS</span>
<span>{{ shareFps }}</span>
</div>
<PrimeSlider v-model="shareFps" class="mx-[10px]" :min="30" :max="60" :step="5" />
</div>
<template v-if="isTauri"> <template v-if="isTauri">
<PrimeDivider align="left"> <PrimeDivider align="left">
Hotkeys Hotkeys
@@ -117,6 +129,7 @@ const {
toggleOutputHotkey, toggleOutputHotkey,
inputDeviceExist, inputDeviceExist,
outputDeviceExist, outputDeviceExist,
shareFps,
} = usePreferences() } = usePreferences()
const setupToggleInputHotkey = (event: KeyboardEvent) => setupHotkey(event, toggleInputHotkey) const setupToggleInputHotkey = (event: KeyboardEvent) => setupHotkey(event, toggleInputHotkey)

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "chad", "productName": "chad",
"version": "0.2.17", "version": "0.2.19",
"identifier": "xyz.koptilnya.chad", "identifier": "xyz.koptilnya.chad",
"build": { "build": {
"frontendDist": "../.output/public", "frontendDist": "../.output/public",