fix(desktop): restore notification sounds (#2582)

Restore desktop notification sounds by default, add a persisted Play sound setting, and group notification permission and testing in a dedicated Notifications section.
This commit is contained in:
Glen Stampoultzis
2026-08-08 22:28:37 +02:00
committed by GitHub
parent b19db9537c
commit b9b3a24d58
24 changed files with 451 additions and 123 deletions
@@ -1,7 +1,7 @@
import { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { View, Text } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { View } from "react-native";
import { withUnistyles } from "react-native-unistyles";
import { RotateCw } from "lucide-react-native";
import { Button } from "@/components/ui/button";
import { DesktopPermissionRow } from "@/desktop/components/desktop-permission-row";
@@ -9,49 +9,33 @@ import { useDesktopPermissions } from "@/desktop/permissions/use-desktop-permiss
import { settingsStyles } from "@/styles/settings";
import { SettingsSection } from "@/screens/settings/settings-section";
const ThemedRotateCw = withUnistyles(RotateCw, (theme) => ({
size: theme.iconSize.md,
color: theme.colors.foregroundMuted,
}));
export function DesktopPermissionsSection() {
const { t } = useTranslation();
const { theme } = useUnistyles();
const {
isDesktopApp,
snapshot,
isRefreshing,
requestingPermission,
isSendingTestNotification,
testNotificationError,
refreshPermissions,
requestPermission,
sendTestNotification,
} = useDesktopPermissions();
const errorTextStyle = useMemo(
() => [styles.errorText, { color: theme.colors.destructive }],
[theme.colors.destructive],
);
const handleRefreshPress = useCallback(() => {
void refreshPermissions();
}, [refreshPermissions]);
const handleRequestNotifications = useCallback(() => {
void requestPermission("notifications");
}, [requestPermission]);
const handleRequestMicrophone = useCallback(() => {
void requestPermission("microphone");
}, [requestPermission]);
const handleSendTestNotification = useCallback(() => {
void sendTestNotification();
}, [sendTestNotification]);
const isBusy = isRefreshing || requestingPermission !== null;
const notificationsGranted = snapshot?.notifications.state === "granted";
const refreshIcon = useMemo(
() => <RotateCw size={theme.iconSize.md} color={theme.colors.foregroundMuted} />,
[theme.iconSize.md, theme.colors.foregroundMuted],
);
const refreshIcon = useMemo(() => <ThemedRotateCw />, []);
const refreshButton = useMemo(
() => (
@@ -74,7 +58,6 @@ export function DesktopPermissionsSection() {
granted: t("settings.permissions.actions.granted"),
request: t("settings.permissions.actions.request"),
requesting: t("settings.permissions.actions.requesting"),
busyExtraAction: (label: string) => t("settings.permissions.actions.busySuffix", { label }),
}),
[t],
);
@@ -86,21 +69,8 @@ export function DesktopPermissionsSection() {
return (
<SettingsSection title={t("settings.permissions.title")} trailing={refreshButton}>
<View style={settingsStyles.card}>
<DesktopPermissionRow
title={t("settings.permissions.notifications")}
status={snapshot?.notifications ?? null}
isRequesting={requestingPermission === "notifications"}
onRequest={handleRequestNotifications}
labels={permissionLabels}
extraActionLabel={t("settings.permissions.test")}
isExtraActionBusy={isSendingTestNotification}
isExtraActionDisabled={!notificationsGranted || isBusy}
onExtraAction={handleSendTestNotification}
/>
{testNotificationError ? <Text style={errorTextStyle}>{testNotificationError}</Text> : null}
<DesktopPermissionRow
title={t("settings.permissions.microphone")}
showBorder
status={snapshot?.microphone ?? null}
isRequesting={requestingPermission === "microphone"}
onRequest={handleRequestMicrophone}
@@ -110,11 +80,3 @@ export function DesktopPermissionsSection() {
</SettingsSection>
);
}
const styles = StyleSheet.create((theme) => ({
errorText: {
fontSize: theme.fontSize.xs,
paddingHorizontal: theme.spacing[4],
paddingBottom: theme.spacing[2],
},
}));