@decentnetwork/beagle 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/desktop/app.js +167 -6
- package/package.json +1 -1
package/dist/desktop/app.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
window.__DK_UI_VERSION="0.1.
|
|
1
|
+
window.__DK_UI_VERSION="0.1.14";
|
|
2
2
|
const ICON_PATHS = {
|
|
3
3
|
// ---- tab bar (the four must feel like one set) ----
|
|
4
4
|
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
|
@@ -1528,6 +1528,144 @@ function dkMarkdownHtml(src) {
|
|
|
1528
1528
|
}
|
|
1529
1529
|
return html || dkHtmlEscape(src);
|
|
1530
1530
|
}
|
|
1531
|
+
const DK_NATIVE_MEDIA_MIME = {
|
|
1532
|
+
".jpg": "image/jpeg",
|
|
1533
|
+
".jpeg": "image/jpeg",
|
|
1534
|
+
".png": "image/png",
|
|
1535
|
+
".gif": "image/gif",
|
|
1536
|
+
".webp": "image/webp",
|
|
1537
|
+
".heic": "image/heic",
|
|
1538
|
+
".m4a": "audio/mp4",
|
|
1539
|
+
".aac": "audio/aac",
|
|
1540
|
+
".mp3": "audio/mpeg",
|
|
1541
|
+
".wav": "audio/wav",
|
|
1542
|
+
".caf": "audio/x-caf",
|
|
1543
|
+
".mp4": "video/mp4",
|
|
1544
|
+
".mov": "video/quicktime",
|
|
1545
|
+
".m4v": "video/x-m4v"
|
|
1546
|
+
};
|
|
1547
|
+
const DK_GROUP_TS_RE = /\n?\[(20\d{2}-\d{1,2}-\d{1,2}\s+\d{1,2}:\d{2}:\d{2})\]\s*$/;
|
|
1548
|
+
function dkStripGroupTs(text) {
|
|
1549
|
+
const m = DK_GROUP_TS_RE.exec(text);
|
|
1550
|
+
return m ? { body: text.slice(0, m.index), ts: m[1] } : { body: text, ts: null };
|
|
1551
|
+
}
|
|
1552
|
+
function dkSplitGroupSender(text) {
|
|
1553
|
+
const m = /^([^:\n]{1,48}):\s([\s\S]+)$/.exec(text);
|
|
1554
|
+
return m ? { sender: m[1], body: m[2] } : null;
|
|
1555
|
+
}
|
|
1556
|
+
function dkParseCGP1(text) {
|
|
1557
|
+
const t = String(text || "").trim();
|
|
1558
|
+
if (!t.startsWith("CGP1 "))
|
|
1559
|
+
return null;
|
|
1560
|
+
let j = null;
|
|
1561
|
+
try {
|
|
1562
|
+
j = JSON.parse(t.slice(5));
|
|
1563
|
+
} catch (e) {
|
|
1564
|
+
return null;
|
|
1565
|
+
}
|
|
1566
|
+
if (!j || j.type !== "carrier_group_message" || j.chat_type !== "group")
|
|
1567
|
+
return null;
|
|
1568
|
+
const origin = j.origin || {};
|
|
1569
|
+
const senderId = origin.userid || origin.friendid || null;
|
|
1570
|
+
const sender = origin.nickname || origin.user_info && origin.user_info.name || (senderId ? senderId.slice(0, 10) : "member");
|
|
1571
|
+
const body = j.message && j.message.text || j.render && j.render.plain || "";
|
|
1572
|
+
return { sender, senderId, body: String(body), ts: null, strong: true };
|
|
1573
|
+
}
|
|
1574
|
+
function dkGroupParse(text) {
|
|
1575
|
+
const cgp = dkParseCGP1(text);
|
|
1576
|
+
if (cgp)
|
|
1577
|
+
return cgp;
|
|
1578
|
+
const t = String(text || "");
|
|
1579
|
+
const { body: noTs, ts } = dkStripGroupTs(t);
|
|
1580
|
+
const split = dkSplitGroupSender(noTs.trim());
|
|
1581
|
+
if (!split)
|
|
1582
|
+
return null;
|
|
1583
|
+
return { sender: split.sender, senderId: null, body: split.body.trim(), ts, strong: !!ts };
|
|
1584
|
+
}
|
|
1585
|
+
function DkGroupSender({ grp, T }) {
|
|
1586
|
+
const [open, setOpen] = React.useState(false);
|
|
1587
|
+
const [busy, setBusy] = React.useState(false);
|
|
1588
|
+
const [done, setDone] = React.useState(null);
|
|
1589
|
+
const seed = grp.senderId || grp.sender;
|
|
1590
|
+
const addFriend = () => {
|
|
1591
|
+
setBusy(true);
|
|
1592
|
+
fetch("/api/add", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ address: grp.senderId }) }).then((r) => r.json()).then((r) => setDone(r.ok ? T && T.addSent || "request sent" : r.error || "failed")).catch((e) => setDone(String(e && e.message || e))).finally(() => setBusy(false));
|
|
1593
|
+
};
|
|
1594
|
+
return /* @__PURE__ */ React.createElement("span", { style: { position: "relative", display: "inline-flex", alignItems: "center", gap: 5, margin: "0 3px 2px" } }, /* @__PURE__ */ React.createElement(
|
|
1595
|
+
"button",
|
|
1596
|
+
{
|
|
1597
|
+
onClick: () => setOpen((v) => !v),
|
|
1598
|
+
style: { display: "inline-flex", alignItems: "center", gap: 5, background: "none", border: "none", padding: 0, cursor: "pointer" }
|
|
1599
|
+
},
|
|
1600
|
+
/* @__PURE__ */ React.createElement(DkIdenticon, { seed, size: 16, radius: 4 }),
|
|
1601
|
+
/* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, grp.sender)
|
|
1602
|
+
), open && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { onClick: () => setOpen(false), style: { position: "fixed", inset: 0, zIndex: 40 } }), /* @__PURE__ */ React.createElement("span", { style: {
|
|
1603
|
+
position: "absolute",
|
|
1604
|
+
left: 0,
|
|
1605
|
+
top: 20,
|
|
1606
|
+
zIndex: 50,
|
|
1607
|
+
width: 240,
|
|
1608
|
+
padding: 12,
|
|
1609
|
+
borderRadius: 10,
|
|
1610
|
+
background: "var(--panel-2)",
|
|
1611
|
+
border: "1px solid var(--line)",
|
|
1612
|
+
boxShadow: "0 14px 40px rgba(0,0,0,0.4)",
|
|
1613
|
+
display: "flex",
|
|
1614
|
+
flexDirection: "column",
|
|
1615
|
+
gap: 8
|
|
1616
|
+
} }, /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkIdenticon, { seed, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, fontWeight: 700, color: "var(--text)", wordBreak: "break-all" } }, grp.sender)), grp.senderId ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Mono, { size: 10.5, dim: true, copy: grp.senderId, title: grp.senderId }, shortKey(grp.senderId, 12, 8)), /* @__PURE__ */ React.createElement(
|
|
1617
|
+
"button",
|
|
1618
|
+
{
|
|
1619
|
+
onClick: addFriend,
|
|
1620
|
+
disabled: busy || !!done,
|
|
1621
|
+
style: {
|
|
1622
|
+
padding: "6px 10px",
|
|
1623
|
+
borderRadius: 8,
|
|
1624
|
+
border: "none",
|
|
1625
|
+
background: "var(--accent)",
|
|
1626
|
+
color: "#fff",
|
|
1627
|
+
fontFamily: "var(--ui)",
|
|
1628
|
+
fontSize: 12,
|
|
1629
|
+
cursor: busy || done ? "default" : "pointer",
|
|
1630
|
+
opacity: busy ? 0.6 : 1
|
|
1631
|
+
}
|
|
1632
|
+
},
|
|
1633
|
+
done || (T && T.add || "Add friend")
|
|
1634
|
+
)) : /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)", lineHeight: 1.45 } }, T && T.groupSenderUnknown || "The group relays only this display name. Register Beagle as a group agent (/agent add <beagle address> in the group) to receive full member identities you can add as friends."))));
|
|
1635
|
+
}
|
|
1636
|
+
function dkThreadIsGroup(thread) {
|
|
1637
|
+
return (thread || []).some((m) => !m.day && m.dir !== "out" && !m.file && (dkGroupParse(m.text) || {}).strong);
|
|
1638
|
+
}
|
|
1639
|
+
function dkNativeMediaFromText(text) {
|
|
1640
|
+
let body = dkStripGroupTs(String(text || "")).body.trim();
|
|
1641
|
+
if (body.length < 32)
|
|
1642
|
+
return null;
|
|
1643
|
+
let sender = null;
|
|
1644
|
+
if (!body.startsWith("{")) {
|
|
1645
|
+
const split = dkSplitGroupSender(body);
|
|
1646
|
+
if (!split || !split.body.startsWith("{"))
|
|
1647
|
+
return null;
|
|
1648
|
+
sender = split.sender;
|
|
1649
|
+
body = split.body.trim();
|
|
1650
|
+
}
|
|
1651
|
+
if (!body.startsWith("{") || !body.endsWith("}"))
|
|
1652
|
+
return null;
|
|
1653
|
+
let j = null;
|
|
1654
|
+
try {
|
|
1655
|
+
j = JSON.parse(body);
|
|
1656
|
+
} catch (e) {
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
if (!j || typeof j !== "object" || typeof j.data !== "string" || j.data.length < 16)
|
|
1660
|
+
return null;
|
|
1661
|
+
const kind = j.type === "image" ? "image" : j.type === "audio" || j.type === "voice" ? "audio" : j.type === "video" ? "video" : null;
|
|
1662
|
+
if (!kind)
|
|
1663
|
+
return null;
|
|
1664
|
+
const ext = String(j.fileExtension || "").toLowerCase();
|
|
1665
|
+
const mime = DK_NATIVE_MEDIA_MIME[ext] || kind + "/*";
|
|
1666
|
+
const name = String(j.fileName || "file") + ext;
|
|
1667
|
+
return { sender, kind, name, url: "data:" + mime + ";base64," + j.data.replace(/\s+/g, "") };
|
|
1668
|
+
}
|
|
1531
1669
|
function MarkdownText({ text }) {
|
|
1532
1670
|
return /* @__PURE__ */ React.createElement("div", { className: "dk-md", dangerouslySetInnerHTML: { __html: dkMarkdownHtml(text) } });
|
|
1533
1671
|
}
|
|
@@ -1701,9 +1839,11 @@ function DkChatForm({ form, submitted, peer, onSubmit }) {
|
|
|
1701
1839
|
return null;
|
|
1702
1840
|
}), err && /* @__PURE__ */ React.createElement("div", { style: { color: "var(--danger, #ff6b6b)", fontSize: 11.5, fontFamily: "var(--mono)" } }, err));
|
|
1703
1841
|
}
|
|
1704
|
-
function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onCall, onFormSubmit, answered, selMode, selected, onToggleSel, busy }) {
|
|
1842
|
+
function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onCall, onFormSubmit, answered, selMode, selected, onToggleSel, busy, isGroup }) {
|
|
1705
1843
|
const mine = m.from === "me";
|
|
1706
|
-
const
|
|
1844
|
+
const nativeMedia = !m.file ? dkNativeMediaFromText(m.text) : null;
|
|
1845
|
+
const grp = isGroup && m.dir !== "out" && !m.file && !nativeMedia ? dkGroupParse(m.text) : null;
|
|
1846
|
+
const read = window.ChatComponents ? window.ChatComponents.readMessage((grp ? grp.body : m.text) || "") : { text: grp ? grp.body : m.text, form: null, interaction: null };
|
|
1707
1847
|
const submitted = read.form && answered ? answered.get(read.form.custom_id) : null;
|
|
1708
1848
|
const rtcFile = !mine && !m.file ? dkRtcFileFromText(peer.userId || peer.id, m.text) : null;
|
|
1709
1849
|
const callRec = !m.file ? dkCallFromText(m.text) : null;
|
|
@@ -1934,7 +2074,22 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
1934
2074
|
)
|
|
1935
2075
|
);
|
|
1936
2076
|
})()
|
|
1937
|
-
) : /* @__PURE__ */ React.createElement("div", { style: {
|
|
2077
|
+
) : nativeMedia ? /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 4, maxWidth: "min(420px, 88%)" } }, nativeMedia.sender && /* @__PURE__ */ React.createElement(DkGroupSender, { grp: { sender: nativeMedia.sender, senderId: null }, T }), nativeMedia.kind === "image" ? /* @__PURE__ */ React.createElement(
|
|
2078
|
+
"img",
|
|
2079
|
+
{
|
|
2080
|
+
src: nativeMedia.url,
|
|
2081
|
+
alt: nativeMedia.name,
|
|
2082
|
+
style: { maxWidth: "100%", borderRadius: 12, border: "1px solid var(--line)", cursor: "pointer" },
|
|
2083
|
+
onClick: () => {
|
|
2084
|
+
try {
|
|
2085
|
+
const w = window.open();
|
|
2086
|
+
if (w)
|
|
2087
|
+
w.document.write('<img src="' + nativeMedia.url + '" style="max-width:100%">');
|
|
2088
|
+
} catch (e) {
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
) : nativeMedia.kind === "audio" ? /* @__PURE__ */ React.createElement("audio", { controls: true, src: nativeMedia.url, style: { maxWidth: "100%" } }) : /* @__PURE__ */ React.createElement("video", { controls: true, src: nativeMedia.url, style: { maxWidth: "100%", borderRadius: 12, border: "1px solid var(--line)" } })) : /* @__PURE__ */ React.createElement(React.Fragment, null, grp && /* @__PURE__ */ React.createElement(DkGroupSender, { grp, T }), /* @__PURE__ */ React.createElement("div", { style: {
|
|
1938
2093
|
padding: "8px 12px",
|
|
1939
2094
|
borderRadius: 12,
|
|
1940
2095
|
borderBottomRightRadius: mine ? 4 : 12,
|
|
@@ -1950,7 +2105,7 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
1950
2105
|
lineHeight: 1.4,
|
|
1951
2106
|
letterSpacing: -0.1,
|
|
1952
2107
|
wordBreak: "break-word"
|
|
1953
|
-
} }, /* @__PURE__ */ React.createElement(MarkdownText, { text: read.text })), read.form && /* @__PURE__ */ React.createElement("div", { style: { marginTop: 6 } }, /* @__PURE__ */ React.createElement(DkChatForm, { form: read.form, submitted, peer, onSubmit: onFormSubmit })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 4, margin: "3px 3px 0" } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10, color: "var(--faint)" } }, m.time), !mine && m.via && /* @__PURE__ */ React.createElement(
|
|
2108
|
+
} }, /* @__PURE__ */ React.createElement(MarkdownText, { text: read.text }))), read.form && /* @__PURE__ */ React.createElement("div", { style: { marginTop: 6 } }, /* @__PURE__ */ React.createElement(DkChatForm, { form: read.form, submitted, peer, onSubmit: onFormSubmit })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 4, margin: "3px 3px 0" } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10, color: "var(--faint)" } }, m.time), !mine && m.via && /* @__PURE__ */ React.createElement(
|
|
1954
2109
|
"span",
|
|
1955
2110
|
{
|
|
1956
2111
|
title: m.via === "offline" ? "delivered via express relay (offline)" : "delivered over a live session (online)",
|
|
@@ -1981,6 +2136,7 @@ function Msg({ m, peer, T, onTheater, onDelete, onCancel, onRetry, onReveal, onC
|
|
|
1981
2136
|
}
|
|
1982
2137
|
function Conversation({ T, peer, lang, thread: threadProp, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread }) {
|
|
1983
2138
|
const scrollRef = React.useRef(null);
|
|
2139
|
+
const isGroup = React.useMemo(() => dkThreadIsGroup(threadProp), [threadProp]);
|
|
1984
2140
|
const followScrollRef = React.useRef(true);
|
|
1985
2141
|
const fileRef = React.useRef(null);
|
|
1986
2142
|
const rtcFileRef = React.useRef(null);
|
|
@@ -2233,7 +2389,7 @@ function Conversation({ T, peer, lang, thread: threadProp, onSend, onSendFile, o
|
|
|
2233
2389
|
onDrop
|
|
2234
2390
|
},
|
|
2235
2391
|
dragOver && /* @__PURE__ */ React.createElement("div", { style: { position: "absolute", inset: 0, zIndex: 30, background: "rgba(91,140,255,0.10)", border: "2px dashed var(--accent)", borderRadius: 12, display: "flex", alignItems: "center", justifyContent: "center", pointerEvents: "none", fontFamily: "var(--mono)", fontSize: 14, color: "var(--accent)" } }, lang === "zh" ? "\u677E\u5F00\u53D1\u9001\u6587\u4EF6" : "Drop to send file"),
|
|
2236
|
-
/* @__PURE__ */ React.createElement("div", { style: { height: 60, flexShrink: 0, borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 12, padding: "0 16px", background: "var(--panel)" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: peer.alias ? "var(--ui)" : "var(--mono)", fontSize: 15, fontWeight: 700, color: "var(--text)" } }, peer.alias || shortKey(peer.userId, 10, 6)), peer.agent && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "agent"), /* @__PURE__ */ React.createElement(RouteTag, { peer })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 2 } }, /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.userId, title: peer.userId }, shortKey(peer.userId, 10, 6)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement("button", { onClick: () => onOpenNet(peer), title: T && T.openNet || "Network view", style: { background: "none", border: "none", cursor: "pointer", padding: 0, color: "var(--accent)", display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "network", size: 12, stroke: 2 })), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.ip, title: peer.ip }, peer.ip), peer.address && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement(
|
|
2392
|
+
/* @__PURE__ */ React.createElement("div", { style: { height: 60, flexShrink: 0, borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 12, padding: "0 16px", background: "var(--panel)" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer, size: 34, radius: 8 }), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0 } }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: peer.alias ? "var(--ui)" : "var(--mono)", fontSize: 15, fontWeight: 700, color: "var(--text)" } }, peer.alias || shortKey(peer.userId, 10, 6)), peer.agent && /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, "agent"), isGroup && /* @__PURE__ */ React.createElement(Tag, null, T && T.groupTag || "group"), /* @__PURE__ */ React.createElement(RouteTag, { peer })), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 2 } }, /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.userId, title: peer.userId }, shortKey(peer.userId, 10, 6)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement("button", { onClick: () => onOpenNet(peer), title: T && T.openNet || "Network view", style: { background: "none", border: "none", cursor: "pointer", padding: 0, color: "var(--accent)", display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "network", size: 12, stroke: 2 })), /* @__PURE__ */ React.createElement(Mono, { size: 11.5, dim: true, copy: peer.ip, title: peer.ip }, peer.ip), peer.address && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { style: { color: "var(--line)" } }, "\xB7"), /* @__PURE__ */ React.createElement(
|
|
2237
2393
|
Mono,
|
|
2238
2394
|
{
|
|
2239
2395
|
size: 11.5,
|
|
@@ -2283,6 +2439,7 @@ ${peer.address}`
|
|
|
2283
2439
|
m,
|
|
2284
2440
|
peer,
|
|
2285
2441
|
T,
|
|
2442
|
+
isGroup,
|
|
2286
2443
|
onTheater: setTheater,
|
|
2287
2444
|
onDelete: (id) => doDelete([id]),
|
|
2288
2445
|
onCancel: doCancel,
|
|
@@ -3493,9 +3650,11 @@ const STR = {
|
|
|
3493
3650
|
pickPeer: "Select a peer to open the conversation",
|
|
3494
3651
|
queued: "queued",
|
|
3495
3652
|
sendingMsg: "sending",
|
|
3653
|
+
groupTag: "group",
|
|
3496
3654
|
open: "open",
|
|
3497
3655
|
retry: "Retry",
|
|
3498
3656
|
cancel: "Cancel",
|
|
3657
|
+
groupSenderUnknown: "The group relays only this display name. Register Beagle as a group agent (/agent add <beagle address> in the group) to receive full member identities you can add as friends.",
|
|
3499
3658
|
pendingFriend: "Waiting for them to accept your friend request \u2014 messages will queue and deliver once they do.",
|
|
3500
3659
|
cancelling: "Cancelling\u2026",
|
|
3501
3660
|
cancelled: "Transfer cancelled",
|
|
@@ -3589,9 +3748,11 @@ const STR = {
|
|
|
3589
3748
|
pickPeer: "\u9009\u62E9\u4E00\u4F4D\u597D\u53CB\u5F00\u59CB\u4F1A\u8BDD",
|
|
3590
3749
|
queued: "\u5F85\u53D1\u9001",
|
|
3591
3750
|
sendingMsg: "\u53D1\u9001\u4E2D",
|
|
3751
|
+
groupTag: "\u7FA4",
|
|
3592
3752
|
open: "\u6253\u5F00",
|
|
3593
3753
|
retry: "\u91CD\u8BD5",
|
|
3594
3754
|
cancel: "\u53D6\u6D88",
|
|
3755
|
+
groupSenderUnknown: "\u7FA4\u670D\u52A1\u53EA\u8F6C\u53D1\u4E86\u663E\u793A\u540D\uFF0C\u62FF\u4E0D\u5230\u8BE5\u6210\u5458\u7684\u5B8C\u6574\u8EAB\u4EFD\u3002\u5728\u7FA4\u91CC\u6267\u884C /agent add <beagle \u5730\u5740> \u628A Beagle \u6CE8\u518C\u4E3A\u7FA4 agent \u540E\uFF0C\u5373\u53EF\u6536\u5230\u5B8C\u6574\u8EAB\u4EFD\u5E76\u4E00\u952E\u52A0\u597D\u53CB\u3002",
|
|
3595
3756
|
pendingFriend: "\u7B49\u5F85\u5BF9\u65B9\u63A5\u53D7\u597D\u53CB\u8BF7\u6C42 \u2014 \u6D88\u606F\u4F1A\u5148\u6392\u961F\uFF0C\u5BF9\u65B9\u63A5\u53D7\u540E\u81EA\u52A8\u9001\u8FBE\u3002",
|
|
3596
3757
|
cancelling: "\u6B63\u5728\u53D6\u6D88\u2026",
|
|
3597
3758
|
cancelled: "\u5DF2\u53D6\u6D88\u4F20\u8F93",
|
package/package.json
CHANGED