Compare commits

..
3 Commits
Author SHA1 Message Date
Lotus CIandClaude Opus 5.5 4a9823890b feat(desktop): "Start minimized" setting under Launch on login (cinny-desktop #3)
CI / Build & Quality Checks (push) Successful in 5m19s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 24s
CI / Trigger Desktop Build (push) Successful in 9s
CI / Playwright smoke (e2e) (push) Successful in 15m37s
Shown only while Launch on login is on, and only when the native side
answers `get_start_minimized` (older desktop builds just don't show it).
Toggling calls `set_start_minimized`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-23 22:46:10 -04:00
Lotus CIandClaude Opus 5.5 e80b170fd1 fix(sw): only register the service worker on http(s) pages
register() rejects on non-http(s) origins, and the rejection was
unhandled. The desktop app's debug build loads from tauri://localhost,
which surfaced as a Sentry "serviceWorker.register() must be called with
a script URL whose protocol is either HTTP or HTTPS". Skip registration
there, and catch any other failure (e.g. SWs disabled) with a warning.
The app works without a SW.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-23 22:46:05 -04:00
Lotus CIandClaude Opus 5.5 76929a8763 docs(embeds): SoundCloud short links already embed via og:url (#200)
CI / Build & Quality Checks (push) Successful in 4m47s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 17s
CI / Trigger Desktop Build (push) Successful in 6s
CI / Playwright smoke (e2e) (push) Canceled after 4m39s
The comment said on.soundcloud.com links need an oEmbed round-trip. They
don't: Synapse follows the redirect for the preview and the og:url
fallback re-parses the canonical track URL. Checked with a real short
link (the play facade loads the w.soundcloud player).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-23 22:09:34 -04:00
3 changed files with 40 additions and 5 deletions
@@ -161,11 +161,19 @@ function DesktopChromeSetting() {
*/
function AutostartSetting() {
const [enabled, setEnabled] = useState(false);
// [cinny-desktop #3] null until the native side answers (older builds don't
// have the command, so the switch just stays hidden there).
const [startMinimized, setStartMinimized] = useState<boolean | null>(null);
useEffect(() => {
tauriInvoke()?.('plugin:autostart|is_enabled')
.then((value) => setEnabled(value === true))
.catch(() => undefined);
tauriInvoke()?.('get_start_minimized')
.then((value) => {
if (typeof value === 'boolean') setStartMinimized(value);
})
.catch(() => undefined);
}, []);
const handleChange = (value: boolean) => {
@@ -173,6 +181,11 @@ function AutostartSetting() {
setEnabled(value);
};
const handleStartMinimized = (value: boolean) => {
invokeTauri('set_start_minimized', { value });
setStartMinimized(value);
};
if (!isTauriEnv()) return null;
return (
<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
@@ -181,6 +194,15 @@ function AutostartSetting() {
description="Start Lotus Chat automatically when you sign in to your computer."
after={<Switch variant="Primary" value={enabled} onChange={handleChange} />}
/>
{enabled && startMinimized !== null && (
<SettingTile
title="Start minimized"
description="When it starts at login, keep Lotus Chat in the system tray instead of opening the window. Notifications still arrive; click the tray icon to open it."
after={
<Switch variant="Primary" value={startMinimized} onChange={handleStartMinimized} />
}
/>
)}
</SequenceCard>
);
}
+5 -3
View File
@@ -363,9 +363,11 @@ const SOUNDCLOUD_PROFILE_TABS = new Set([
export function isSoundCloudTrack(url: string): boolean {
try {
const { hostname, pathname } = new URL(url);
// NOTE: on.soundcloud.com short links are NOT handled here — the w.soundcloud
// widget resolver doesn't follow the redirect; supporting them needs an oEmbed
// round-trip (soundcloud.com/oembed is CORS-enabled) to get the canonical URL.
// on.soundcloud.com short links are not matched here (the w.soundcloud widget
// doesn't follow the redirect), but they still embed: Synapse follows the
// redirect when building the preview, and UrlPreviewCard's og:url fallback
// re-parses the canonical soundcloud.com/<artist>/<track> URL (verified with
// a real short link, Gitea #200).
if (hostname.replace(/^www\./, '') !== 'soundcloud.com') return false;
// /<artist>/<track|sets/set> — at least two segments, not a bare profile
const parts = pathname
+13 -2
View File
@@ -22,7 +22,14 @@ import { cleanupSearchCacheIfSignedOut } from './client/initMatrix';
document.body.classList.add(configClass, varsClass);
// Register Service Worker
if ('serviceWorker' in navigator) {
// Service workers only register on http(s) pages. The desktop app loads from
// `tauri://localhost` in debug builds (and on any platform where the localhost
// plugin isn't used), where register() rejects: that surfaced in Sentry as an
// unhandled "must be called with a script URL whose protocol is either HTTP or
// HTTPS". Skip it there; the app works without a SW, only authenticated media
// falls back to the client's own fetch.
const swProtocolOk = window.location.protocol === 'https:' || window.location.protocol === 'http:';
if ('serviceWorker' in navigator && swProtocolOk) {
const swUrl =
import.meta.env.MODE === 'production'
? `${trimTrailingSlash(import.meta.env.BASE_URL)}/sw.js`
@@ -39,7 +46,11 @@ if ('serviceWorker' in navigator) {
// never route. Production sw.js is a classic bundled script.
navigator.serviceWorker
.register(swUrl, import.meta.env.MODE === 'production' ? undefined : { type: 'module' })
.then(sendSessionToSW);
.then(sendSessionToSW)
.catch((err) => {
// e.g. a private window with SWs disabled; the app still works.
console.warn('Service worker registration failed', err);
});
navigator.serviceWorker.ready.then(sendSessionToSW);
navigator.serviceWorker.addEventListener('message', (ev) => {