pengx17
2025-04-08 10:18:08 +00:00
parent 780c35eabe
commit 93d8e22b07
8 changed files with 149 additions and 59 deletions

View File

@@ -473,7 +473,7 @@ function setupMediaListeners() {
// will be called when the app is ready or when the user has enabled the recording feature in settings
export function setupRecordingFeature() {
if (!MeetingsSettingsState.value.enabled || !checkRecordingAvailable()) {
if (!MeetingsSettingsState.value.enabled || !checkCanRecordMeeting()) {
return;
}
@@ -767,9 +767,24 @@ export const checkRecordingAvailable = () => {
return (version.major === 14 && version.minor >= 2) || version.major > 14;
};
export const checkScreenRecordingPermission = () => {
export const checkMeetingPermissions = () => {
if (!isMacOS()) {
return false;
return undefined;
}
return systemPreferences.getMediaAccessStatus('screen') === 'granted';
const mediaTypes = ['screen', 'microphone'] as const;
return Object.fromEntries(
mediaTypes.map(mediaType => [
mediaType,
systemPreferences.getMediaAccessStatus(mediaType) === 'granted',
])
) as Record<(typeof mediaTypes)[number], boolean>;
};
export const checkCanRecordMeeting = () => {
const features = checkMeetingPermissions();
return (
checkRecordingAvailable() &&
features &&
Object.values(features).every(feature => feature)
);
};

View File

@@ -9,8 +9,8 @@ import { shell } from 'electron';
import { isMacOS } from '../../shared/utils';
import type { NamespaceHandlers } from '../type';
import {
checkMeetingPermissions,
checkRecordingAvailable,
checkScreenRecordingPermission,
disableRecordingFeature,
getRawAudioBuffers,
getRecording,
@@ -73,13 +73,17 @@ export const recordingHandlers = {
disableRecordingFeature: async () => {
return disableRecordingFeature();
},
checkScreenRecordingPermission: async () => {
return checkScreenRecordingPermission();
checkMeetingPermissions: async () => {
return checkMeetingPermissions();
},
showScreenRecordingPermissionSetting: async () => {
showRecordingPermissionSetting: async (_, type: 'screen' | 'microphone') => {
const urlMap = {
screen: 'Privacy_ScreenCapture',
microphone: 'Privacy_Microphone',
};
if (isMacOS()) {
return shell.openExternal(
'x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture'
`x-apple.systempreferences:com.apple.preference.security?${urlMap[type]}`
);
}
// this only available on MacOS

View File

@@ -15,8 +15,8 @@ import { beforeAppQuit } from '../cleanup';
import { logger } from '../logger';
import {
appGroups$,
checkCanRecordMeeting,
checkRecordingAvailable,
checkScreenRecordingPermission,
MeetingsSettingsState,
recordingStatus$,
startRecording,
@@ -89,7 +89,7 @@ class TrayState implements Disposable {
// tray's icon
icon: NativeImage = nativeImage
.createFromPath(icons.tray)
.resize({ width: 16, height: 16 });
.resize({ width: 18, height: 18 });
// tray's tooltip
tooltip: string = 'AFFiNE';
@@ -142,10 +142,17 @@ class TrayState implements Disposable {
const getConfig = () => {
const items: TrayMenuConfig = [];
if (
checkScreenRecordingPermission() &&
MeetingsSettingsState.value.enabled
) {
if (!MeetingsSettingsState.value.enabled) {
items.push({
label: 'Meetings are disabled',
disabled: true,
});
} else if (!checkCanRecordMeeting()) {
items.push({
label: 'Required permissions not granted',
disabled: true,
});
} else {
const appGroups = appGroups$.value;
const runningAppGroups = appGroups.filter(
appGroup => appGroup.isRunning