From 28f12dbe39a4976b7d7cdc1f22e942bcd2cf95d7 Mon Sep 17 00:00:00 2001 From: automated-signal <37887102+automated-signal@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:20:52 -0600 Subject: [PATCH] Hide standard_donate megaphone after getting a badge Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com> --- ts/services/megaphone.preload.ts | 26 +++++++++++++++++++++++--- ts/services/profiles.preload.ts | 6 ++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/ts/services/megaphone.preload.ts b/ts/services/megaphone.preload.ts index 23ace4d490..e584aa8105 100644 --- a/ts/services/megaphone.preload.ts +++ b/ts/services/megaphone.preload.ts @@ -54,6 +54,7 @@ export async function runMegaphoneCheck(): Promise { } const megaphones = await DataReader.getAllMegaphones(); + const shownIds: Set = new Set(); log.info( `runMegaphoneCheck: Checking ${megaphones.length} locally saved megaphones` @@ -61,7 +62,10 @@ export async function runMegaphoneCheck(): Promise { for (const megaphone of megaphones) { try { // eslint-disable-next-line no-await-in-loop - await processMegaphone(megaphone); + const result = await processMegaphone(megaphone); + if (result === 'shown') { + shownIds.add(megaphone.id); + } } catch (error) { log.error( `runMegaphoneCheck: Error processing ${megaphone.id}`, @@ -69,6 +73,17 @@ export async function runMegaphoneCheck(): Promise { ); } } + + // Hide megaphones which are visible but should no longer be shown + // Example: standard_donate, then you donated on primary and got a badge + const { visibleMegaphones } = window.reduxStore.getState().megaphones; + for (const visibleMegaphone of visibleMegaphones) { + const { id } = visibleMegaphone; + if (!shownIds.has(id)) { + log.info(`runMegaphoneCheck: Hiding ${id}`); + window.reduxActions.megaphones.removeVisibleMegaphone(id); + } + } } finally { clearTimeoutIfNecessary(nextCheckTimeout); nextCheckTimeout = safeSetTimeout(() => { @@ -131,13 +146,15 @@ export async function deleteMegaphoneAndRemoveFromRedux( // Private -async function processMegaphone(megaphone: RemoteMegaphoneType): Promise { +async function processMegaphone( + megaphone: RemoteMegaphoneType +): Promise<'shown' | 'not-shown'> { const { id } = megaphone; if (isMegaphoneDeletable(megaphone)) { log.info(`processMegaphone: Deleting ${id}`); await deleteMegaphoneAndRemoveFromRedux(id); - return; + return 'not-shown'; } if (isMegaphoneShowable(megaphone)) { @@ -153,7 +170,10 @@ async function processMegaphone(megaphone: RemoteMegaphoneType): Promise { log.info(`processMegaphone: Showing ${id}`); window.reduxActions.megaphones.addVisibleMegaphone(megaphone); + return 'shown'; } + + return 'not-shown'; } export function isMegaphoneDeletable(megaphone: RemoteMegaphoneType): boolean { diff --git a/ts/services/profiles.preload.ts b/ts/services/profiles.preload.ts index aaee8b9aba..5d28ca0795 100644 --- a/ts/services/profiles.preload.ts +++ b/ts/services/profiles.preload.ts @@ -56,6 +56,7 @@ import { import { ProfileDecryptError } from '../types/errors.std.js'; import { signalProtocolStore } from '../SignalProtocolStore.preload.js'; import { itemStorage } from '../textsecure/Storage.preload.js'; +import { runMegaphoneCheck } from './megaphone.preload.js'; const log = createLogger('profiles'); @@ -765,6 +766,11 @@ async function doGetProfile( : {}), })), }); + + // Refresh visible megaphones, since badges may affect conditionals + if (isMe(c.attributes)) { + drop(runMegaphoneCheck()); + } } else { c.set({ badges: undefined }); }