(feat): add mobile notifications
Some checks failed
/ build-web (push) Successful in 8m31s
/ build-desktop (linux) (push) Successful in 14m5s
/ release (push) Has been cancelled
/ build-mobile (push) Has been cancelled

(feat): improve mobile ui & ux
This commit is contained in:
Alois 2026-08-05 16:19:46 +02:00
commit 13fa3d8db7
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
29 changed files with 6638 additions and 6094 deletions

View file

@ -32,7 +32,7 @@ export default function LegalPage({
});
return (
<div className="mx-auto flex min-h-[calc(100dvh-17rem)] w-full max-w-5xl flex-col gap-10 p-10 py-20 md:min-h-[calc(100dvh-20.5rem)] md:p-24">
<div className="mx-auto flex min-h-[calc(100dvh-17rem)] w-full max-w-5xl flex-col gap-10 p-2 py-20 md:min-h-[calc(100dvh-20.5rem)] md:p-24">
<div className="flex flex-1 items-center justify-center">
<div className="flex flex-col items-start gap-2">
<BigCheckbox

View file

@ -0,0 +1,99 @@
import { useEffect, useState } from "react";
import { Button, useOnboardingStep } from "@methanium/ui";
import { invoke } from "@tauri-apps/api/core";
import {
isPermissionGranted,
requestPermission,
} from "@tauri-apps/plugin-notification";
import { BatteryCharging, Bell } from "lucide-react";
export default function TauriPermissionsPage() {
const [notificationsGranted, setNotificationsGranted] = useState(false);
const [batteryExempt, setBatteryExempt] = useState(false);
const [notificationAttempted, setNotificationAttempted] = useState(false);
const [batteryAttempted, setBatteryAttempted] = useState(false);
useEffect(() => {
const refresh = () => {
void Promise.all([
isPermissionGranted(),
invoke<boolean>("mtp_is_ignoring_battery_optimizations"),
]).then(([notifications, battery]) => {
setNotificationsGranted(notifications);
setBatteryExempt(battery);
});
};
refresh();
window.addEventListener("focus", refresh);
document.addEventListener("visibilitychange", refresh);
const interval = window.setInterval(refresh, 1_000);
return () => {
window.removeEventListener("focus", refresh);
document.removeEventListener("visibilitychange", refresh);
window.clearInterval(interval);
};
}, []);
useOnboardingStep({
canContinue:
(notificationsGranted || notificationAttempted) &&
(batteryExempt || batteryAttempted),
onContinue: async () => {
await invoke("mtp_set_enabled", { enabled: true });
},
});
return (
<div className="mx-auto flex w-full max-w-xl flex-col gap-12 py-6">
<div className="flex flex-col gap-3">
<div className="flex items-center gap-3">
<div>
<Bell className="h-6! w-6!" />
</div>
<div>
<h3 className="font-semibold">Allow notifications</h3>
<p className="text-muted-foreground text-sm">
Allow Tensamin to notify you while it's closed.
</p>
</div>
</div>
<Button
variant={notificationsGranted ? "outline" : "default"}
disabled={notificationsGranted}
onClick={() => {
setNotificationAttempted(true);
void requestPermission().then((permission) => {
setNotificationsGranted(permission === "granted");
});
}}
>
{notificationsGranted ? "Allowed" : "Allow notifications"}
</Button>
</div>
<div className="flex flex-col gap-3">
<div className="flex items-center gap-3">
<div>
<BatteryCharging className="h-6! w-6!" />
</div>
<div>
<h3 className="font-semibold">Allow running in the background</h3>
<p className="text-muted-foreground text-sm">
Exclude Tensamin from battery optimisation so Android does not
suspend it's connection for decryption of live messages.
</p>
</div>
</div>
<Button
variant={batteryExempt ? "outline" : "default"}
disabled={batteryExempt}
onClick={() => {
setBatteryAttempted(true);
void invoke("mtp_request_battery_exemption");
}}
>
{batteryExempt ? "Allowed" : "Open battery prompt"}
</Button>
</div>
</div>
);
}