feat(desktop): improve new user defaults for presence and notifications (#376)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wes
2026-04-21 07:48:15 -06:00
committed by GitHub
parent f57e5493d5
commit 60b51806dd
5 changed files with 48 additions and 18 deletions

View File

@@ -170,10 +170,21 @@ export function useNotificationSettings(pubkey?: string) {
const [errorMessage, setErrorMessage] = React.useState<string | null>(null);
const [isUpdatingDesktopEnabled, setIsUpdatingDesktopEnabled] =
React.useState(false);
const isNewUserRef = React.useRef(
normalizedPubkey.length > 0 &&
window.localStorage.getItem(
notificationSettingsStorageKey(normalizedPubkey),
) === null,
);
React.useEffect(() => {
setSettings(readStoredNotificationSettings(normalizedPubkey));
setErrorMessage(null);
isNewUserRef.current =
normalizedPubkey.length > 0 &&
window.localStorage.getItem(
notificationSettingsStorageKey(normalizedPubkey),
) === null;
}, [normalizedPubkey]);
React.useEffect(() => {
@@ -191,6 +202,33 @@ export function useNotificationSettings(pubkey?: string) {
void refreshPermission();
}, [normalizedPubkey]);
// Auto-request desktop notification permission for new users
React.useEffect(() => {
if (!normalizedPubkey || !isNewUserRef.current) return;
isNewUserRef.current = false;
let cancelled = false;
void (async () => {
try {
const currentPermission = await getDesktopNotificationPermissionState();
if (cancelled || currentPermission !== "default") return;
const result = await requestDesktopNotificationAccess();
if (cancelled) return;
setPermission(result);
if (result === "granted") {
setSettings((current) => ({ ...current, desktopEnabled: true }));
}
} catch {
// Best-effort auto-request; silently ignore errors
}
})();
return () => {
cancelled = true;
};
}, [normalizedPubkey]);
const setDesktopEnabled = React.useCallback(async (enabled: boolean) => {
if (!enabled) {
setErrorMessage(null);

View File

@@ -232,10 +232,6 @@ export function usePresenceSession(pubkey?: string) {
),
[isDocumentHidden, lastActivityAt, statusClock],
);
const relayStatus =
normalizedPubkey.length > 0
? (presenceQuery.data?.[normalizedPubkey] ?? "offline")
: "offline";
const currentStatus =
normalizedPubkey.length === 0
? "offline"
@@ -245,7 +241,7 @@ export function usePresenceSession(pubkey?: string) {
? "away"
: presencePreference === "auto"
? automaticStatus
: relayStatus;
: automaticStatus;
const updatePresence = React.useCallback(
async (status: PresenceStatus) => {
@@ -283,7 +279,7 @@ export function usePresenceSession(pubkey?: string) {
});
React.useEffect(() => {
if (normalizedPubkey.length === 0 || presencePreference === null) {
if (normalizedPubkey.length === 0) {
return;
}
@@ -293,14 +289,10 @@ export function usePresenceSession(pubkey?: string) {
}
syncPresence(currentStatus);
}, [currentStatus, normalizedPubkey, presencePreference]);
}, [currentStatus, normalizedPubkey]);
React.useEffect(() => {
if (
normalizedPubkey.length === 0 ||
presencePreference === null ||
currentStatus === "offline"
) {
if (normalizedPubkey.length === 0 || currentStatus === "offline") {
return;
}
@@ -311,7 +303,7 @@ export function usePresenceSession(pubkey?: string) {
return () => {
window.clearInterval(intervalId);
};
}, [currentStatus, normalizedPubkey, presencePreference]);
}, [currentStatus, normalizedPubkey]);
return {
currentStatus,

View File

@@ -197,7 +197,7 @@ test("shows presence in sidebar, DM header, and member list", async ({
await expect(page.getByTestId("sidebar-profile-card")).toBeVisible();
await expect(page.getByTestId("self-presence-badge")).toHaveAttribute(
"aria-label",
"Offline",
"Online",
);
await expect(page.getByTestId("channel-presence-alice-tyler")).toBeVisible();

View File

@@ -51,7 +51,7 @@ test("updates presence from the profile menu", async ({ page }) => {
await openProfileMenu(page);
await expect(
page.getByTestId("profile-popover-current-status"),
).toContainText("Offline");
).toContainText("Online");
await page.getByTestId("profile-popover-status-away").click();
await openProfileMenu(page);

View File

@@ -203,15 +203,15 @@ mobile_dir := "mobile"
# Install mobile Flutter dependencies
mobile-install:
cd {{mobile_dir}} && flutter pub get
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter pub get
# Run mobile lint and format checks
mobile-check:
cd {{mobile_dir}} && dart format --output=none --set-exit-if-changed . && flutter analyze
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && dart format --output=none --set-exit-if-changed . && flutter analyze
# Run mobile tests
mobile-test:
cd {{mobile_dir}} && flutter test
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter test
# ─── Database ─────────────────────────────────────────────────────────────────