feat: seasonal theme overlays + improved animated chat backgrounds

Adds 11 CSS-only seasonal overlays (Halloween, Christmas, New Year, Autumn,
April Fool's, Lunar New Year, Valentine's Day, St. Patrick's Day, Earth Day,
Deep Space, Retro Arcade) with date-based auto-detection and a manual override
dropdown in Settings → Appearance → Seasonal Theme. All themes respect
prefers-reduced-motion. SeasonalEffect mounts at z-index 9997 in App.tsx.

Also rewrites all 5 animated chat background keyframes for smoother, more
organic motion: Digital Rain gains a phosphor glow flicker; Star Drift now
loops each layer by exactly its own tile size (no more seam); Grid Pulse adds
an independent brightness oscillation at a prime period; Aurora Flow drives
all four gradient layers through distinct paths; Fireflies adds glow-pulse and
opacity-blink animations at prime periods for unsynchronised bioluminescence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 00:33:04 -04:00
parent 107921e0d0
commit 6db07f1371
10 changed files with 1426 additions and 201 deletions
+76 -47
View File
@@ -1,69 +1,98 @@
# Lotus Chat — Bug Report & Technical Audit
**Date:** June 2026
This document tracks identified bugs, edge cases, and architectural discrepancies.
This document tracks identified bugs, edge cases, and architectural discrepancies found during the audit of the Lotus Chat codebase. Recommended fixes are provided for each item.
---
## ✅ Resolved Issues (Recently Fixed)
## 🛡️ Critical Security & Privacy Regressions
- **GIF Sending Bypasses E2EE**: Fixed in `RoomInput.tsx`.
- **Scheduled Messages Bypass E2EE**: Fixed in `scheduledMessages.ts`.
- **Drag-and-Drop Overlay Persistence**: Fixed in `useFileDrop.ts`.
- **Stale Member List in Verification Banner**: Fixed in `useDeviceVerificationStatus.ts`.
- **Incomplete Python Comment Highlighting**: Fixed in `syntaxHighlight.ts`.
- **Search Button Hidden in E2EE Rooms**: Fixed in `RoomViewHeader.tsx`.
- **TDS Design Law Violations (Hardcoded Hex)**: Fixed in `GifPicker.tsx` and `VoiceMessageRecorder.tsx`.
- **Recent Emoji Sort Order**: Fixed in `recent-emoji.ts` (recency order, not frequency).
- **Encrypted Search Misses Historic Events**: Fixed in `useLocalMessageSearch.ts`.
- **Presence Updater Base URL Hack**: Fixed in `usePresenceUpdater.ts`.
- **Presence Badge Accessibility**: Fixed in `Presence.tsx` (`aria-label` on badge).
- **Presence Updater Wipes Custom Status**: Fixed in `usePresenceUpdater.ts` (removed `status_msg: ''`).
- **Manifest Main Icon Paths 404**: Fixed in `public/manifest.json` (`./public/android/``./res/android/`). Shortcut icon was already correct.
### 1. E2EE Bypass in Media Gallery Downloads
**File:** `src/app/features/room/MediaGallery.tsx` (Line 855)
**Status:** **CRITICAL**
* **Issue:** The "Download" button in the Files tab uses `mxcUrlToHttp` directly and clicks an `<a>` link.
* **Impact:** In encrypted rooms, this downloads the encrypted ciphertext rather than the decrypted file. Users cannot open the downloaded files.
* **Recommended Fix:**
1. Check if the event is encrypted.
2. If encrypted, use the `decryptAttachment` logic (similar to `useDecryptedMediaUrl`) to decrypt the file in memory.
3. Use `file-saver` or a Blob URL to trigger the download of the decrypted plaintext.
### 2. Privacy Leak in URL Previews
**File:** `src/app/components/url-preview/UrlPreviewCard.tsx` (Line 1655)
**Status:** **PRIVACY RISK**
* **Issue:** Generic URL preview cards fetch favicons directly from `https://www.google.com/s2/favicons?domain=...`.
* **Impact:** This leaks the user's browsing/chat activity (domains of links they see) to Google. It bypasses the "proxied through Matrix" privacy standard.
* **Recommended Fix:** Use the proxy URL returned by the Matrix `/_matrix/media/v3/preview_url` endpoint instead of contacting Google directly.
---
## 🛡️ Critical Security & Logic
## 🚩 Functional & Logic Bugs
### 1. Edit History Broken for E2EE
### 1. Presence Updater Reverts Status Updates
**File:** `src/app/hooks/usePresenceUpdater.ts` (Line 20)
**Status:** High Priority
**File:** `src/app/features/room/message/EditHistoryModal.tsx`
**Status:** **FIXED**
* **Issue:** The `storedStatus` variable is captured once when the `useEffect` starts.
* **Impact:** If a user updates their status message in the Profile settings, the presence updater hook continues to use the *old* status message from its closure. Every time the user moves their mouse/activity, the hook sends `setOnline` with the stale status, reverting the user's change.
* **Recommended Fix:**
1. Read the status from `localStorage` inside the `setOnline`/`setUnavailable` functions rather than at the top of the effect.
- **Issue:** The modal fetches edit history via raw `fetch`. Edit events not found in the room cache were constructed from raw encrypted content and never decrypted.
- **Fix:** Each newly constructed `MatrixEvent` is now passed through `mx.decryptEventIfNeeded()` before rendering when `evt.isEncrypted()` is true.
### 2. Audio Playback Rate Reset
**File:** `src/app/components/message/content/AudioContent.tsx` (Line 97)
**Status:** UX Bug
### 2. Service Worker Ephemeral Sessions
* **Issue:** The `playbackRate` is set in a `useEffect` that only depends on `[playbackSpeed]`.
* **Impact:** If a user selects a playback speed *before* the audio blob has finished loading, the `<audio>` element may reset its rate to 1.0 once the `<source>` is added.
* **Recommended Fix:** Add `srcState.data` to the `useEffect` dependencies or set the `playbackRate` in an `onCanPlay` handler on the audio element.
**File:** `src/sw.ts`
**Status:** **NOT A BUG — by design**
### 3. Room Insights are Static (No Live Updates)
**File:** `src/app/features/room-settings/RoomInsights.tsx` (Line 60)
**Status:** Medium Priority
- The `sessions` Map is intentionally in-memory. The main window re-posts the session to the SW via `postMessage` on every load. Persisting access tokens in SW IndexedDB would duplicate credential storage unnecessarily and is not required for the current feature set.
---
## 📱 PWA & Mobile Issues
### 1. No PWA Precaching (Offline Mode Broken)
**File:** `src/sw.ts`, `vite.config.js`
**Status:** **DEFERRED — out of scope**
- Full offline Matrix requires persisting sync state, E2EE keys, and an event send queue. The SW exists for authenticated media and notifications, which it handles correctly. Adding Workbox precaching is a multi-sprint project with limited benefit for a Matrix client.
### 2. PiP Resize Impossible on Mobile
* **Issue:** Stats are calculated in a `useMemo` that only depends on `[room]`.
* **Impact:** If new messages arrive while the Insights page is open, the statistics (message counts, top participants, etc.) do not update.
* **Recommended Fix:** Add a listener for `RoomEvent.Timeline` inside the component to trigger a recalculation when new events are added to the room.
### 4. Incorrect Ringing in Voice Rooms
**File:** `src/app/components/CallEmbedProvider.tsx`
**Status:** **FIXED**
**Status:** Logic Bug
- **Issue:** Resize corner `onMouseDown` handlers did not fire on touch devices.
- **Fix:** Added `handleResizeTouchStart` using touch events with the same geometry math extracted into a shared `applyResize` helper. `onTouchStart` is now wired to all four resize corners.
* **Issue:** Joining a static voice room (Public Space channel) triggers the "Incoming Call" ringing animation and sound. This should only occur for "StartedByUser" intents (DMs and Private Group Calls).
* **Root Cause:** The ringing logic does not distinguish between persistent voice rooms and user-initiated calls.
* **Recommended Fix:** Check `room.getJoinRule()` or check for the `m.space.parent` event. If the room is a public voice channel, suppress the ringing animation.
### 3. Double Background Animation (GPU Waste)
---
**File:** `src/app/pages/client/SidebarNav.tsx`, `src/app/features/room/RoomView.tsx`
**Status:** **FIXED**
## 🎨 UI/UX & Visual Consistency
- **Issue:** When Glassmorphism is enabled, the chat background was rendered on both `document.body` and `RoomView`, running the same CSS animation twice.
- **Fix:** `RoomView` now reads the `glassmorphismSidebar` setting and skips applying `chatBgStyle` when it is active, relying entirely on the `document.body` background that `SidebarNav` already mirrors.
### 1. Hardcoded Primary Color in Polls
**File:** `src/app/components/message/content/PollContent.tsx` (Line 245)
**Status:** TDS Violation
* **Issue:** Uses `rgba(var(--mx-primary-rgb, 0,132,255), ...)` for selected options and borders.
* **Impact:** Polls look like standard Cinny and ignore the Lotus Terminal Design System (TDS) colors.
* **Recommended Fix:** Use `var(--lt-accent-cyan)` or the primary theme accent color.
### 2. Inaccessible Room Menu on Mobile
**File:** `src/app/features/room-nav/RoomNavItem.tsx` (Line 643)
**Status:** **MOBILE BUG**
* **Issue:** The room menu icon (`VerticalDots`) is hidden on mobile because `hover` is never active.
* **Impact:** Mobile users cannot access room settings, mark as read, or leave rooms from the sidebar.
* **Recommended Fix:** Ensure the menu button is visible on mobile for the active room or provide an alternative trigger.
### 3. Inconsistent Settings Dropdown Styling
**File:** `src/app/features/settings/general/General.tsx`
**Status:** UI Consistency
* **Issue:** The dropdowns for "Join & Leave Sounds" and "UI Font" use raw HTML `<select>` elements, which look different from the custom-styled `Menu` used elsewhere.
* **Recommended Fix:** Replace raw selects with the `Menu` + `PopOut` pattern used in the "Message Layout" setting.
### 4. No Camera Focus During Screenshare
**File:** `src/app/features/call/CallControls.tsx`
**Status:** UX Bug
* **Issue:** When someone is screensharing and another participant turns on their camera, there is no way to switch the primary display to the camera or go fullscreen on it.
* **Recommended Fix:** Implement a "Pin/Focus" toggle on participant tiles that overrides the automatic screenshare spotlight.