(feat): remove mtp loading screen
Some checks failed
/ build-web (push) Failing after 4m35s
/ build-desktop (linux) (push) Failing after 4m37s
/ build-mobile (push) Failing after 6m40s
/ release (push) Has been skipped

(fix): weird dedupe bugs
(qol): update todo
This commit is contained in:
Alois 2026-07-03 21:49:13 +02:00
commit 69149b73bd
6 changed files with 86 additions and 61 deletions

View file

@ -25,13 +25,13 @@ import CallPopout from "@tensamin/call/popout";
import ChatContext from "@tensamin/chat/context";
import { useInitializeCall } from "@tensamin/call/store";
import { Provider as MTPProvider } from "@tensamin/mtp";
import UserContext from "@tensamin/user/context";
import UserProvider from "@tensamin/user/context";
import DeeplinkContext from "@tensamin/tauri/deeplinkHandler";
import NotificationsProvider from "@tensamin/notifications/context";
import TAuthWrapper from "@tensamin/tauth/context";
import { ThemeProvider, useTheme } from "@tensamin/ui";
import { ErrorScreen, ThemeProvider, useTheme } from "@tensamin/ui";
import z from "zod";
import { useEffect, useRef, useState, type ReactNode } from "react";
@ -256,7 +256,7 @@ function AppShell() {
return (
<MTPProvider>
<Session>
<UserContext>
<UserProvider>
<CallInit />
<CallPopout />
<TAuthWrapper>
@ -268,7 +268,7 @@ function AppShell() {
</ChatContext>
</AppLayout>
</TAuthWrapper>
</UserContext>
</UserProvider>
</Session>
</MTPProvider>
);
@ -281,6 +281,12 @@ function CallInit() {
const rootRoute = createRootRoute({
component: RootShell,
errorComponent: ({ error }: { error: Error }) => (
<ErrorScreen
description={error.message}
error={"Error in TanStack Router: " + error.name}
/>
),
});
const appRoute = createRoute({

View file

@ -114,6 +114,9 @@ export default defineConfig({
"@tensamin/crypto",
"@tensamin/storage",
"@tensamin/mtp",
"@tensamin/user",
"@tensamin/tauri",
"@tensamin/chat",
"@codemirror/commands",
"@codemirror/lang-markdown",
"@codemirror/state",

View file

@ -10,8 +10,11 @@ import {
} from "react";
import { isTauri } from "@tauri-apps/api/core";
import { onResume } from "tauri-plugin-app-events-api";
import { ConnectionState, MTPClient } from "mtp";
import type { z } from "zod";
import { ConnectionState, MTPClient, codec } from "mtp";
import { type z } from "zod";
import createAsyncQueue, {
createQueuedFunc,
} from "@tensamin/shared/asyncQueue";
import {
type Calls,
@ -20,9 +23,8 @@ import {
mtp as schemas,
type MTP as Schemas,
} from "@tensamin/shared/data";
import { log } from "@tensamin/shared/log";
import { log, toast } from "@tensamin/shared/log";
import { useStorage } from "@tensamin/storage/context";
import { ErrorScreen, LoadingScreen as Loading } from "@tensamin/ui";
import {
PING_INTERVAL,
@ -91,6 +93,8 @@ type ContextType = {
freshContacts: Contacts;
freshCommunities: Communities;
freshCalls: Calls;
contextReady: boolean;
loadingDescription: string;
};
const MTPContext = createContext<ContextType | undefined>(undefined);
@ -161,9 +165,6 @@ export function Provider(props: {
const [ownPing, setOwnPing] = useState<number>(0);
const [iotaPing, setIotaPing] = useState<number>(0);
const [error, setError] = useState("");
const [errorDescription, setErrorDescription] = useState("");
const [freshCommunities, setFreshCommunities] = useState<Communities>([]);
const [freshContacts, setFreshContacts] = useState<Contacts>([]);
const [freshCalls, setFreshCalls] = useState<Calls>([]);
@ -234,9 +235,10 @@ export function Provider(props: {
return subscribe("error_no_iota", () => {
setIdentified(false);
setIdentifying(false);
setError("We couldn't reach your Iota");
setErrorDescription(
"You could try to restart your Iota, check for updates or check your network connection.",
toast(
"error",
"We couldn't reach your Iota",
"Check your network connection and try restarting your Iota",
);
});
}, [connected, subscribe]);
@ -303,9 +305,10 @@ export function Provider(props: {
if (disposed || reconnectScheduled) return;
if (attempts >= RECONNECT_TRIES) {
setError("Connection Failed");
setErrorDescription(
"Unable to connect to the server after multiple attempts. Please check your internet connection or try again later.",
toast(
"error",
"Connection Failed",
"Unable to connect to the Omikron after multiple attempts. Cehck your network connection.",
);
log(0, "mtp", "red", "Reconnection attempts exhausted", reason);
return;
@ -321,15 +324,16 @@ export function Provider(props: {
};
async function connect() {
if (disposed || props.blockConnection) {
return;
}
if (disposed || props.blockConnection) return;
try {
setIdentified(false);
setIdentifying(false);
await MTPClient.init();
const rawOmikronData = await fetch(mtpUrl ?? "").then((res) =>
codec.decode(res.arrayBuffer()),
);
const client = await MTPClient.create({
url: mtpUrl ?? "",
descriptor: "client",
@ -383,8 +387,6 @@ export function Provider(props: {
scheduleReconnectReset();
setReadyState(client.state);
setIdentifying(true);
setError("");
setErrorDescription("");
await client.auth();
const finalResponse = await authPayload;
@ -427,9 +429,6 @@ export function Provider(props: {
clearReconnectResetTimer();
attempts = 0;
reconnectScheduled = false;
setError("");
setErrorDescription("");
await connect();
}
@ -459,53 +458,39 @@ export function Provider(props: {
};
}, [mtpUrl, props.blockConnection]);
// Loading bar
const progress = useMemo(() => {
if (!mtpUrl) return 10;
if (readyState === ConnectionState.Connecting) return 30;
if (!connected) return 45;
if (identifying) return 75;
if (!identified) return 90;
return 100;
}, [connected, identified, identifying, readyState, mtpUrl]);
const loadingTitle = useMemo(() => {
if (!mtpUrl) return "Looking up configuration";
if (readyState === ConnectionState.Connecting || !connected)
return "Connecting to Tensamin";
if (identifying || !identified) return "Identifying secure session";
return "Loading";
}, [connected, identified, identifying, readyState, mtpUrl]);
// Async queue
const loadingDescription = useMemo(() => {
if (!mtpUrl) return "Loading connection details";
if (readyState === ConnectionState.Connecting || !connected) {
return "Establishing transport channel";
}
if (identifying || !identified) return "Waiting for authenticated session";
return undefined;
return "Loading...";
}, [connected, identified, identifying, readyState, mtpUrl]);
// Return
if (error !== "" && errorDescription !== "") {
return <ErrorScreen error={error} description={errorDescription} />;
}
if (!connected || !identified || !mtpUrl) {
return (
<Loading
progress={progress}
title={loadingTitle}
description={loadingDescription}
fullscreen
/>
);
}
const contextReady = connected && identified && mtpUrl !== null;
const mtpRef = useMemo(
() =>
createAsyncQueue<{
send: typeof send;
subscribe: typeof subscribe;
subscribePush: typeof subscribePush;
}>(),
[],
);
useEffect(() => {
if (connected && identified && mtpUrl) {
mtpRef.set({
send,
subscribe,
subscribePush,
});
}
}, [connected, identified, mtpUrl, send, subscribe, subscribePush, mtpRef]);
return (
<MTPContext.Provider
value={{
send,
send: createQueuedFunc(() => (contextReady ? send : null)),
subscribe,
subscribePush,
readyState,
@ -515,6 +500,8 @@ export function Provider(props: {
freshContacts,
freshCommunities,
freshCalls,
contextReady,
loadingDescription,
}}
>
{props.children}

1
packages/mtp/todo.md Normal file
View file

@ -0,0 +1 @@
- Get omikron url & public key from omega

View file

@ -4,6 +4,7 @@
"version": "0.0.0",
"type": "module",
"exports": {
"./asyncQueue": "./src/asyncQueue.ts",
"./code": "./src/code.ts",
"./data": "./src/data.ts",
"./desktopMedia": "./src/desktopMedia.tsx",

View file

@ -0,0 +1,27 @@
export default function createAsyncQueue<T>() {
let resolve!: (value: T) => void;
const promise = new Promise<T>((r) => {
resolve = r;
});
return {
set: resolve,
get: () => promise,
};
}
// eslint-disable-next-line
type AnyFn = (...args: any[]) => any;
export function createQueuedFunc<F extends AnyFn>(
getFn: () => F | null | undefined,
) {
return (async (...args: Parameters<F>): Promise<Awaited<ReturnType<F>>> => {
while (!getFn()) {
await new Promise((r) => setTimeout(r, 50));
}
return await getFn()!(...args);
}) as F;
}