Files
huly-platform/plugins/love-resources/src/components/ControlBar.svelte
T

327 lines
10 KiB
Svelte

<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { getCurrentEmployee } from '@hcengineering/contact'
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
import { Room, RoomType, isOffice, roomAccessIcon, RoomAccess } from '@hcengineering/love'
import { getResource } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import {
ButtonMenu,
DropdownIntlItem,
IconMaximize,
IconMoreV,
IconUpOutline,
ModernButton,
Popup,
SplitButton,
eventToHTMLElement,
showPopup,
TooltipInstance
} from '@hcengineering/ui'
import view, { Action } from '@hcengineering/view'
import { getActions } from '@hcengineering/view-resources'
import { toggleCamState, toggleMicState, state } from '@hcengineering/media-resources'
import love from '../plugin'
import { currentRoom, myInfo, myOffice } from '../stores'
import {
isFullScreen,
isRecording,
isRecordingAvailable,
isShareWithSound,
isSharingEnabled,
isTranscription,
isTranscriptionAllowed,
leaveRoom,
record,
screenSharing,
setShare,
startTranscription,
stopTranscription,
lk
} from '../utils'
import CamSettingPopup from './meeting/CamSettingPopup.svelte'
import ControlBarContainer from './ControlBarContainer.svelte'
import MicSettingPopup from './meeting/MicSettingPopup.svelte'
import RoomAccessPopup from './RoomAccessPopup.svelte'
import RoomModal from './RoomModal.svelte'
import ShareSettingPopup from './ShareSettingPopup.svelte'
import { lkSessionConnected } from '../liveKitClient'
import emojiPlugin from '@hcengineering/emoji'
export let room: Room
export let canMaximize: boolean = true
export let fullScreen: boolean = false
export let onFullScreen: (() => void) | undefined = undefined
let allowCam: boolean = false
const allowShare: boolean = true
let allowLeave: boolean = false
let noLabel: boolean = false
$: allowCam = $currentRoom?.type === RoomType.Video
$: allowLeave = $myInfo?.room !== ($myOffice?._id ?? love.ids.Reception)
$: isMicEnabled = $state.microphone?.enabled === true
$: isCamEnabled = $state.camera?.enabled === true
async function changeShare (): Promise<void> {
const newValue = !$isSharingEnabled
const audio = newValue && $isShareWithSound
await setShare(newValue, audio)
}
async function leave (): Promise<void> {
await leaveRoom($myInfo, $myOffice)
}
function micSettings (e: MouseEvent): void {
showPopup(MicSettingPopup, {}, eventToHTMLElement(e))
}
function camSettings (e: MouseEvent): void {
showPopup(CamSettingPopup, {}, eventToHTMLElement(e))
}
function shareSettings (e: MouseEvent): void {
showPopup(ShareSettingPopup, {}, eventToHTMLElement(e))
}
function setAccess (e: MouseEvent): void {
if (isOffice(room) && room.person !== me) return
showPopup(RoomAccessPopup, { room }, eventToHTMLElement(e))
}
const me = getCurrentEmployee()
const client = getClient()
const camKeys = client.getModel().findAllSync(view.class.Action, { _id: love.action.ToggleVideo })?.[0]?.keyBinding
const micKeys = client.getModel().findAllSync(view.class.Action, { _id: love.action.ToggleMic })?.[0]?.keyBinding
let actions: Action[] = []
let moreItems: DropdownIntlItem[] = []
$: void getActions(client, room, love.class.Room).then((res) => {
actions = res
})
$: moreItems = actions.map((action) => ({
id: action._id,
label: action.label,
icon: action.icon
}))
async function handleMenuOption (e: CustomEvent<DropdownIntlItem['id']>): Promise<void> {
const action = actions.find((action) => action._id === e.detail)
if (action !== undefined) {
await handleAction(action)
}
}
async function handleAction (action: Action): Promise<void> {
const fn = await getResource(action.action)
await fn(room)
}
$: withVideo = $screenSharing || room.type === RoomType.Video
function maximize (): void {
showPopup(RoomModal, { room }, 'full-centered')
}
function addReaction (event: MouseEvent): void {
showPopup(
emojiPlugin.component.EmojiPopup,
{},
event?.target as HTMLElement,
async (result) => {
const emoji = result?.text
if (emoji == null) return
void lk.localParticipant.sendChatMessage(emoji, { topic: 'reaction' })
},
() => {}
)
}
</script>
<ControlBarContainer bind:noLabel>
<svelte:fragment slot="right">
{#if room._id !== love.ids.Reception && $lkSessionConnected}
<ModernButton
icon={roomAccessIcon[room.access]}
iconProps={{
fill:
room.access === RoomAccess.Open
? 'var(--bg-positive-default)'
: room.access === RoomAccess.DND
? 'var(--bg-negative-default)'
: 'currentColor'
}}
tooltip={{ label: love.string.ChangeAccess }}
kind={'secondary'}
size={'large'}
disabled={isOffice(room) && room.person !== me}
on:click={setAccess}
/>
{/if}
</svelte:fragment>
<svelte:fragment slot="center">
{#if $lkSessionConnected}
<ModernButton icon={emojiPlugin.icon.Emoji} kind={'secondary'} size={'large'} on:click={addReaction} />
<SplitButton
size={'large'}
icon={isMicEnabled ? love.icon.MicEnabled : love.icon.MicDisabled}
showTooltip={{
label: isMicEnabled ? love.string.Mute : love.string.UnMute,
keys: micKeys
}}
action={toggleMicState}
secondIcon={IconUpOutline}
secondAction={micSettings}
separate
/>
{#if allowCam}
<SplitButton
size={'large'}
icon={isCamEnabled ? love.icon.CamEnabled : love.icon.CamDisabled}
showTooltip={{
label: isCamEnabled ? love.string.StopVideo : love.string.StartVideo,
keys: camKeys
}}
action={toggleCamState}
secondIcon={IconUpOutline}
secondAction={camSettings}
separate
/>
{/if}
{#if allowShare}
<SplitButton
size={'large'}
icon={$isSharingEnabled ? love.icon.SharingEnabled : love.icon.SharingDisabled}
iconProps={{
fill: $isSharingEnabled ? 'var(--bg-negative-default)' : 'var(--bg-positive-default)'
}}
showTooltip={{ label: $isSharingEnabled ? love.string.StopShare : love.string.Share }}
disabled={($screenSharing && !$isSharingEnabled) || !$lkSessionConnected}
action={changeShare}
secondIcon={IconUpOutline}
secondAction={shareSettings}
separate
/>
{/if}
{#if hasAccountRole(getCurrentAccount(), AccountRole.User) && $isRecordingAvailable}
<ModernButton
icon={$isRecording ? love.icon.StopRecord : love.icon.Record}
tooltip={{ label: $isRecording ? love.string.StopRecord : love.string.Record }}
disabled={!$lkSessionConnected}
kind={'secondary'}
size={'large'}
on:click={() => record(room)}
/>
{/if}
{#if hasAccountRole(getCurrentAccount(), AccountRole.User) && isTranscriptionAllowed() && $lkSessionConnected}
<ModernButton
icon={view.icon.Feather}
iconProps={$isTranscription ? { fill: 'var(--button-negative-BackgroundColor)' } : {}}
tooltip={{ label: $isTranscription ? love.string.StopTranscription : love.string.StartTranscription }}
kind="secondary"
size="large"
on:click={() => {
if ($isTranscription) {
void stopTranscription(room)
} else {
void startTranscription(room)
}
}}
/>
{/if}
{:else}
<ModernButton
icon={roomAccessIcon[room.access]}
iconProps={{
fill:
room.access === RoomAccess.Open
? 'var(--bg-positive-default)'
: room.access === RoomAccess.DND
? 'var(--bg-negative-default)'
: 'currentColor'
}}
tooltip={{ label: love.string.ChangeAccess }}
kind={'secondary'}
size={'large'}
disabled={isOffice(room) && room.person !== me}
on:click={setAccess}
/>
{/if}
</svelte:fragment>
<svelte:fragment slot="left">
{#if $lkSessionConnected && withVideo && onFullScreen}
<ModernButton
icon={$isFullScreen ? love.icon.ExitFullScreen : love.icon.FullScreen}
tooltip={{
label: $isFullScreen ? love.string.ExitingFullscreenMode : love.string.FullscreenMode,
direction: 'top'
}}
kind={'secondary'}
size={'large'}
on:click={() => {
$isFullScreen = !$isFullScreen
}}
/>
{/if}
{#if ($screenSharing || room.type === RoomType.Video) && $lkSessionConnected && canMaximize}
<ModernButton
icon={IconMaximize}
tooltip={{
label: love.string.FullscreenMode,
direction: 'top'
}}
kind={'secondary'}
iconSize="medium"
size={'large'}
on:click={maximize}
/>
{/if}
{#if $lkSessionConnected && moreItems.length > 0}
<ButtonMenu
items={moreItems}
icon={IconMoreV}
tooltip={{ label: love.string.MoreOptions, direction: 'top' }}
kind="secondary"
size="large"
noSelection
on:selected={handleMenuOption}
/>
{/if}
{#if allowLeave}
<ModernButton
icon={love.icon.LeaveRoom}
label={noLabel ? undefined : love.string.LeaveRoom}
tooltip={{ label: love.string.LeaveRoom, direction: 'top' }}
kind={'negative'}
size={'large'}
on:click={leave}
/>
{/if}
</svelte:fragment>
<svelte:fragment slot="extra">
{#if fullScreen}
<Popup fullScreen />
<TooltipInstance fullScreen />
{/if}
</svelte:fragment>
</ControlBarContainer>