From 07abc8516fcf2ec54fc28fbad99e951cbce272a1 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Tue, 20 Jan 2026 02:04:10 +0000
Subject: [PATCH] Refactor DM UI: Move privacy settings, unify Zaps interface,
and adjust layout
---
js/ui/dm/AppShell.js | 60 +++++++++--
js/ui/dm/Composer.js | 181 --------------------------------
js/ui/dm/DMPrivacySettings.js | 72 +++++++++++++
js/ui/dm/MessageBubble.js | 4 +-
js/ui/dm/MessageThread.js | 131 ++++++++++++++++++++++-
js/ui/profileModalController.js | 30 +++---
6 files changed, 266 insertions(+), 212 deletions(-)
create mode 100644 js/ui/dm/DMPrivacySettings.js
diff --git a/js/ui/dm/AppShell.js b/js/ui/dm/AppShell.js
index 1ac096a1..1e32a5e6 100644
--- a/js/ui/dm/AppShell.js
+++ b/js/ui/dm/AppShell.js
@@ -2,6 +2,7 @@ import { Composer } from "./Composer.js";
import { ConversationList } from "./ConversationList.js";
import { MessageThread } from "./MessageThread.js";
import { NotificationCenter } from "./NotificationCenter.js";
+import { DMPrivacySettings } from "./DMPrivacySettings.js";
import { aggregateZapTotals } from "./zapHelpers.js";
function createElement(doc, tag, className, text) {
@@ -121,6 +122,7 @@ export class AppShell {
threadErrorType = "",
composerState = "idle",
privacyMode = "nip04",
+ dmPrivacySettings = { readReceiptsEnabled: false, typingIndicatorsEnabled: false },
notifications = [],
signingAdapter = null,
zapConfig = null,
@@ -129,6 +131,8 @@ export class AppShell {
onSendZap,
onMarkConversationRead,
onMarkAllRead,
+ onToggleReadReceipts,
+ onToggleTypingIndicators,
} = {}) {
if (!doc) {
throw new Error("AppShell requires a document reference.");
@@ -153,13 +157,47 @@ export class AppShell {
);
const sidebar = createElement(doc, "aside", "dm-app-shell__sidebar");
+ const sidebarHeader = createElement(doc, "div", "dm-app-shell__sidebar-header flex items-center justify-between p-4");
const sidebarTitle = createElement(
doc,
"h1",
- "dm-app-shell__title",
+ "dm-app-shell__title text-lg font-bold",
"Direct Messages",
);
- sidebar.appendChild(sidebarTitle);
+ sidebarHeader.appendChild(sidebarTitle);
+
+ const settingsBtn = createElement(doc, "button", "btn-ghost btn-icon");
+ settingsBtn.innerHTML = ``;
+ settingsBtn.ariaLabel = "Direct message settings";
+ settingsBtn.addEventListener("click", (e) => {
+ e.stopPropagation();
+ let popover = sidebar.querySelector(".dm-settings-popover");
+ if (popover) {
+ popover.remove();
+ return;
+ }
+ popover = DMPrivacySettings({
+ document: doc,
+ readReceiptsEnabled: dmPrivacySettings.readReceiptsEnabled,
+ typingIndicatorsEnabled: dmPrivacySettings.typingIndicatorsEnabled,
+ onToggleReadReceipts,
+ onToggleTypingIndicators,
+ });
+ popover.classList.add("dm-settings-popover", "absolute", "z-50", "right-4", "top-12", "bg-surface", "border", "border-border", "rounded-xl");
+ sidebarHeader.style.position = "relative";
+ sidebarHeader.appendChild(popover);
+
+ const closeHandler = (event) => {
+ if (!popover.contains(event.target) && event.target !== settingsBtn && !settingsBtn.contains(event.target)) {
+ popover.remove();
+ doc.removeEventListener("click", closeHandler);
+ }
+ };
+ doc.addEventListener("click", closeHandler);
+ });
+ sidebarHeader.appendChild(settingsBtn);
+ sidebar.appendChild(sidebarHeader);
+
sidebar.appendChild(
ConversationList({
document: doc,
@@ -172,12 +210,7 @@ export class AppShell {
);
const main = createElement(doc, "main", "dm-app-shell__main");
- main.appendChild(
- NotificationCenter({
- document: doc,
- notices: notifications,
- }),
- );
+
main.appendChild(
MessageThread({
document: doc,
@@ -191,6 +224,8 @@ export class AppShell {
totalsByConversation.get(activeConversation.id) || 0,
profileZapTotalSats: totalsByProfile.get(activeConversation.pubkey) || 0,
onMarkRead: onMarkConversationRead,
+ onSendZap,
+ zapConfig,
}),
);
main.appendChild(
@@ -202,7 +237,14 @@ export class AppShell {
zapRecipient: activeConversation,
zapConfig,
onSend: onSendMessage,
- onSendZap,
+ // Zap button moved to MessageThread, so onSendZap here might be redundant if triggered from thread
+ // But Composer still handles text message sending.
+ }),
+ );
+ main.appendChild(
+ NotificationCenter({
+ document: doc,
+ notices: notifications,
}),
);
diff --git a/js/ui/dm/Composer.js b/js/ui/dm/Composer.js
index 184630f2..f9f2a1d5 100644
--- a/js/ui/dm/Composer.js
+++ b/js/ui/dm/Composer.js
@@ -1,6 +1,3 @@
-import { createAndPublishZapRequest, resolveZapRecipient } from "../../payments/zapRequests.js";
-import { devLogger, userLogger } from "../../utils/logger.js";
-
function createElement(doc, tag, className, text) {
const element = doc.createElement(tag);
if (className) {
@@ -21,7 +18,6 @@ export function Composer({
zapRecipient = null,
zapConfig = null,
onSend,
- onSendZap,
} = {}) {
if (!doc) {
throw new Error("Composer requires a document reference.");
@@ -87,15 +83,7 @@ export function Composer({
privacyToggle.setAttribute("aria-pressed", "false");
privacyToggle.setAttribute("aria-label", "Toggle privacy mode");
- const zapToggle = createElement(doc, "button", "dm-composer__menu-item", "Zap");
- zapToggle.type = "button";
- zapToggle.setAttribute("role", "menuitem");
- zapToggle.setAttribute("aria-expanded", "false");
- zapToggle.setAttribute("aria-label", "Open zap composer");
- zapToggle.setAttribute("aria-pressed", "false");
-
moreMenu.appendChild(privacyToggle);
- moreMenu.appendChild(zapToggle);
tools.appendChild(attachButton);
tools.appendChild(moreButton);
@@ -126,64 +114,8 @@ export function Composer({
status.textContent = "Sending…";
}
- const zapPanel = createElement(doc, "div", "dm-composer__zap-panel");
- zapPanel.id = "dm-composer-zap-panel";
- zapPanel.hidden = true;
- zapToggle.setAttribute("aria-controls", zapPanel.id);
- const zapRecipientLabel = createElement(
- doc,
- "span",
- "dm-composer__zap-recipient",
- zapRecipient?.name
- ? `Zap ${zapRecipient.name}`
- : "Zap this contact",
- );
- zapPanel.appendChild(zapRecipientLabel);
-
- const zapAddress = createElement(
- doc,
- "span",
- "dm-composer__zap-address",
- zapRecipient?.lightningAddress || "Lightning address required.",
- );
- zapPanel.appendChild(zapAddress);
-
- const zapAmountLabel = createElement(doc, "label", "dm-composer__zap-label", "Amount (sats)");
- zapAmountLabel.setAttribute("for", "dm-zap-amount-input");
- const zapAmountInput = createElement(doc, "input", "dm-composer__zap-input");
- zapAmountInput.type = "number";
- zapAmountInput.min = "1";
- zapAmountInput.step = "1";
- zapAmountInput.inputMode = "numeric";
- zapAmountInput.id = "dm-zap-amount-input";
- zapAmountInput.placeholder = "100";
- zapAmountInput.setAttribute("aria-label", "Zap amount in sats");
- zapPanel.appendChild(zapAmountLabel);
- zapPanel.appendChild(zapAmountInput);
-
- const zapNoteLabel = createElement(doc, "label", "dm-composer__zap-label", "Zap note");
- zapNoteLabel.setAttribute("for", "dm-zap-note-input");
- const zapNoteInput = createElement(doc, "input", "dm-composer__zap-input");
- zapNoteInput.type = "text";
- zapNoteInput.id = "dm-zap-note-input";
- zapNoteInput.placeholder = "Optional note for this zap";
- zapNoteInput.setAttribute("aria-label", "Zap note");
- zapPanel.appendChild(zapNoteLabel);
- zapPanel.appendChild(zapNoteInput);
-
- const zapActions = createElement(doc, "div", "dm-composer__zap-actions");
- const zapSendButton = createElement(doc, "button", "dm-composer__zap-send", "Send zap");
- zapSendButton.type = "button";
- zapSendButton.setAttribute("aria-label", "Send zap request");
- zapActions.appendChild(zapSendButton);
- zapPanel.appendChild(zapActions);
-
- const zapStatus = createElement(doc, "div", "dm-composer__zap-status");
- zapPanel.appendChild(zapStatus);
-
form.appendChild(label);
form.appendChild(textarea);
- form.appendChild(zapPanel);
form.appendChild(actions);
form.appendChild(status);
@@ -213,48 +145,6 @@ export function Composer({
onSend(textarea.value, payload);
};
- let zapOpen = false;
- let resolvedRecipient = null;
-
- const setZapStatus = (message, variant = "info") => {
- zapStatus.textContent = message || "";
- zapStatus.dataset.state = variant;
- };
-
- const resolveRecipient = async () => {
- if (!zapRecipient?.lightningAddress) {
- setZapStatus("Add a Lightning address to enable zaps.", "error");
- return null;
- }
- setZapStatus("Resolving LNURL…", "loading");
- try {
- const resolver =
- typeof zapConfig?.resolveRecipient === "function"
- ? zapConfig.resolveRecipient
- : resolveZapRecipient;
- resolvedRecipient = await resolver(zapRecipient.lightningAddress, {
- fetcher: zapConfig?.fetcher,
- });
- if (
- !resolvedRecipient?.metadata?.allowsNostr &&
- !resolvedRecipient?.metadata?.nostrPubkey
- ) {
- setZapStatus("Recipient LNURL does not support Nostr zaps.", "error");
- resolvedRecipient = null;
- return null;
- }
- setZapStatus("LNURL ready for zaps.", "success");
- return resolvedRecipient;
- } catch (error) {
- devLogger.warn("[dm] Failed to resolve LNURL for zap recipient.", error);
- setZapStatus(
- error instanceof Error ? error.message : "Failed to resolve LNURL.",
- "error",
- );
- return null;
- }
- };
-
form.addEventListener("submit", (event) => {
event.preventDefault();
void handleSubmit();
@@ -281,77 +171,6 @@ export function Composer({
updatePrivacyLabel();
});
- zapToggle.addEventListener("click", () => {
- zapOpen = !zapOpen;
- zapPanel.hidden = !zapOpen;
- zapToggle.setAttribute("aria-expanded", zapOpen ? "true" : "false");
- zapToggle.setAttribute("aria-pressed", zapOpen ? "true" : "false");
- if (zapOpen) {
- void resolveRecipient();
- } else {
- setZapStatus("");
- }
- });
-
- zapSendButton.addEventListener("click", async () => {
- const amount = Number(zapAmountInput.value);
- if (!Number.isFinite(amount) || amount <= 0) {
- setZapStatus("Enter a zap amount greater than zero.", "error");
- return;
- }
-
- const resolved = resolvedRecipient || (await resolveRecipient());
- if (!resolved) {
- return;
- }
-
- const comment = zapNoteInput.value.trim();
- const payload = {
- amountSats: Math.round(amount),
- comment,
- recipient: zapRecipient,
- resolved,
- };
-
- if (typeof onSendZap === "function") {
- try {
- await onSendZap(payload);
- setZapStatus("Zap request sent. Awaiting receipt…", "success");
- } catch (error) {
- userLogger.error("[dm] Zap request failed.", error);
- setZapStatus(
- error instanceof Error ? error.message : "Zap request failed.",
- "error",
- );
- }
- return;
- }
-
- if (zapConfig?.signer) {
- try {
- await createAndPublishZapRequest({
- address: zapRecipient?.lightningAddress,
- recipientPubkey: zapRecipient?.pubkey,
- relays: zapRecipient?.relayHints || zapConfig?.relays,
- amountSats: Math.round(amount),
- comment,
- signer: zapConfig.signer,
- pool: zapConfig.pool,
- fetcher: zapConfig.fetcher,
- });
- setZapStatus("Zap request published. Awaiting receipt…", "success");
- } catch (error) {
- userLogger.error("[dm] Zap publish failed.", error);
- setZapStatus(
- error instanceof Error ? error.message : "Zap request failed.",
- "error",
- );
- }
- } else {
- setZapStatus("Connect a Nostr signer to send zap requests.", "error");
- }
- });
-
textarea.addEventListener("keydown", (event) => {
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
diff --git a/js/ui/dm/DMPrivacySettings.js b/js/ui/dm/DMPrivacySettings.js
new file mode 100644
index 00000000..5a839fe5
--- /dev/null
+++ b/js/ui/dm/DMPrivacySettings.js
@@ -0,0 +1,72 @@
+export function DMPrivacySettings({
+ document: doc,
+ readReceiptsEnabled = false,
+ typingIndicatorsEnabled = false,
+ onToggleReadReceipts,
+ onToggleTypingIndicators,
+} = {}) {
+ if (!doc) {
+ throw new Error("DMPrivacySettings requires a document reference.");
+ }
+
+ const root = doc.createElement("div");
+ root.className = "dm-privacy-settings card p-4 space-y-4 shadow-lg";
+
+ const title = doc.createElement("h4");
+ title.className = "text-sm font-semibold text-text";
+ title.textContent = "Direct message privacy";
+ root.appendChild(title);
+
+ const desc = doc.createElement("p");
+ desc.className = "text-xs text-muted mb-4";
+ desc.textContent = "Control read receipts and typing indicators for direct messages.";
+ root.appendChild(desc);
+
+ // Read Receipts Toggle
+ const readReceiptsRow = doc.createElement("div");
+ readReceiptsRow.className = "flex items-center justify-between";
+
+ const readReceiptsLabel = doc.createElement("label");
+ readReceiptsLabel.className = "text-sm text-text cursor-pointer";
+ readReceiptsLabel.textContent = "Read receipts";
+ readReceiptsLabel.setAttribute("for", "dm-read-receipts-toggle");
+ readReceiptsRow.appendChild(readReceiptsLabel);
+
+ const readReceiptsToggle = doc.createElement("input");
+ readReceiptsToggle.type = "checkbox";
+ readReceiptsToggle.id = "dm-read-receipts-toggle";
+ readReceiptsToggle.className = "toggle toggle-sm toggle-accent";
+ readReceiptsToggle.checked = readReceiptsEnabled;
+ readReceiptsToggle.addEventListener("change", (e) => {
+ if (typeof onToggleReadReceipts === "function") {
+ onToggleReadReceipts(e.target.checked);
+ }
+ });
+ readReceiptsRow.appendChild(readReceiptsToggle);
+ root.appendChild(readReceiptsRow);
+
+ // Typing Indicators Toggle
+ const typingIndicatorsRow = doc.createElement("div");
+ typingIndicatorsRow.className = "flex items-center justify-between";
+
+ const typingIndicatorsLabel = doc.createElement("label");
+ typingIndicatorsLabel.className = "text-sm text-text cursor-pointer";
+ typingIndicatorsLabel.textContent = "Typing indicators";
+ typingIndicatorsLabel.setAttribute("for", "dm-typing-indicators-toggle");
+ typingIndicatorsRow.appendChild(typingIndicatorsLabel);
+
+ const typingIndicatorsToggle = doc.createElement("input");
+ typingIndicatorsToggle.type = "checkbox";
+ typingIndicatorsToggle.id = "dm-typing-indicators-toggle";
+ typingIndicatorsToggle.className = "toggle toggle-sm toggle-accent";
+ typingIndicatorsToggle.checked = typingIndicatorsEnabled;
+ typingIndicatorsToggle.addEventListener("change", (e) => {
+ if (typeof onToggleTypingIndicators === "function") {
+ onToggleTypingIndicators(e.target.checked);
+ }
+ });
+ typingIndicatorsRow.appendChild(typingIndicatorsToggle);
+ root.appendChild(typingIndicatorsRow);
+
+ return root;
+}
diff --git a/js/ui/dm/MessageBubble.js b/js/ui/dm/MessageBubble.js
index eea45877..061a7b29 100644
--- a/js/ui/dm/MessageBubble.js
+++ b/js/ui/dm/MessageBubble.js
@@ -33,7 +33,9 @@ export function MessageBubble({
const meta = createElement(doc, "div", "dm-message-bubble__meta");
if (timestamp) {
- meta.appendChild(createElement(doc, "span", "dm-message-bubble__time", timestamp));
+ // Added 'text-muted' class for theme-respecting color (usually handles light/dark text)
+ const timeSpan = createElement(doc, "span", "dm-message-bubble__time text-muted", timestamp);
+ meta.appendChild(timeSpan);
}
if (variant === "outgoing") {
diff --git a/js/ui/dm/MessageThread.js b/js/ui/dm/MessageThread.js
index 554d5aa9..3ced8116 100644
--- a/js/ui/dm/MessageThread.js
+++ b/js/ui/dm/MessageThread.js
@@ -2,6 +2,8 @@ import { DayDivider } from "./DayDivider.js";
import { MessageBubble } from "./MessageBubble.js";
import { ZapReceiptList } from "./ZapReceiptList.js";
import { formatZapAmount } from "./zapHelpers.js";
+import { createAndPublishZapRequest, resolveZapRecipient } from "../../payments/zapRequests.js";
+import { userLogger, devLogger } from "../../utils/logger.js";
function createElement(doc, tag, className, text) {
const element = doc.createElement(tag);
@@ -25,6 +27,8 @@ export function MessageThread({
conversationZapTotalSats = 0,
profileZapTotalSats = 0,
onMarkRead,
+ onSendZap,
+ zapConfig = null,
} = {}) {
if (!doc) {
throw new Error("MessageThread requires a document reference.");
@@ -84,6 +88,21 @@ export function MessageThread({
);
header.appendChild(zapSummary);
+ // Zap Button
+ const zapBtn = createElement(doc, "button", "btn-ghost btn-icon");
+ zapBtn.innerHTML = ``;
+ zapBtn.ariaLabel = "Zap";
+ zapBtn.addEventListener("click", () => {
+ const existingInterface = root.querySelector(".dm-zap-interface");
+ if (existingInterface) {
+ existingInterface.remove();
+ return;
+ }
+ const zapInterface = createZapInterface(doc, { contact, zapReceipts, onSendZap, zapConfig });
+ root.appendChild(zapInterface);
+ });
+ header.appendChild(zapBtn);
+
if (typeof onMarkRead === "function") {
const actions = createElement(doc, "div", "ml-auto flex items-center gap-2");
const markReadButton = createElement(doc, "button", "btn-ghost", "Mark read");
@@ -146,14 +165,118 @@ export function MessageThread({
});
}
- root.appendChild(timeline);
+ // Scroll to bottom
+ if (messages.length > 0) {
+ setTimeout(() => {
+ timeline.scrollTop = timeline.scrollHeight;
+ }, 0);
+ }
- root.appendChild(
+ root.appendChild(timeline);
+ return root;
+}
+
+function createZapInterface(doc, { contact, zapReceipts, onSendZap, zapConfig }) {
+ const container = createElement(doc, "div", "dm-zap-interface card p-4 absolute bottom-16 right-4 z-20 w-80 shadow-xl border border-border bg-surface");
+
+ const closeBtn = createElement(doc, "button", "absolute top-2 right-2 btn-ghost btn-xs", "✕");
+ closeBtn.addEventListener("click", () => container.remove());
+ container.appendChild(closeBtn);
+
+ const title = createElement(doc, "h4", "text-sm font-bold mb-2", "Send Zap");
+ container.appendChild(title);
+
+ // Zap Form
+ const form = createElement(doc, "form", "space-y-2 mb-4");
+ const amountInput = createElement(doc, "input", "input input-sm w-full");
+ amountInput.type = "number";
+ amountInput.placeholder = "Amount (sats)";
+ amountInput.min = "1";
+
+ const noteInput = createElement(doc, "input", "input input-sm w-full");
+ noteInput.type = "text";
+ noteInput.placeholder = "Comment (optional)";
+
+ const sendBtn = createElement(doc, "button", "btn btn-sm btn-primary w-full", "Zap ⚡");
+ const statusDiv = createElement(doc, "div", "text-xs text-center mt-1");
+
+ sendBtn.addEventListener("click", async (e) => {
+ e.preventDefault();
+ const amount = parseInt(amountInput.value);
+ const comment = noteInput.value;
+ if (!amount || amount <= 0) {
+ statusDiv.textContent = "Invalid amount";
+ statusDiv.className = "text-error text-xs text-center mt-1";
+ return;
+ }
+
+ statusDiv.textContent = "Sending...";
+ statusDiv.className = "text-muted text-xs text-center mt-1";
+ sendBtn.disabled = true;
+
+ try {
+ if (typeof onSendZap === "function") {
+ // Use provided callback if available (e.g. from controller)
+ if (!contact.lightningAddress) {
+ throw new Error("No lightning address for this contact");
+ }
+
+ const resolver = zapConfig?.resolveRecipient || resolveZapRecipient;
+ const resolved = await resolver(contact.lightningAddress, { fetcher: zapConfig?.fetcher });
+ if (!resolved) throw new Error("Could not resolve lightning address");
+
+ const payload = {
+ amountSats: amount,
+ comment,
+ recipient: contact,
+ resolved
+ };
+ await onSendZap(payload);
+ statusDiv.textContent = "Zap sent!";
+ statusDiv.className = "text-success text-xs text-center mt-1";
+ amountInput.value = "";
+ noteInput.value = "";
+ } else if (zapConfig?.signer) {
+ await createAndPublishZapRequest({
+ address: contact.lightningAddress,
+ recipientPubkey: contact.pubkey,
+ relays: contact.relayHints || zapConfig?.relays,
+ amountSats: amount,
+ comment,
+ signer: zapConfig.signer,
+ pool: zapConfig.pool,
+ fetcher: zapConfig.fetcher,
+ });
+ statusDiv.textContent = "Zap sent!";
+ statusDiv.className = "text-success text-xs text-center mt-1";
+ amountInput.value = "";
+ noteInput.value = "";
+ } else {
+ throw new Error("No signer available");
+ }
+ } catch (err) {
+ console.error(err);
+ statusDiv.textContent = "Failed to send zap";
+ statusDiv.className = "text-error text-xs text-center mt-1";
+ } finally {
+ sendBtn.disabled = false;
+ }
+ });
+
+ form.appendChild(amountInput);
+ form.appendChild(noteInput);
+ form.appendChild(sendBtn);
+ form.appendChild(statusDiv);
+ container.appendChild(form);
+
+ // Receipts List
+ container.appendChild(
ZapReceiptList({
document: doc,
receipts: zapReceipts,
- emptyLabel: "No zap receipts published yet.",
+ emptyLabel: "No recent zaps.",
}),
);
- return root;
+
+ return container;
}
diff --git a/js/ui/profileModalController.js b/js/ui/profileModalController.js
index e5a78276..f2ea097d 100644
--- a/js/ui/profileModalController.js
+++ b/js/ui/profileModalController.js
@@ -4421,6 +4421,8 @@ export class ProfileModalController {
container.innerHTML = "";
try {
+ const dmPrivacySettings = this.getDmPrivacySettingsSnapshot();
+
this.dmAppShell = new AppShell({
document,
conversations,
@@ -4429,8 +4431,12 @@ export class ProfileModalController {
messages: timeline,
threadState,
privacyMode,
+ dmPrivacySettings,
composerState: this.dmComposerState || "idle",
notifications: [],
+ zapConfig: {
+ signer: this.services.nostrClient,
+ },
onSelectConversation: (conversation) => {
void this.handleDmConversationSelect(conversation);
},
@@ -4443,6 +4449,12 @@ export class ProfileModalController {
onMarkAllRead: () => {
void this.handleDmMarkAllConversationsRead();
},
+ onToggleReadReceipts: (enabled) => {
+ this.handleReadReceiptsToggle(enabled);
+ },
+ onToggleTypingIndicators: (enabled) => {
+ this.handleTypingIndicatorsToggle(enabled);
+ },
});
} catch (error) {
this.dmAppShell = null;
@@ -5160,23 +5172,7 @@ export class ProfileModalController {
});
}
- if (this.profileMessagesReadReceiptsToggle instanceof HTMLElement) {
- this.profileMessagesReadReceiptsToggle.addEventListener("change", (event) => {
- const toggle = event.currentTarget;
- if (toggle instanceof HTMLInputElement) {
- this.handleReadReceiptsToggle(toggle.checked);
- }
- });
- }
-
- if (this.profileMessagesTypingToggle instanceof HTMLElement) {
- this.profileMessagesTypingToggle.addEventListener("change", (event) => {
- const toggle = event.currentTarget;
- if (toggle instanceof HTMLInputElement) {
- this.handleTypingIndicatorsToggle(toggle.checked);
- }
- });
- }
+ // Legacy toggles removed - handled by DMPrivacySettings in AppShell
if (this.profileLinkPreviewAutoToggle instanceof HTMLElement) {
this.profileLinkPreviewAutoToggle.addEventListener("change", (event) => {