mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(voice): keep saved linux audio apps in the source picker (#3150)
This commit is contained in:
@@ -15,8 +15,10 @@ import {
|
|||||||
type LinuxAudioSourceFilterOptions,
|
type LinuxAudioSourceFilterOptions,
|
||||||
type LinuxAudioSourceItem,
|
type LinuxAudioSourceItem,
|
||||||
linuxAudioSourceItemKey,
|
linuxAudioSourceItemKey,
|
||||||
|
linuxAudioSourcePatternsEqual,
|
||||||
mapLinuxAudioNodeToItems,
|
mapLinuxAudioNodeToItems,
|
||||||
uniqueLinuxAudioSourceItems,
|
uniqueLinuxAudioSourceItems,
|
||||||
|
withSelectedLinuxAudioSources,
|
||||||
} from '@app/features/voice/utils/LinuxAudioSourceRules';
|
} from '@app/features/voice/utils/LinuxAudioSourceRules';
|
||||||
import {
|
import {
|
||||||
formatScreenShareAudioSummary,
|
formatScreenShareAudioSummary,
|
||||||
@@ -78,15 +80,8 @@ const EMPTY_SNAPSHOT: AudioSourceSnapshot = {
|
|||||||
error: null,
|
error: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
function nodesEqual(a: VirtmicNode, b: VirtmicNode): boolean {
|
|
||||||
const keysA = Object.keys(a);
|
|
||||||
const keysB = Object.keys(b);
|
|
||||||
if (keysA.length !== keysB.length) return false;
|
|
||||||
return keysA.every((key) => a[key] === b[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isItemSelected(value: VirtmicNode, sources: Array<VirtmicNode>): boolean {
|
function isItemSelected(value: VirtmicNode, sources: Array<VirtmicNode>): boolean {
|
||||||
return sources.some((source) => nodesEqual(source, value));
|
return sources.some((source) => linuxAudioSourcePatternsEqual(source, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAudioSources(options: LinuxAudioSourceFilterOptions): Promise<AudioSourceSnapshot> {
|
async function fetchAudioSources(options: LinuxAudioSourceFilterOptions): Promise<AudioSourceSnapshot> {
|
||||||
@@ -188,7 +183,7 @@ export const AudioSourcePickerLinuxSubmenu = observer((props: AudioSourcePickerL
|
|||||||
(item: LinuxAudioSourceItem) => {
|
(item: LinuxAudioSourceItem) => {
|
||||||
const isSelected = isItemSelected(item.value, includeSources);
|
const isSelected = isItemSelected(item.value, includeSources);
|
||||||
const nextSources = isSelected
|
const nextSources = isSelected
|
||||||
? includeSources.filter((source) => !nodesEqual(source, item.value))
|
? includeSources.filter((source) => !linuxAudioSourcePatternsEqual(source, item.value))
|
||||||
: [...includeSources, item.value];
|
: [...includeSources, item.value];
|
||||||
VoiceSettingsCommands.update({
|
VoiceSettingsCommands.update({
|
||||||
screenShareAudioSourceMode: nextSources.length > 0 ? 'specific' : 'system',
|
screenShareAudioSourceMode: nextSources.length > 0 ? 'specific' : 'system',
|
||||||
@@ -203,7 +198,7 @@ export const AudioSourcePickerLinuxSubmenu = observer((props: AudioSourcePickerL
|
|||||||
(item: LinuxAudioSourceItem) => {
|
(item: LinuxAudioSourceItem) => {
|
||||||
const isSelected = isItemSelected(item.value, excludeSources);
|
const isSelected = isItemSelected(item.value, excludeSources);
|
||||||
const nextSources = isSelected
|
const nextSources = isSelected
|
||||||
? excludeSources.filter((source) => !nodesEqual(source, item.value))
|
? excludeSources.filter((source) => !linuxAudioSourcePatternsEqual(source, item.value))
|
||||||
: [...excludeSources, item.value];
|
: [...excludeSources, item.value];
|
||||||
VoiceSettingsCommands.update({
|
VoiceSettingsCommands.update({
|
||||||
screenShareAudioExcludeSources: nextSources,
|
screenShareAudioExcludeSources: nextSources,
|
||||||
@@ -230,6 +225,8 @@ export const AudioSourcePickerLinuxSubmenu = observer((props: AudioSourcePickerL
|
|||||||
usesDeviceMicrophone,
|
usesDeviceMicrophone,
|
||||||
});
|
});
|
||||||
const showsWideSourceLists = !offersWindowScope || resolvedScope === 'system';
|
const showsWideSourceLists = !offersWindowScope || resolvedScope === 'system';
|
||||||
|
const includeItems = withSelectedLinuxAudioSources(snapshot.items, includeSources);
|
||||||
|
const excludeItems = withSelectedLinuxAudioSources(snapshot.items, excludeSources);
|
||||||
const wideSourceIsSelected = isDeviceShare ? usesDeviceMicrophone : sourceMode === 'system';
|
const wideSourceIsSelected = isDeviceShare ? usesDeviceMicrophone : sourceMode === 'system';
|
||||||
if (!snapshot.available && !snapshot.loading) {
|
if (!snapshot.available && !snapshot.loading) {
|
||||||
return null;
|
return null;
|
||||||
@@ -269,12 +266,12 @@ export const AudioSourcePickerLinuxSubmenu = observer((props: AudioSourcePickerL
|
|||||||
</MenuItemRadio>
|
</MenuItemRadio>
|
||||||
)}
|
)}
|
||||||
</MenuGroup>
|
</MenuGroup>
|
||||||
{showsWideSourceLists && snapshot.items.length > 0 && (
|
{showsWideSourceLists && includeItems.length > 0 && (
|
||||||
<MenuGroup data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.menu-group--2">
|
<MenuGroup data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.menu-group--2">
|
||||||
<MenuGroupLabel data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.group-label.include-apps">
|
<MenuGroupLabel data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.group-label.include-apps">
|
||||||
{i18n._(INCLUDE_APPS_DESCRIPTOR)}
|
{i18n._(INCLUDE_APPS_DESCRIPTOR)}
|
||||||
</MenuGroupLabel>
|
</MenuGroupLabel>
|
||||||
{snapshot.items.map((item) => (
|
{includeItems.map((item) => (
|
||||||
<CheckboxItem
|
<CheckboxItem
|
||||||
key={linuxAudioSourceItemKey(item)}
|
key={linuxAudioSourceItemKey(item)}
|
||||||
checked={isItemSelected(item.value, includeSources)}
|
checked={isItemSelected(item.value, includeSources)}
|
||||||
@@ -286,12 +283,12 @@ export const AudioSourcePickerLinuxSubmenu = observer((props: AudioSourcePickerL
|
|||||||
))}
|
))}
|
||||||
</MenuGroup>
|
</MenuGroup>
|
||||||
)}
|
)}
|
||||||
{!isDeviceShare && showsWideSourceLists && sourceMode === 'system' && snapshot.items.length > 0 && (
|
{!isDeviceShare && showsWideSourceLists && sourceMode === 'system' && excludeItems.length > 0 && (
|
||||||
<MenuGroup data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.menu-group--3">
|
<MenuGroup data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.menu-group--3">
|
||||||
<MenuGroupLabel data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.group-label.exclude-from-system">
|
<MenuGroupLabel data-flx="voice.audio-source-picker-linux.audio-source-picker-linux-submenu.group-label.exclude-from-system">
|
||||||
{i18n._(EXCLUDE_FROM_SYSTEM_DESCRIPTOR)}
|
{i18n._(EXCLUDE_FROM_SYSTEM_DESCRIPTOR)}
|
||||||
</MenuGroupLabel>
|
</MenuGroupLabel>
|
||||||
{snapshot.items.map((item) => (
|
{excludeItems.map((item) => (
|
||||||
<CheckboxItem
|
<CheckboxItem
|
||||||
key={`exclude-${linuxAudioSourceItemKey(item)}`}
|
key={`exclude-${linuxAudioSourceItemKey(item)}`}
|
||||||
checked={isItemSelected(item.value, excludeSources)}
|
checked={isItemSelected(item.value, excludeSources)}
|
||||||
|
|||||||
@@ -135,6 +135,27 @@ export function mapLinuxAudioNodeToItems(
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function linuxAudioSourcePatternsEqual(a: VirtmicNode, b: VirtmicNode): boolean {
|
||||||
|
const keysA = Object.keys(a);
|
||||||
|
const keysB = Object.keys(b);
|
||||||
|
if (keysA.length !== keysB.length) return false;
|
||||||
|
return keysA.every((key) => a[key] === b[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withSelectedLinuxAudioSources(
|
||||||
|
items: ReadonlyArray<LinuxAudioSourceItem>,
|
||||||
|
selected: ReadonlyArray<VirtmicNode>,
|
||||||
|
): Array<LinuxAudioSourceItem> {
|
||||||
|
const missing = selected.filter((source) => !items.some((item) => linuxAudioSourcePatternsEqual(item.value, source)));
|
||||||
|
return [
|
||||||
|
...items,
|
||||||
|
...missing.map((source) => ({
|
||||||
|
name: getLinuxAudioSourceDisplayName(source) ?? JSON.stringify(source),
|
||||||
|
value: source,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
export function uniqueLinuxAudioSourceItems(items: Array<LinuxAudioSourceItem>): Array<LinuxAudioSourceItem> {
|
export function uniqueLinuxAudioSourceItems(items: Array<LinuxAudioSourceItem>): Array<LinuxAudioSourceItem> {
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const result: Array<LinuxAudioSourceItem> = [];
|
const result: Array<LinuxAudioSourceItem> = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user