Fix UI
This commit is contained in:
parent
8435cabcec
commit
7e78d5c0ae
6 changed files with 87 additions and 52 deletions
|
@ -4,7 +4,7 @@
|
||||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { app, desktopCapturer, dialog, ipcMain, session, shell } from "electron";
|
import { app, dialog, ipcMain, session, shell } from "electron";
|
||||||
import { existsSync, readFileSync, watch } from "fs";
|
import { existsSync, readFileSync, watch } from "fs";
|
||||||
import { open, readFile } from "fs/promises";
|
import { open, readFile } from "fs/promises";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
@ -75,8 +75,6 @@ ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
|
||||||
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
|
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.CAPTURER_GET_SOURCES, (_, options) => desktopCapturer.getSources(options));
|
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
|
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
|
||||||
const res = await dialog.showOpenDialog(mainWin!, {
|
const res = await dialog.showOpenDialog(mainWin!, {
|
||||||
properties: ["openDirectory"]
|
properties: ["openDirectory"]
|
||||||
|
|
|
@ -4,9 +4,22 @@
|
||||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { desktopCapturer, session } from "electron";
|
import { desktopCapturer, ipcMain, session, Streams } from "electron";
|
||||||
|
import type { StreamPick } from "renderer/components/ScreenSharePicker";
|
||||||
|
import { IpcEvents } from "shared/IpcEvents";
|
||||||
|
|
||||||
export function registerScreenShareHandler() {
|
export function registerScreenShareHandler() {
|
||||||
|
ipcMain.handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => {
|
||||||
|
const sources = await desktopCapturer.getSources({
|
||||||
|
types: ["window", "screen"],
|
||||||
|
thumbnailSize: {
|
||||||
|
width: 1920,
|
||||||
|
height: 1080
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sources.find(s => s.id === id)?.thumbnail.toDataURL();
|
||||||
|
});
|
||||||
|
|
||||||
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
|
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
|
||||||
const sources = await desktopCapturer.getSources({
|
const sources = await desktopCapturer.getSources({
|
||||||
types: ["window", "screen"],
|
types: ["window", "screen"],
|
||||||
|
@ -24,17 +37,19 @@ export function registerScreenShareHandler() {
|
||||||
|
|
||||||
const choice = await request.frame
|
const choice = await request.frame
|
||||||
.executeJavaScript(`VencordDesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
|
.executeJavaScript(`VencordDesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
|
||||||
.catch(() => "cancelled");
|
.then(e => e as StreamPick)
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
if (choice === "cancelled") {
|
if (!choice) return callback({});
|
||||||
callback({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = sources.find(s => s.id === choice);
|
const source = sources.find(s => s.id === choice.id);
|
||||||
callback({
|
if (!source) return callback({});
|
||||||
video: source,
|
|
||||||
audio: "loopback"
|
const streams: Streams = {
|
||||||
});
|
video: source
|
||||||
|
};
|
||||||
|
if (choice.audio) streams.audio = "loopback";
|
||||||
|
|
||||||
|
callback(streams);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { DesktopCapturerSource, SourcesOptions } from "electron";
|
|
||||||
import type { Settings } from "shared/settings";
|
import type { Settings } from "shared/settings";
|
||||||
import type { LiteralUnion } from "type-fest";
|
import type { LiteralUnion } from "type-fest";
|
||||||
|
|
||||||
|
@ -37,13 +36,6 @@ export const VencordDesktopNative = {
|
||||||
focus: () => invoke<void>(IpcEvents.FOCUS)
|
focus: () => invoke<void>(IpcEvents.FOCUS)
|
||||||
},
|
},
|
||||||
capturer: {
|
capturer: {
|
||||||
getSources: async (options?: SourcesOptions) => {
|
getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id)
|
||||||
const res = await invoke<DesktopCapturerSource[]>(IpcEvents.CAPTURER_GET_SOURCES, options);
|
|
||||||
return res.map(({ id, name, thumbnail }) => ({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
url: thumbnail.toDataURL()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
import "./screenSharePicker.css";
|
import "./screenSharePicker.css";
|
||||||
|
|
||||||
import { Modals, openModal } from "@vencord/types/utils";
|
import { closeModal, Modals, openModal, useAwaiter } from "@vencord/types/utils";
|
||||||
import { Button, Card, Forms, Switch, Text, useState } from "@vencord/types/webpack/common";
|
import { Button, Card, Forms, Switch, Text, useState } from "@vencord/types/webpack/common";
|
||||||
import { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
|
||||||
const StreamResolutions = ["720", "1080", "1440", "Source"] as const;
|
const StreamResolutions = ["720", "1080", "1440", "Source"] as const;
|
||||||
const StreamFps = ["15", "30", "60"] as const;
|
const StreamFps = ["15", "30", "60"] as const;
|
||||||
|
@ -22,6 +22,10 @@ interface StreamSettings {
|
||||||
audio: boolean;
|
audio: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface StreamPick extends StreamSettings {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface Source {
|
interface Source {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -29,18 +33,26 @@ interface Source {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openScreenSharePicker(screens: Source[]) {
|
export function openScreenSharePicker(screens: Source[]) {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<StreamPick>((resolve, reject) => {
|
||||||
openModal(props => (
|
const key = openModal(
|
||||||
<ModalComponent
|
props => (
|
||||||
screens={screens}
|
<ModalComponent
|
||||||
modalProps={props}
|
screens={screens}
|
||||||
submit={resolve}
|
modalProps={props}
|
||||||
close={() => {
|
submit={resolve}
|
||||||
props.onClose();
|
close={() => {
|
||||||
reject(new Error("Aborted"));
|
props.onClose();
|
||||||
}}
|
reject("Aborted");
|
||||||
/>
|
}}
|
||||||
));
|
/>
|
||||||
|
),
|
||||||
|
{
|
||||||
|
onCloseRequest() {
|
||||||
|
closeModal(key);
|
||||||
|
reject("Aborted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,11 +80,16 @@ function StreamSettings({
|
||||||
settings: StreamSettings;
|
settings: StreamSettings;
|
||||||
setSettings: Dispatch<SetStateAction<StreamSettings>>;
|
setSettings: Dispatch<SetStateAction<StreamSettings>>;
|
||||||
}) {
|
}) {
|
||||||
|
const [thumb] = useAwaiter(() => VencordDesktopNative.capturer.getLargeThumbnail(source.id), {
|
||||||
|
fallbackValue: source.url,
|
||||||
|
deps: [source.id]
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
|
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
|
||||||
<Card className="vcd-screen-picker-card vcd-screen-picker-preview">
|
<Card className="vcd-screen-picker-card vcd-screen-picker-preview">
|
||||||
<img src={source.url} alt="" />
|
<img src={thumb} alt="" />
|
||||||
<Text variant="text-sm/normal">{source.name}</Text>
|
<Text variant="text-sm/normal">{source.name}</Text>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
@ -85,7 +102,7 @@ function StreamSettings({
|
||||||
<div className="vcd-screen-picker-radios">
|
<div className="vcd-screen-picker-radios">
|
||||||
{StreamResolutions.map(res => (
|
{StreamResolutions.map(res => (
|
||||||
<label className="vcd-screen-picker-radio" data-checked={settings.resolution === res}>
|
<label className="vcd-screen-picker-radio" data-checked={settings.resolution === res}>
|
||||||
<Forms.FormTitle>{res}</Forms.FormTitle>
|
<Text variant="text-sm/bold">{res}</Text>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="resolution"
|
name="resolution"
|
||||||
|
@ -103,7 +120,7 @@ function StreamSettings({
|
||||||
<div className="vcd-screen-picker-radios">
|
<div className="vcd-screen-picker-radios">
|
||||||
{StreamFps.map(fps => (
|
{StreamFps.map(fps => (
|
||||||
<label className="vcd-screen-picker-radio" data-checked={settings.fps === fps}>
|
<label className="vcd-screen-picker-radio" data-checked={settings.fps === fps}>
|
||||||
<Forms.FormTitle>{fps}</Forms.FormTitle>
|
<Text variant="text-sm/bold">{fps}</Text>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="fps"
|
name="fps"
|
||||||
|
@ -138,7 +155,7 @@ function ModalComponent({
|
||||||
}: {
|
}: {
|
||||||
screens: Source[];
|
screens: Source[];
|
||||||
modalProps: any;
|
modalProps: any;
|
||||||
submit: (id: string) => void;
|
submit: (data: StreamPick) => void;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
}) {
|
}) {
|
||||||
const [selected, setSelected] = useState<string>();
|
const [selected, setSelected] = useState<string>();
|
||||||
|
@ -150,8 +167,8 @@ function ModalComponent({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modals.ModalRoot {...modalProps}>
|
<Modals.ModalRoot {...modalProps}>
|
||||||
<Modals.ModalHeader>
|
<Modals.ModalHeader className="vcd-screen-picker-header">
|
||||||
<Forms.FormTitle tag="h2">Screen Picker</Forms.FormTitle>
|
<Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
|
||||||
<Modals.ModalCloseButton onClick={close} />
|
<Modals.ModalCloseButton onClick={close} />
|
||||||
</Modals.ModalHeader>
|
</Modals.ModalHeader>
|
||||||
|
|
||||||
|
@ -167,11 +184,14 @@ function ModalComponent({
|
||||||
)}
|
)}
|
||||||
</Modals.ModalContent>
|
</Modals.ModalContent>
|
||||||
|
|
||||||
<Modals.ModalFooter>
|
<Modals.ModalFooter className="vcd-screen-picker-footer">
|
||||||
<Button
|
<Button
|
||||||
disabled={!selected}
|
disabled={!selected}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
submit(selected!);
|
submit({
|
||||||
|
id: selected!,
|
||||||
|
...settings
|
||||||
|
});
|
||||||
close();
|
close();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -2,7 +2,17 @@
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-screen-picker-grid { display: grid;
|
.vcd-screen-picker-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vcd-screen-picker-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vcd-screen-picker-grid {
|
||||||
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 2em 1em;
|
gap: 2em 1em;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +23,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-screen-picker-selected img {
|
.vcd-screen-picker-selected img {
|
||||||
outline: 2px solid var(--brand-experiment);
|
border: 2px solid var(--brand-experiment);
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-screen-picker-grid label {
|
.vcd-screen-picker-grid label {
|
||||||
|
@ -43,7 +54,7 @@
|
||||||
|
|
||||||
.vcd-screen-picker-preview img {
|
.vcd-screen-picker-preview img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-screen-picker-preview {
|
.vcd-screen-picker-preview {
|
||||||
|
@ -51,8 +62,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
margin-bottom: 1em;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-screen-picker-radio input {
|
.vcd-screen-picker-radio input {
|
||||||
|
|
|
@ -28,9 +28,9 @@ export const enum IpcEvents {
|
||||||
|
|
||||||
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
|
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
|
||||||
|
|
||||||
CAPTURER_GET_SOURCES = "VCD_CAPTURER_GET_SOURCES",
|
CAPTURER_GET_LARGE_THUMBNAIL = "VCD_CAPTURER_GET_LARGE_THUMBNAIL",
|
||||||
|
|
||||||
AUTOSTART_ENABLED = "VCD_AUTOSTART_ENABLED",
|
AUTOSTART_ENABLED = "VCD_AUTOSTART_ENABLED",
|
||||||
ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART",
|
ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART",
|
||||||
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART",
|
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART"
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue