aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js40
1 files changed, 34 insertions, 6 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index cde11dc..54c9cfe 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -2507,6 +2507,9 @@ export function messagesFeature(ctx) {
? [...new Set(newest.tags.filter((x) => x[0] === 'p' && /^[0-9a-f]{64}$/.test(x[1] || '')).map((x) => x[1]))]
: [];
const known = [...threads.keys()];
+ // who may ring us when the app is shut: those we've written to (the
+ // follows ride separately); `known` stays the DM filter's wider list
+ const rings = known.filter((pk) => wroteTo(pk));
const names = {};
for (const pk of [...follows, ...known]) {
const p = profiles.get(pk);
@@ -2515,7 +2518,7 @@ export function messagesFeature(ctx) {
await saveInbox(wallet._cacheKey(), {
pubkey: id.pubkey,
sk: id.signer instanceof Uint8Array ? bytesToHex(id.signer) : null,
- follows, known, names, hasList: !!newest, updated: Date.now(),
+ follows, known, rings, names, hasList: !!newest, updated: Date.now(),
muted: [...mutesNow().set], // no buzz from a muted sender either
});
} catch { inboxAt = 0; }
@@ -9091,8 +9094,18 @@ export function messagesFeature(ctx) {
return navigator.mediaDevices.getUserMedia(type === 'video' ? { audio, video } : { audio });
}
// who may ring: someone you follow, or someone you've written to
- const mayRing = (pk) => !hiddenPk(pk) && (followsNow().set.has(pk)
- || [...(threads.get(pk) || new Map()).values()].some((m) => m.mine));
+ // who may ring: someone you follow, or someone you've written to. Anyone
+ // else's call doesn't ring but is told of, as a missed call that didn't
+ // ring (a wife's call must not vanish because you never followed her);
+ // a muted person's leaves nothing.
+ const mayRing = (pk) => hiddenPk(pk) ? null
+ : followsNow().set.has(pk) || wroteTo(pk) ? 'ring' : 'quiet';
+ // a message of ours in the conversation — not a call logged there (a
+ // stranger's unrung call would otherwise let their next one ring)
+ function wroteTo(pk) {
+ for (const m of (threads.get(pk) || new Map()).values()) if (m.mine && m.rumor.kind !== CALL_LOG) return true;
+ return false;
+ }
function callsNow() {
if (calls) return calls;
calls = createCalls({
@@ -9128,7 +9141,7 @@ export function messagesFeature(ctx) {
// devices list it too. A call rung on two of our devices is logged by
// both; the conversation shows it once, by its call-id.
const callStatus = (rec) => rec.connected ? 'answered'
- : rec.reason === 'missed' ? 'missed'
+ : rec.reason === 'missed' || rec.reason === 'unrung' ? 'missed'
: rec.reason === 'declined' || rec.reason === 'peer-declined' ? 'declined'
: rec.reason === 'no-answer' ? 'no-answer'
: rec.reason === 'busy' ? 'busy'
@@ -9157,7 +9170,7 @@ export function messagesFeature(ctx) {
kind: CALL_LOG, pubkey: id.pubkey, created_at: Math.floor((rec.at || Date.now()) / 1000),
content: callLogText(rec.dir, rec.type, status, rec.seconds),
tags: [['p', rec.peer], ['call-id', rec.id], ['call-type', rec.type], ['direction', rec.dir], ['status', status],
- ['duration', String(rec.seconds || 0)], ['alt', 'Call log']],
+ ['duration', String(rec.seconds || 0)], ...(rec.reason === 'unrung' ? [['rang', 'no']] : []), ['alt', 'Call log']],
});
noteDM(rec.peer, rumor, true);
persistDms();
@@ -9184,11 +9197,15 @@ export function messagesFeature(ctx) {
const tag = (k) => (m.rumor.tags.find((x) => x[0] === k) || [])[1];
const type = tag('call-type') === 'video' ? 'video' : 'voice', status = tag('status') || 'failed', dir = tag('direction') || 'out';
const missed = status === 'missed' || (dir === 'in' && status === 'declined');
+ // a call that didn't ring (someone you don't follow), saying so — and,
+ // while that's still so, how to have them ring next time
+ const unrung = tag('rang') === 'no';
return h('div', { class: 'chat-row call-log' + (missed ? ' missed' : ''), 'data-call-log': tag('call-id') || '' },
h('button', { type: 'button', class: 'call-log-pill', title: t(type === 'video' ? 'callVideo' : 'callVoice'), onClick: () => startCall(peer, type) },
callIcon(type === 'video' ? 'video' : 'phone'),
h('span', {}, callLogText(dir, type, status, +tag('duration') || 0)),
- h('span', { class: 'chat-time' }, timeLabel(m.rumor.created_at * 1000))));
+ h('span', { class: 'chat-time' }, timeLabel(m.rumor.created_at * 1000))),
+ unrung ? h('div', { class: 'small faint call-log-why' }, t(mayRing(peer) === 'ring' ? 'callLogUnrungWas' : 'callLogUnrung')) : null);
}
// the call offer a push brought (sw-nwc.js keeps it): rung now, once
@@ -9196,6 +9213,17 @@ export function messagesFeature(ctx) {
try {
if (typeof caches === 'undefined') return;
const cache = await caches.open('coinos-call');
+ // calls the worker saw from people who don't ring us: logged, unrung
+ const quiet = await cache.match('/__quiet-calls');
+ if (quiet) {
+ await cache.delete('/__quiet-calls');
+ for (const offer of (await quiet.json()) || []) {
+ if (!offer || !offer.pubkey || !mayRing(offer.pubkey)) continue;
+ const id = (offer.tags.find((x) => x[0] === 'call-id') || [])[1];
+ const type = (offer.tags.find((x) => x[0] === 'call-type') || [])[1] === 'video' ? 'video' : 'voice';
+ if (id) logCall({ id, peer: offer.pubkey, type, dir: 'in', reason: 'unrung', seconds: 0, at: offer.created_at * 1000 }).catch(() => {});
+ }
+ }
const r = await cache.match('/__pending-call');
if (!r) return;
await cache.delete('/__pending-call');