Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b8d0d85f2 | |||
|
|
6e31989262 |
||
|
|
c155bbb534 |
6 changed files with 230 additions and 53 deletions
182
apps/tauri/src-tauri/Cargo.lock
generated
182
apps/tauri/src-tauri/Cargo.lock
generated
|
|
@ -560,6 +560,17 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfb"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"uuid",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.15.8"
|
||||
|
|
@ -826,7 +837,20 @@ version = "0.36.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
|
||||
dependencies = [
|
||||
"cssparser-macros",
|
||||
"cssparser-macros 0.6.1",
|
||||
"dtoa-short",
|
||||
"itoa",
|
||||
"phf",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98"
|
||||
dependencies = [
|
||||
"cssparser-macros 0.7.0",
|
||||
"dtoa-short",
|
||||
"itoa",
|
||||
"phf",
|
||||
|
|
@ -843,6 +867,16 @@ dependencies = [
|
|||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser-macros"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a2a99df6e410a8ff4245aa2006499ea662245f967cc7c0a38c83ef8eb44dbf"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.8.0"
|
||||
|
|
@ -1127,11 +1161,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"cssparser",
|
||||
"cssparser 0.36.0",
|
||||
"foldhash",
|
||||
"html5ever",
|
||||
"html5ever 0.38.0",
|
||||
"precomputed-hash",
|
||||
"selectors",
|
||||
"selectors 0.36.1",
|
||||
"tendril",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dom_query"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"cssparser 0.37.0",
|
||||
"foldhash",
|
||||
"html5ever 0.39.0",
|
||||
"precomputed-hash",
|
||||
"selectors 0.38.0",
|
||||
"tendril",
|
||||
]
|
||||
|
||||
|
|
@ -1982,7 +2031,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
|
||||
dependencies = [
|
||||
"log",
|
||||
"markup5ever",
|
||||
"markup5ever 0.38.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8"
|
||||
dependencies = [
|
||||
"log",
|
||||
"markup5ever 0.39.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2278,7 +2337,16 @@ version = "0.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7"
|
||||
dependencies = [
|
||||
"cfb",
|
||||
"cfb 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "infer"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4"
|
||||
dependencies = [
|
||||
"cfb 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2641,6 +2709,17 @@ dependencies = [
|
|||
"web_atoms",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de"
|
||||
dependencies = [
|
||||
"log",
|
||||
"tendril",
|
||||
"web_atoms",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
|
|
@ -4200,7 +4279,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"cssparser",
|
||||
"cssparser 0.36.0",
|
||||
"derive_more",
|
||||
"log",
|
||||
"new_debug_unreachable",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
"precomputed-hash",
|
||||
"rustc-hash",
|
||||
"servo_arc",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "selectors"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"cssparser 0.37.0",
|
||||
"derive_more",
|
||||
"log",
|
||||
"new_debug_unreachable",
|
||||
|
|
@ -4798,7 +4896,7 @@ dependencies = [
|
|||
"serde_repr",
|
||||
"serialize-to-javascript",
|
||||
"swift-rs",
|
||||
"tauri-build",
|
||||
"tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=4af26a3f7f8b692d62cca549bbacd93f5ce90b41)",
|
||||
"tauri-macros",
|
||||
"tauri-runtime",
|
||||
"tauri-runtime-wry",
|
||||
|
|
@ -4833,6 +4931,26 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.6.3"
|
||||
source = "git+https://github.com/tauri-apps/tauri?rev=dd6befda925845fc74ca595d6d42de6c49580dd8#dd6befda925845fc74ca595d6d42de6c49580dd8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
"dirs",
|
||||
"glob",
|
||||
"heck 0.5.0",
|
||||
"json-patch 4.2.0",
|
||||
"schemars 0.8.22",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.9.3 (git+https://github.com/tauri-apps/tauri?rev=dd6befda925845fc74ca595d6d42de6c49580dd8)",
|
||||
"tauri-winres",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.6.3"
|
||||
|
|
@ -5027,11 +5145,11 @@ dependencies = [
|
|||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"ctor 0.8.0",
|
||||
"dom_query",
|
||||
"dom_query 0.27.0",
|
||||
"dunce",
|
||||
"glob",
|
||||
"http",
|
||||
"infer",
|
||||
"infer 0.19.0",
|
||||
"json-patch 3.0.1",
|
||||
"log",
|
||||
"memchr",
|
||||
|
|
@ -5063,11 +5181,11 @@ dependencies = [
|
|||
"brotli",
|
||||
"cargo_metadata",
|
||||
"ctor 1.0.12",
|
||||
"dom_query",
|
||||
"dom_query 0.27.0",
|
||||
"dunce",
|
||||
"glob",
|
||||
"http",
|
||||
"infer",
|
||||
"infer 0.19.0",
|
||||
"json-patch 4.2.0",
|
||||
"log",
|
||||
"memchr",
|
||||
|
|
@ -5091,6 +5209,42 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.9.3"
|
||||
source = "git+https://github.com/tauri-apps/tauri?rev=dd6befda925845fc74ca595d6d42de6c49580dd8#dd6befda925845fc74ca595d6d42de6c49580dd8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"ctor 1.0.12",
|
||||
"dom_query 0.28.0",
|
||||
"dunce",
|
||||
"glob",
|
||||
"http",
|
||||
"infer 0.22.0",
|
||||
"json-patch 4.2.0",
|
||||
"log",
|
||||
"memchr",
|
||||
"phf",
|
||||
"plist",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"schemars 0.8.22",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde-untagged",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"swift-rs",
|
||||
"thiserror 2.0.19",
|
||||
"toml 1.1.4+spec-1.1.0",
|
||||
"url",
|
||||
"urlpattern 0.6.0",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-winres"
|
||||
version = "0.3.6"
|
||||
|
|
@ -5146,7 +5300,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-build 2.6.3 (git+https://github.com/tauri-apps/tauri?rev=dd6befda925845fc74ca595d6d42de6c49580dd8)",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-log",
|
||||
"tauri-plugin-notification",
|
||||
|
|
@ -6330,7 +6484,7 @@ dependencies = [
|
|||
"cookie",
|
||||
"crossbeam-channel",
|
||||
"dirs",
|
||||
"dom_query",
|
||||
"dom_query 0.27.0",
|
||||
"dpi",
|
||||
"dunce",
|
||||
"gdkx11",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ name = "mobile_lib"
|
|||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "4af26a3f7f8b692d62cca549bbacd93f5ce90b41", features = [] }
|
||||
tauri-build = { git = "https://github.com/tauri-apps/tauri", rev = "dd6befda925845fc74ca595d6d42de6c49580dd8", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri-plugin-opener = "2"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
import MessageContextMenu from "./messageContextMenu";
|
||||
import Media from "./media/media";
|
||||
import { useStorage } from "@tensamin/storage/context";
|
||||
import { useMTP } from "@tensamin/mtp";
|
||||
import { requireRelaySuccess, useMTP } from "@tensamin/mtp";
|
||||
import { getMessage, useChat } from "../context";
|
||||
import { decryptChatText, encryptChatText } from "@tensamin/crypto/chatSecret";
|
||||
import { log, toast } from "@tensamin/shared/log";
|
||||
|
|
@ -42,6 +42,7 @@ function MessageComponent({
|
|||
user: SelectedUser<readonly ["UserId", "Avatar", "Display"]> | null;
|
||||
}) {
|
||||
const actuallyFailed =
|
||||
Boolean(message.ErrorType) ||
|
||||
(message.failed && message.MessageState === "awaiting") ||
|
||||
message.decryptionFailed;
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ function MessageComponent({
|
|||
|
||||
// Message states
|
||||
const { load } = useStorage();
|
||||
const { send } = useMTP();
|
||||
const { send, sendSealedRelay } = useMTP();
|
||||
const [ownId, setOwnId] = useState(0);
|
||||
useEffect(() => {
|
||||
load("user_id").then(setOwnId);
|
||||
|
|
@ -73,22 +74,38 @@ function MessageComponent({
|
|||
const messageStateReadUpdate = useCallback(async () => {
|
||||
const readConfirmations = await load("settings.read_confirmations");
|
||||
|
||||
if (readConfirmations) {
|
||||
if (!user?.UserId) return;
|
||||
|
||||
await send("MessageState", {
|
||||
ChatPartnerId: user?.UserId,
|
||||
SendTime: message.SendTime,
|
||||
MessageState: "read",
|
||||
});
|
||||
} else {
|
||||
await send("MessageState", {
|
||||
ChatPartnerId: user?.UserId,
|
||||
SendTime: message.SendTime,
|
||||
MessageState: "received",
|
||||
});
|
||||
if (!user?.UserId || !message.RelayMessageId || ownId === 0) return;
|
||||
const [ownIota, peerIota] = await Promise.all([
|
||||
send("GetIotaData", { UserId: ownId }),
|
||||
send("GetIotaData", { UserId: user.UserId }),
|
||||
]);
|
||||
if (ownIota.type !== "GetIotaData" || peerIota.type !== "GetIotaData") {
|
||||
throw new Error("Could not resolve an Iota for this receipt");
|
||||
}
|
||||
}, [load, message.SendTime, user?.UserId, send]);
|
||||
const response = await sendSealedRelay(
|
||||
"MessageState",
|
||||
{
|
||||
ChatPartnerId: user.UserId,
|
||||
RelayMessageId: message.RelayMessageId,
|
||||
EventAt: Date.now(),
|
||||
MessageState: readConfirmations ? "read" : "received",
|
||||
ReceiverId: user.UserId,
|
||||
},
|
||||
{
|
||||
nextHop: { kind: "iota", id: ownIota.data.IotaId },
|
||||
finalRecipientId: user.UserId,
|
||||
metadataRecipients: [
|
||||
{ value: ownIota.data.PublicKey, encoding: "base64" },
|
||||
{ value: peerIota.data.PublicKey, encoding: "base64" },
|
||||
],
|
||||
contentRecipients: [
|
||||
{ value: ownIota.data.PublicKey, encoding: "base64" },
|
||||
{ value: peerIota.data.PublicKey, encoding: "base64" },
|
||||
],
|
||||
},
|
||||
);
|
||||
requireRelaySuccess(response);
|
||||
}, [load, message.RelayMessageId, ownId, send, sendSealedRelay, user]);
|
||||
useEffect(() => {
|
||||
if (message.SenderId === ownId || ownId === 0) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,14 @@ type MessageEdit = Partial<
|
|||
>
|
||||
>;
|
||||
|
||||
const messageStateRank: Record<RawMessage["MessageState"], number> = {
|
||||
awaiting: 0,
|
||||
sending: 0,
|
||||
sent: 1,
|
||||
received: 2,
|
||||
read: 3,
|
||||
};
|
||||
|
||||
function updateMessagesBySendTime<T extends EditableMessage>(
|
||||
messages: T[],
|
||||
sendTime: number,
|
||||
|
|
@ -81,6 +89,13 @@ function updateMessagesBySendTime<T extends EditableMessage>(
|
|||
return item;
|
||||
}
|
||||
|
||||
if (
|
||||
edit.MessageState !== undefined &&
|
||||
messageStateRank[edit.MessageState] < messageStateRank[item.MessageState]
|
||||
) {
|
||||
return item;
|
||||
}
|
||||
|
||||
const entries = Object.entries(edit) as Array<
|
||||
[keyof MessageEdit, MessageEdit[keyof MessageEdit]]
|
||||
>;
|
||||
|
|
@ -983,9 +998,7 @@ export default function Provider({ children }: { children: ReactNode }) {
|
|||
);
|
||||
return;
|
||||
}
|
||||
editMessage(data.SendTime, {
|
||||
MessageState: data.MessageState,
|
||||
});
|
||||
editMessage(data.SendTime, { MessageState: data.MessageState });
|
||||
});
|
||||
return () => {
|
||||
unsubscribeEdit();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ async function requestNotificationPermission() {
|
|||
}
|
||||
|
||||
export default function Provider(props: { children: React.ReactNode }) {
|
||||
const { subscribe, send } = useMTP();
|
||||
const { subscribe } = useMTP();
|
||||
const { load } = useStorage();
|
||||
const { get } = useUser();
|
||||
const { addLiveMessage, chatSecret, getChatSecret, userId } = useChat();
|
||||
|
|
@ -79,11 +79,6 @@ export default function Provider(props: { children: React.ReactNode }) {
|
|||
// todo: add notification symbol to conversation cards (incl. message start)
|
||||
moveUserIdToTop(data.SenderId);
|
||||
|
||||
if (await load("settings.receive_confirmations")) {
|
||||
void send("MessageState", {
|
||||
MessageState: "received",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const user = await get(data.SenderId, [
|
||||
|
|
@ -180,7 +175,6 @@ export default function Provider(props: { children: React.ReactNode }) {
|
|||
load,
|
||||
location.pathname,
|
||||
navigate,
|
||||
send,
|
||||
moveUserIdToTop,
|
||||
subscribe,
|
||||
getChatSecret,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ const callSecretEnvelopeRequest = z.object({
|
|||
export const Reaction = z.object({
|
||||
Reaction: z.string(),
|
||||
SenderId: z.number(),
|
||||
RelayMessageId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const Message = z.object({
|
||||
|
|
@ -82,6 +83,8 @@ export const Message = z.object({
|
|||
Avatar: z.boolean().optional(),
|
||||
Display: z.boolean().optional(),
|
||||
ReplyId: z.number().optional(),
|
||||
UpdatedAt: z.number().optional(),
|
||||
ErrorType: z.string().optional(),
|
||||
MessageState: z
|
||||
.enum(["read", "received", "sent", "sending", "awaiting"]) // awaiting for 'internal' use
|
||||
.default("received"),
|
||||
|
|
@ -107,6 +110,7 @@ const authPayload = z.object({
|
|||
.array(
|
||||
z.object({
|
||||
LastMessageAt: z.number().default(0),
|
||||
CreatedAt: z.number().optional(),
|
||||
UserId: z.number(),
|
||||
LastMessage: z
|
||||
.object({
|
||||
|
|
@ -397,17 +401,12 @@ export const mtp = {
|
|||
response: z.object({}),
|
||||
},
|
||||
MessageState: {
|
||||
request: z
|
||||
.object({
|
||||
ChatPartnerId: z.number(),
|
||||
SendTime: z.number(),
|
||||
MessageState: Message.shape.MessageState,
|
||||
})
|
||||
.or(
|
||||
z.object({
|
||||
MessageState: Message.shape.MessageState,
|
||||
}),
|
||||
),
|
||||
request: z.object({
|
||||
ChatPartnerId: z.number(),
|
||||
RelayMessageId: z.string(),
|
||||
EventAt: z.number(),
|
||||
MessageState: z.enum(["received", "read"]),
|
||||
}),
|
||||
response: z.object({
|
||||
ChatPartnerId: z.number(),
|
||||
MessageState: Message.shape.MessageState,
|
||||
|
|
|
|||
Loading…
Reference in a new issue