Files
readest/apps/readest-app/.claude/memory/platform-compat-fixes.md
T
Huang Xin 78794499a2 fix(dictionary): correct System Dictionary platform gating on web and iPad (#4362)
* fix(dictionary): keep other dictionaries usable when System Dictionary syncs to an unsupported platform

`dictionarySettings.providerEnabled` is whole-field synced across devices, so enabling System Dictionary on macOS/iOS sets the flag on web/Linux/Windows too. There the row is hidden and the feature is a no-op, but the settings UI read the raw flag and locked every other dictionary's toggle read-only. Gate the lock on `isSystemDictionaryEnabled(settings)` — the same platform-aware check the annotator uses — so it matches real lookup behavior and never triggers where the system dictionary can't run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(dictionary): dispatch system dictionary handoff by native OS (fixes iPad)

iPadOS sends a desktop "Macintosh" user agent, so the UA-based `getOSPlatform()` reported iPad as 'macos' and the handoff invoked the macOS-only `show_lookup_popover` Rust command that iOS never registers ("Command show_lookup_popover not found"). Derive the OS from the app service's `is*App` capability flags (sourced from the Tauri OS plugin, correct on iPad) via a new synchronous `getInitializedAppService()` accessor, so iPad routes to the iOS plugin command path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ui): constrain reader View Options dropdown to h-8

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(agent): note System Dictionary platform-detection and synced-flag patterns

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 09:51:22 +02:00

4.6 KiB

Platform Compatibility Fixes Reference

Android

WebView API Issues

  • navigator.getGamepads() returns null on older WebView (#3245): Always null-check before .some()
  • CompressionStream unavailable on some Android WebView versions (#3255): Add fallback zip compression path
  • Annotation tools unresponsive (#3225): Don't call makeSelection() immediately on pointer-up; let popup flow complete naturally
  • Safe inset updates (#3469): Call onUpdateInsets() after setSystemUIVisibility()
  • Navigation bar overlap (#3466): Use calc(env(safe-area-inset-bottom) + 16px) for bottom padding

General Android Rules

  • Test with older WebView versions (97+)
  • Always check API availability before calling Web APIs
  • Touch event handling differs from iOS - avoid premature re-selection

iOS

Common Issues

  • Slider touch dead zones (#3382): Strip native appearance, use larger hit areas (min-h-12)
  • Safe area insets stale (#3395): Native Swift plugin must push updated insets
  • Section content caching (#3242, #3206): Don't cache section content in foliate-js when updating subitems; cached content retains stale styles after mode switch
  • CompressionStream (#3255): Also broken on iOS 15.x; zip.js has its own native API disable
  • zip.js native API (#3170): Disable native CompressionStream/DecompressionStream on iOS 15.x

iPad reports a desktop UA → never branch native dispatch on getOSPlatform()

  • getOSPlatform() (utils/misc) is user-agent based, and iPadOS sends a desktop "Macintosh" UA → it returns 'macos' on iPad. Any native-OS dispatch keyed on it misroutes iPad to the macOS path.
  • Symptom seen: system dictionary on iPad threw "Command show_lookup_popover not found" — the macOS-only Rust command (src-tauri/src/macos/system_dictionary.rs); iOS only registers the plugin command plugin:native-bridge|show_lookup_popover.
  • Rule: for OS-specific native dispatch/capability, use appService.isIOSApp / isMacOSApp / isAndroidApp (derived from the Tauri OS plugin type()OS_TYPE in nativeAppService.ts), NOT getOSPlatform(). The misc.ts comment says this explicitly.
  • Sync, non-React modules: getInitializedAppService() (environment.ts) returns the cached singleton synchronously (null pre-init). Used by systemDictionary.ts for isSystemDictionarySupported() (sync) + invokeSystemDictionary() (async).

iOS-Specific Code

  • src-tauri/plugins/tauri-plugin-native-bridge/ios/Sources/NativeBridgePlugin.swift
  • Slider CSS: -webkit-appearance: none; appearance: none in globals.css
  • useSafeAreaInsets.ts hook

macOS

Traffic Lights (Window Controls)

  • Check isFullscreen() before hiding (#3129)
  • Use timeouts (100ms) for visibility transitions (#3488)
  • Don't hide when sidebar is open (#3488)

Input Issues

  • Context menu steals event loop (#3324): 100ms setTimeout before calling menu.popup()
  • Touchpad natural scrolling (#3127): Respect system setting in usePagination.ts
  • Two-finger swipe (#3127): Support trackpad two-finger swipe for pagination

macOS-Specific Code

  • src-tauri/src/macos/ - Platform-specific Rust code
  • src/store/trafficLightStore.ts
  • src/hooks/useTrafficLight.ts

Linux

WebKitGTK Issues

  • View Transitions API unsupported (#3417): Feature-detect document.startViewTransition before calling
  • Use useAppRouter.ts to avoid transitions on Linux

E-ink Devices

Legibility Issues

  • Low contrast colors (#3258): Use not-eink: Tailwind variant prefix for colors/opacity
  • Links invisible (#3258): Don't apply text-primary (blue) on e-ink; use default text color
  • Opacity too low (#3258): Don't apply opacity-60/opacity-75 on e-ink devices
  • Highlight visibility (#3299): Use foreground color for highlights in dark mode e-ink

E-ink CSS Pattern

// Instead of:
className="text-primary opacity-60"
// Use:
className="not-eink:text-primary not-eink:opacity-60"

Docker/Self-Hosting

  • Missing submodules (#3233): Run git submodule update --init --recursive before build
  • Simplecc WASM module must be initialized

OPDS

  • Non-ASCII credentials (#3436): Use TextEncoder + manual Base64 instead of btoa()
  • Author parsing (#3120): Handle varied metadata structures in OPDS 2.0 feeds
  • Responsive layout (#3418): Ensure catalog and download button layout works on small screens

Cross-Platform Testing Checklist

  1. Android (old WebView + current)
  2. iOS (15.x + current)
  3. macOS (traffic lights, trackpad)
  4. Linux (WebKitGTK)
  5. E-ink devices (contrast, colors)
  6. Web (CloudFlare Workers deployment)