1597e7540b
User relays are no longer used until the user explicitly opts in via Settings > Network. Adds a useUserRelays toggle alongside the existing useAppRelays toggle in RelayListManager, defaulting to false. Fresh installs and new accounts will only query app-default relays until the user enables their personal NIP-65 list. The user's relay list (kind 10002) is still synced from Nostr and managed in the UI when logged in — the toggle only controls whether it is included in the effective relay set used by NostrProvider's pool and useNativeNotifications. The setting is persisted to AppConfig and synced cross-device via NIP-78 encrypted settings. getEffectiveRelays now takes both flags and short-circuits accordingly, producing an empty list when both are off (instead of the previous behavior of always returning user relays).
96 lines
3.5 KiB
TypeScript
96 lines
3.5 KiB
TypeScript
import { useEffect, useMemo } from 'react';
|
|
import { Capacitor, registerPlugin } from '@capacitor/core';
|
|
import { LocalNotifications } from '@capacitor/local-notifications';
|
|
|
|
import { useCurrentUser } from './useCurrentUser';
|
|
import { useAppContext } from './useAppContext';
|
|
import { useEncryptedSettings } from './useEncryptedSettings';
|
|
import { useFollowList } from './useFollowActions';
|
|
import { getEffectiveRelays } from '@/lib/appRelays';
|
|
import { getEnabledNotificationKinds } from '@/lib/notificationKinds';
|
|
|
|
/** Interface for the native DittoNotification Capacitor plugin. */
|
|
interface DittoNotificationPlugin {
|
|
configure(options: { userPubkey?: string; relayUrls?: string[]; enabledKinds?: number[]; authors?: string[]; notificationStyle?: string }): Promise<void>;
|
|
}
|
|
|
|
const DittoNotification = registerPlugin<DittoNotificationPlugin>('DittoNotification');
|
|
|
|
/**
|
|
* Manages the native Android notification service via Capacitor.
|
|
*
|
|
* Passes user pubkey + relay URLs + enabled notification kinds + optional
|
|
* authors filter to the DittoNotification plugin so it can poll for events
|
|
* in the background. Respects the NIP-78 notificationsEnabled setting
|
|
* (defaults to on), per-type notification preferences, and the "only from
|
|
* people I follow" setting.
|
|
*
|
|
* Web Push (nostr-push) is handled separately by usePushNotifications +
|
|
* NotificationSettings — this hook is Capacitor-only.
|
|
*/
|
|
export function useNativeNotifications(): void {
|
|
const { user } = useCurrentUser();
|
|
const { config } = useAppContext();
|
|
const { settings } = useEncryptedSettings();
|
|
const { data: followData } = useFollowList();
|
|
|
|
const prefs = settings?.notificationPreferences;
|
|
const notificationsEnabled = settings?.notificationsEnabled ?? true;
|
|
const notificationStyle = settings?.notificationStyle ?? 'push';
|
|
const enabledKinds = useMemo(
|
|
() => getEnabledNotificationKinds(prefs),
|
|
[prefs],
|
|
);
|
|
|
|
// Authors filter: when onlyFollowing is set, restrict to followed pubkeys
|
|
const followedPubkeys = useMemo(
|
|
() => followData?.pubkeys ?? [],
|
|
[followData?.pubkeys],
|
|
);
|
|
const onlyFollowing = prefs?.onlyFollowing === true;
|
|
const authorsFilter = onlyFollowing && followedPubkeys.length > 0
|
|
? followedPubkeys
|
|
: undefined;
|
|
|
|
// Request native notification permission on first mount.
|
|
useEffect(() => {
|
|
if (!Capacitor.isNativePlatform()) return;
|
|
|
|
(async () => {
|
|
try {
|
|
const { display } = await LocalNotifications.checkPermissions();
|
|
if (display === 'prompt' || display === 'prompt-with-rationale') {
|
|
await LocalNotifications.requestPermissions();
|
|
}
|
|
} catch {
|
|
// Permission check failed — ignore
|
|
}
|
|
})();
|
|
}, []);
|
|
|
|
// Configure / deconfigure the native polling service.
|
|
useEffect(() => {
|
|
if (!Capacitor.isNativePlatform()) return;
|
|
|
|
if (!user || !notificationsEnabled) {
|
|
DittoNotification.configure({});
|
|
return;
|
|
}
|
|
|
|
const effectiveRelays = getEffectiveRelays(config.relayMetadata, config.useAppRelays, config.useUserRelays);
|
|
const relayUrls = effectiveRelays.relays
|
|
.filter((r) => r.read)
|
|
.map((r) => r.url);
|
|
|
|
if (relayUrls.length === 0) return;
|
|
|
|
DittoNotification.configure({
|
|
userPubkey: user.pubkey,
|
|
relayUrls,
|
|
enabledKinds,
|
|
notificationStyle,
|
|
...(authorsFilter ? { authors: authorsFilter } : {}),
|
|
});
|
|
}, [user, config.relayMetadata, config.useAppRelays, config.useUserRelays, notificationsEnabled, notificationStyle, enabledKinds, authorsFilter]);
|
|
}
|