(qol): add delete mobile app script
All checks were successful
/ deploy (push) Successful in 14m53s

(qol): updated todos
(fix): small px-2 that shouldn't be there
(feat): turn focus reconnect into a continuous reconnect
This commit is contained in:
Alois 2026-05-10 00:08:54 +02:00
commit 30722b6168
14 changed files with 93 additions and 9 deletions

View file

@ -4573,6 +4573,18 @@ dependencies = [
"walkdir", "walkdir",
] ]
[[package]]
name = "tauri-plugin-app-events"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e625f35abcfc422c7c4af8b348d2069cdf387a39c12429fdce570137d02f069"
dependencies = [
"serde",
"tauri",
"tauri-plugin",
"thiserror 1.0.69",
]
[[package]] [[package]]
name = "tauri-plugin-barcode-scanner" name = "tauri-plugin-barcode-scanner"
version = "2.4.4" version = "2.4.4"
@ -4834,6 +4846,7 @@ dependencies = [
"serde_json", "serde_json",
"tauri", "tauri",
"tauri-build 2.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "tauri-build 2.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tauri-plugin-app-events",
"tauri-plugin-barcode-scanner", "tauri-plugin-barcode-scanner",
"tauri-plugin-deep-link", "tauri-plugin-deep-link",
"tauri-plugin-opener", "tauri-plugin-opener",

View file

@ -50,6 +50,7 @@ default-features = false
[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies]
tauri-plugin-barcode-scanner = "2" tauri-plugin-barcode-scanner = "2"
tauri-plugin-app-events = "0.2"
[patch.crates-io.tauri] [patch.crates-io.tauri]
git = "https://github.com/tauri-apps/tauri" git = "https://github.com/tauri-apps/tauri"

View file

@ -9,6 +9,7 @@
], ],
"permissions": [ "permissions": [
"deep-link:default", "deep-link:default",
"app-events:default",
"barcode-scanner:default", "barcode-scanner:default",
"barcode-scanner:allow-scan", "barcode-scanner:allow-scan",
"barcode-scanner:allow-cancel" "barcode-scanner:allow-cancel"

View file

@ -1,3 +1,5 @@
import com.android.build.gradle.LibraryExtension
buildscript { buildscript {
repositories { repositories {
google() google()
@ -16,7 +18,16 @@ allprojects {
} }
} }
subprojects {
afterEvaluate {
plugins.withId("com.android.library") {
extensions.configure<LibraryExtension>("android") {
compileSdk = 36
}
}
}
}
tasks.register("clean").configure { tasks.register("clean").configure {
delete("build") delete("build")
} }

View file

@ -206,6 +206,9 @@ pub fn run() {
#[cfg(any(target_os = "ios", target_os = "android"))] #[cfg(any(target_os = "ios", target_os = "android"))]
let builder = builder.plugin(tauri_plugin_barcode_scanner::init()); let builder = builder.plugin(tauri_plugin_barcode_scanner::init());
#[cfg(any(target_os = "ios", target_os = "android"))]
let builder = builder.plugin(tauri_plugin_app_events::init());
if let Err(error) = builder if let Err(error) = builder
.setup(|_app| { .setup(|_app| {
#[cfg(any(target_os = "linux", windows))] #[cfg(any(target_os = "linux", windows))]

View file

@ -42,6 +42,7 @@
"tailwind-merge": "^3.5.0", "tailwind-merge": "^3.5.0",
"tailwind-scrollbar-hide": "^4.0.0", "tailwind-scrollbar-hide": "^4.0.0",
"tailwindcss": "^4.2.4", "tailwindcss": "^4.2.4",
"tauri-plugin-app-events-api": "^0.2.0",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
"zod": "^4.3.6" "zod": "^4.3.6"
}, },

View file

@ -76,6 +76,7 @@
"tailwind-merge": "^3.5.0", "tailwind-merge": "^3.5.0",
"tailwind-scrollbar-hide": "^4.0.0", "tailwind-scrollbar-hide": "^4.0.0",
"tailwindcss": "^4.2.4", "tailwindcss": "^4.2.4",
"tauri-plugin-app-events-api": "^0.2.0",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
"zod": "^4.3.6", "zod": "^4.3.6",
}, },
@ -228,6 +229,7 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@tanstack/react-router": "^1.0.0", "@tanstack/react-router": "^1.0.0",
"@tauri-apps/api": "^2",
"@tensamin/crypto": "workspace:*", "@tensamin/crypto": "workspace:*",
"@tensamin/shared": "workspace:*", "@tensamin/shared": "workspace:*",
"@tensamin/storage": "workspace:*", "@tensamin/storage": "workspace:*",
@ -235,6 +237,7 @@
"@tensamin/ui": "*", "@tensamin/ui": "*",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"tauri-plugin-app-events-api": "^0.2.0",
"zod": "^4.3.6", "zod": "^4.3.6",
}, },
"devDependencies": { "devDependencies": {
@ -1497,6 +1500,8 @@
"tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
"tauri-plugin-app-events-api": ["tauri-plugin-app-events-api@0.2.0", "", { "dependencies": { "@tauri-apps/api": "^2.0.3" } }, "sha512-CnlAeucWhT+Rgx6CCsqUpq2D3pqgx0fhjSPKomH7O2t1rGVu5kGLMkYvaCX6gqVTUYpIWX5BLV7LGY2DRri0QA=="],
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
"tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="], "tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="],

View file

@ -22,7 +22,8 @@
"dev:mobile": "cd apps/tauri && bun dev:mobile", "dev:mobile": "cd apps/tauri && bun dev:mobile",
"build:mobile": "cd apps/tauri && bun run build:mobile", "build:mobile": "cd apps/tauri && bun run build:mobile",
"dev:desktop": "cd apps/tauri && bun dev:desktop", "dev:desktop": "cd apps/tauri && bun dev:desktop",
"build:desktop": "cd apps/tauri && bun run build:desktop" "build:desktop": "cd apps/tauri && bun run build:desktop",
"delete:mobile": "cd apps/tauri && nix develop --command adb uninstall net.tensamin.client"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",

View file

@ -431,7 +431,7 @@ export default function Screen() {
} }
return ( return (
<div className="relative flex h-full min-h-0 w-full flex-col overflow-hidden px-2"> <div className="relative flex h-full min-h-0 w-full flex-col overflow-hidden">
<div <div
ref={scrollRef} ref={scrollRef}
id="chat_container" id="chat_container"

View file

@ -0,0 +1 @@
- Improve the Input box

View file

@ -1 +1,2 @@
- Add `notifications: number` to contacts - Add `notifications: number` to contacts
- Store private key in a device bound session

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

@ -0,0 +1 @@
- Finish TAuth SDK

View file

@ -18,8 +18,10 @@
"@tensamin/storage": "workspace:*", "@tensamin/storage": "workspace:*",
"@tensamin/shared": "workspace:*", "@tensamin/shared": "workspace:*",
"@tensamin/ui": "*", "@tensamin/ui": "*",
"@tauri-apps/api": "^2",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"tauri-plugin-app-events-api": "^0.2.0",
"zod": "^4.3.6" "zod": "^4.3.6"
}, },
"devDependencies": { "devDependencies": {

View file

@ -16,6 +16,8 @@ import {
READY_STATE, READY_STATE,
type BoundSendFn, type BoundSendFn,
} from "@tensamin/ttp-core"; } from "@tensamin/ttp-core";
import { isTauri } from "@tauri-apps/api/core";
import { onResume } from "tauri-plugin-app-events-api";
import type { PushHandler } from "@tensamin/ttp-core"; import type { PushHandler } from "@tensamin/ttp-core";
import { import {
PING_INTERVAL, PING_INTERVAL,
@ -141,6 +143,10 @@ function getProtocolErrorDetails(error: unknown) {
}; };
} }
function isTauriMobile() {
return isTauri() && /Android|iPhone|iPad|iPod/.test(navigator.userAgent);
}
type ContextType = { type ContextType = {
send: BoundSendFn<Schemas>; send: BoundSendFn<Schemas>;
subscribePush: (handler: PushHandler) => () => void; subscribePush: (handler: PushHandler) => () => void;
@ -186,7 +192,6 @@ export function Provider(props: {
typeof createTransportClient<Schemas> typeof createTransportClient<Schemas>
> | null>(null); > | null>(null);
const identificationStartedRef = useRef(false); const identificationStartedRef = useRef(false);
const reconnectExhaustedRef = useRef(false);
/** /**
* Sends typed protocol messages through the active transport client. * Sends typed protocol messages through the active transport client.
@ -266,6 +271,8 @@ export function Provider(props: {
let reconnectResetTimer: ReturnType<typeof setTimeout> | null = null; let reconnectResetTimer: ReturnType<typeof setTimeout> | null = null;
let reconnectScheduled = false; let reconnectScheduled = false;
let disposed = false; let disposed = false;
let resumeListenerRegistered = false;
let currentReadyState: number = READY_STATE.CLOSED;
/** /**
* Clears any scheduled reconnect timeout and resets scheduling flags. * Clears any scheduled reconnect timeout and resets scheduling flags.
@ -316,14 +323,12 @@ export function Provider(props: {
return; return;
} }
if (reconnectExhaustedRef.current || attempts >= RECONNECT_TRIES) { if (attempts >= RECONNECT_TRIES) {
reconnectExhaustedRef.current = true;
setError("Connection Failed"); setError("Connection Failed");
setErrorDescription( setErrorDescription(
"Unable to connect to the server after multiple attempts. Please check your internet connection or try again later.", "Unable to connect to the server after multiple attempts. Please check your internet connection or try again later.",
); );
log(0, "ttp", "red", "Reconnection attempts exhausted", reason); log(0, "ttp", "red", "Reconnection attempts exhausted", reason);
void transportClient?.close("reconnect-exhausted");
return; return;
} }
@ -340,12 +345,12 @@ export function Provider(props: {
? createTransportClient(schemas, { ? createTransportClient(schemas, {
url: TRANSPORT_URL, url: TRANSPORT_URL,
onReadyStateChange: (state) => { onReadyStateChange: (state) => {
currentReadyState = state;
setReadyState(state); setReadyState(state);
if (state === READY_STATE.OPEN) { if (state === READY_STATE.OPEN) {
clearReconnectTimer(); clearReconnectTimer();
scheduleReconnectReset(); scheduleReconnectReset();
reconnectExhaustedRef.current = false;
identificationStartedRef.current = false; identificationStartedRef.current = false;
setConnected(true); setConnected(true);
setIdentified(false); setIdentified(false);
@ -383,7 +388,7 @@ export function Provider(props: {
* @returns Promise that resolves after one connection attempt. * @returns Promise that resolves after one connection attempt.
*/ */
async function connect() { async function connect() {
if (disposed || reconnectExhaustedRef.current) { if (disposed) {
return; return;
} }
@ -399,18 +404,56 @@ export function Provider(props: {
} }
} }
/**
* Starts a reconnect after resume only when the transport is disconnected.
* @returns Promise that resolves after any needed resume reconnect starts.
*/
async function reconnectAfterResume() {
if (disposed || !transportClient) {
return;
}
if (
currentReadyState === READY_STATE.OPEN ||
currentReadyState === READY_STATE.CONNECTING
) {
return;
}
clearReconnectTimer();
clearReconnectResetTimer();
attempts = 0;
reconnectScheduled = false;
setError("");
setErrorDescription("");
await connect();
}
void connect(); void connect();
if (!props.blockConnection && isTauriMobile()) {
resumeListenerRegistered = true;
onResume(() => {
void reconnectAfterResume();
});
}
return () => { return () => {
disposed = true; disposed = true;
clearReconnectTimer(); clearReconnectTimer();
clearReconnectResetTimer(); clearReconnectResetTimer();
if (resumeListenerRegistered) {
onResume();
}
if (clientRef.current === transportClient) { if (clientRef.current === transportClient) {
clientRef.current = null; clientRef.current = null;
} }
void transportClient?.close("context-dispose"); void transportClient?.close("context-dispose");
currentReadyState = READY_STATE.CLOSED;
setReadyState(READY_STATE.CLOSED); setReadyState(READY_STATE.CLOSED);
setConnected(false); setConnected(false);
setIdentified(false); setIdentified(false);