From 87721c96194f80ecf774dc2ce71118b93ee6440c Mon Sep 17 00:00:00 2001 From: André Oliveira <37463445+SpecialAro@users.noreply.github.com> Date: Sat, 4 May 2024 01:40:38 +0100 Subject: Fix screenshare on wayland and style (#1739) * fix: screenshare prompts twice * Add loading screen --- src/components/MediaSource.tsx | 147 ++++++++++++++++++++++++++++++++--------- src/environment.ts | 2 + src/i18n/locales/en-US.json | 2 + 3 files changed, 120 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/components/MediaSource.tsx b/src/components/MediaSource.tsx index 02e617800..34fbda227 100644 --- a/src/components/MediaSource.tsx +++ b/src/components/MediaSource.tsx @@ -1,37 +1,65 @@ import { ipcRenderer } from 'electron'; -import { useEffect, useState } from 'react'; +import { type MouseEventHandler, useEffect, useState } from 'react'; +import { + type WrappedComponentProps, + defineMessages, + injectIntl, +} from 'react-intl'; import { SCREENSHARE_CANCELLED_BY_USER } from '../config'; +import { isWayland } from '../environment'; import type Service from '../models/Service'; +import FullscreenLoader from './ui/FullscreenLoader'; -export interface IProps { +interface IProps extends WrappedComponentProps { service: Service; } -export default function MediaSource(props: IProps) { - const { service } = props; +const messages = defineMessages({ + loading: { + id: 'service.screenshare.loading', + defaultMessage: 'Loading screens and windows', + }, + cancel: { + id: 'service.screenshare.cancel', + defaultMessage: 'Cancel', + }, +}); + +interface ICancelButtonProps extends WrappedComponentProps { + handleOnClick: MouseEventHandler | undefined; +} + +const CancelButton = injectIntl( + ({ handleOnClick, intl }: ICancelButtonProps) => ( +
  • + +
  • + ), +); + +function MediaSource(props: IProps) { + const { service, intl } = props; const [sources, setSources] = useState([]); const [show, setShow] = useState(false); const [trackerId, setTrackerId] = useState(null); + const [loadingSources, setLoadingSources] = useState(false); ipcRenderer.on(`select-capture-device:${service.id}`, (_event, data) => { + if (loadingSources) return; setShow(true); setTrackerId(data.trackerId); }); - useEffect(() => { - if (show) { - ipcRenderer - .invoke('get-desktop-capturer-sources') - .then(sources => setSources(sources)); - } else { - setSources([]); - } - }, [show]); - - if (sources.length === 0 || !show) { - return null; - } - const handleOnClick = (e: any) => { const { id } = e.currentTarget.dataset; window['ferdium'].actions.service.sendIPCMessage({ @@ -43,9 +71,76 @@ export default function MediaSource(props: IProps) { }); setShow(false); + setSources([]); setTrackerId(null); }; + // biome-ignore lint/correctness/useExhaustiveDependencies: This effect should only run when `show` changes + useEffect(() => { + if (show) { + setLoadingSources(true); + ipcRenderer + .invoke('get-desktop-capturer-sources') + .then(sources => { + if (isWayland) { + // On Linux, we do not need to prompt the user again for the source + handleOnClick({ + currentTarget: { dataset: { id: sources[0].id } }, + }); + return; + } + + setSources(sources); + setLoadingSources(false); + }) + // silence the error + .catch(() => { + setShow(false); + setSources([]); + setLoadingSources(false); + }); + } else { + setSources([]); + setLoadingSources(false); + } + }, [show]); + + if (!show) { + return null; + } + + if (loadingSources) { + return ( +
    +
      + +
      + +
      +
      +
    +
    + ); + } + + if (sources.length === 0) { + return ( +
    +
      +
    • No available sources.
    • + +
    +
    + ); + } + return (
      @@ -67,20 +162,10 @@ export default function MediaSource(props: IProps) { ))} -
    • - -
    +
    ); } + +export default injectIntl(MediaSource); diff --git a/src/environment.ts b/src/environment.ts index 87e2f4f66..4a0399876 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -7,6 +7,8 @@ export const isWindows = process.platform === 'win32'; export const isLinux = process.platform === 'linux'; export const isWinPortable = process.env.PORTABLE_EXECUTABLE_FILE != null; +export const isWayland = isLinux && process.env.XDG_SESSION_TYPE === 'wayland'; + export const electronVersion: string = process.versions.electron ?? ''; export const chromeVersion: string = process.versions.chrome ?? ''; export const nodeVersion: string = process.versions.node; diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 1835854e1..3947b2e5f 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -164,6 +164,8 @@ "service.errorHandler.headline": "Oh no!", "service.errorHandler.message": "Error", "service.errorHandler.text": "{name} has failed to load.", + "service.screenshare.cancel": "Cancel", + "service.screenshare.loading": "Loading screens and windows", "service.webviewLoader.loading": "Loading {service}", "services.getStarted": "Get started", "services.login": "Please login to use Ferdium.", -- cgit v1.2.3-70-g09d2