diff --git a/packages/app/src/Element/NoteFooter.tsx b/packages/app/src/Element/NoteFooter.tsx index c96f3ec..c3ec280 100644 --- a/packages/app/src/Element/NoteFooter.tsx +++ b/packages/app/src/Element/NoteFooter.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useSelector, useDispatch } from "react-redux"; import { useIntl, FormattedMessage } from "react-intl"; import { Menu, MenuItem } from "@szhsin/react-menu"; @@ -26,6 +26,39 @@ import { useWallet } from "Wallet"; import messages from "./messages"; +// a dumb cache to remember which notes we zapped +class DumbZapCache { + #set: Set = new Set(); + constructor() { + this.#load(); + } + + add(id: u256) { + this.#set.add(this.#truncId(id)); + this.#save(); + } + + has(id: u256) { + return this.#set.has(this.#truncId(id)); + } + + #truncId(id: u256) { + return id.slice(0, 12); + } + + #save() { + window.localStorage.setItem("zap-cache", JSON.stringify([...this.#set])); + } + + #load() { + const data = window.localStorage.getItem("zap-cache"); + if (data) { + this.#set = new Set(JSON.parse(data) as Array); + } + } +} +const ZapCache = new DumbZapCache(); + export interface Translation { text: string; fromLanguage: string; @@ -65,7 +98,7 @@ export default function NoteFooter(props: NoteFooterProps) { type: "language", }); const zapTotal = zaps.reduce((acc, z) => acc + z.amount, 0); - const didZap = zaps.some(a => a.sender === login); + const didZap = ZapCache.has(ev.Id) || zaps.some(a => a.sender === login); const longPress = useLongPress( e => { e.stopPropagation(); @@ -114,16 +147,6 @@ export default function NoteFooter(props: NoteFooterProps) { if (wallet?.isReady() && lnurl) { setZapping(true); try { - if (prefs.fastZapDonate > 0) { - // spin off donate - const donateAmount = Math.floor(prefs.defaultZapAmount * prefs.fastZapDonate); - if (donateAmount > 0) { - console.debug(`Donating ${donateAmount} sats to ${DonateLNURL}`); - fastZapInner(DonateLNURL, donateAmount, bech32ToHex(SnortPubKey)) - .then(() => console.debug("Donation sent! Thank You!")) - .catch(() => console.debug("Failed to donate")); - } - } await fastZapInner(lnurl, prefs.defaultZapAmount, ev.PubKey, ev.Id); } catch (e) { console.warn("Fast zap failed", e); @@ -145,9 +168,37 @@ export default function NoteFooter(props: NoteFooterProps) { const zap = handler.canZap ? await publisher.zap(amount * 1000, key, id) : undefined; const invoice = await handler.getInvoice(amount, undefined, zap); await wallet.payInvoice(unwrap(invoice.pr)); + + if (prefs.fastZapDonate > 0) { + // spin off donate + const donateAmount = Math.floor(prefs.defaultZapAmount * prefs.fastZapDonate); + if (donateAmount > 0) { + console.debug(`Donating ${donateAmount} sats to ${DonateLNURL}`); + fastZapInner(DonateLNURL, donateAmount, bech32ToHex(SnortPubKey)) + .then(() => console.debug("Donation sent! Thank You!")) + .catch(() => console.debug("Failed to donate")); + } + } } } + useEffect(() => { + if (prefs.autoZap) { + const lnurl = author?.lud16 || author?.lud06; + if (wallet?.isReady() && lnurl && !ZapCache.has(ev.Id)) { + queueMicrotask(async () => { + setZapping(true); + try { + await fastZapInner(lnurl, prefs.defaultZapAmount, ev.PubKey, ev.Id); + ZapCache.add(ev.Id); + } finally { + setZapping(false); + } + }); + } + } + }, [prefs.autoZap]); + function tipButton() { const service = author?.lud16 || author?.lud06; if (service) { diff --git a/packages/app/src/Pages/settings/Preferences.tsx b/packages/app/src/Pages/settings/Preferences.tsx index 1a34f87..647fa6f 100644 --- a/packages/app/src/Pages/settings/Preferences.tsx +++ b/packages/app/src/Pages/settings/Preferences.tsx @@ -191,6 +191,23 @@ const PreferencesPage = () => { /> +
+
+
+ +
+ + + +
+
+ dispatch(setPreferences({ ...perf, autoZap: e.target.checked }))} + /> +
+
diff --git a/packages/app/src/State/Login.ts b/packages/app/src/State/Login.ts index 31a28ae..c26e768 100644 --- a/packages/app/src/State/Login.ts +++ b/packages/app/src/State/Login.ts @@ -85,6 +85,11 @@ export interface UserPreferences { * For each fast zap an additional X% will be sent to Snort donate address */ fastZapDonate: number; + + /** + * Auto-zap every post + */ + autoZap: boolean; } export interface LoginStore { @@ -243,8 +248,9 @@ export const InitState = { fileUploader: "void.cat", imgProxyConfig: DefaultImgProxy, defaultRootTab: "posts", - defaultZapAmount: 500, + defaultZapAmount: 50, fastZapDonate: 0.0, + autoZap: false, }, } as LoginStore; diff --git a/packages/app/src/lang.json b/packages/app/src/lang.json index 9e9cc2b..7380af2 100644 --- a/packages/app/src/lang.json +++ b/packages/app/src/lang.json @@ -218,6 +218,9 @@ "Cu/K85": { "defaultMessage": "Translated from {lang}" }, + "D+KzKd": { + "defaultMessage": "Automatically zap every note when loaded" + }, "D3idYv": { "defaultMessage": "Settings" }, @@ -227,6 +230,9 @@ "DZzCem": { "defaultMessage": "Show latest {n} notes" }, + "Dh3hbq": { + "defaultMessage": "Auto Zap" + }, "Dt/Zd5": { "defaultMessage": "Media in posts will automatically be shown for selected people, otherwise only the link will show" }, diff --git a/packages/app/src/translations/en.json b/packages/app/src/translations/en.json index d93c619..5ca4c84 100644 --- a/packages/app/src/translations/en.json +++ b/packages/app/src/translations/en.json @@ -70,9 +70,11 @@ "CHTbO3": "Failed to load invoice", "CmZ9ls": "{n} Muted", "Cu/K85": "Translated from {lang}", + "D+KzKd": "Automatically zap every note when loaded", "D3idYv": "Settings", "DKnriN": "Send sats", "DZzCem": "Show latest {n} notes", + "Dh3hbq": "Auto Zap", "Dt/Zd5": "Media in posts will automatically be shown for selected people, otherwise only the link will show", "E8a4yq": "Follow some popular accounts", "EPYwm7": "Your private key is your password. If you lose this key, you will lose access to your account! Copy it and keep it in a safe place. There is no way to reset your private key.", @@ -299,4 +301,4 @@ "zjJZBd": "You're ready!", "zonsdq": "Failed to load LNURL service", "zvCDao": "Automatically show latest notes" -} +} \ No newline at end of file