Files
readest/apps/readest-app/src-tauri/plugins/tauri-plugin-native-bridge/tests/reading_widget.rs
T
Huang Xin 7da41a65ad feat(widget): add mobile home-screen reading widgets (#1602) (#4842)
Add a resizable home-screen widget on iOS and Android showing recent
in-progress books with cover, reading progress, and tap-to-open.

- One responsive widget: Android resizable 1x1 to 4x3 (one book per
  column, up to 3); iOS Small/Medium/Large families. Covers are cropped,
  rounded, with a percent badge and a progress bar (baked into the bitmap
  on Android, SwiftUI overlays on iOS).
- TTS controls (previous, play-pause, next) appear in 2+ row sizes when
  TTS is active, wired to the existing media session. Reading progress
  stays live during background TTS via a fraction computed from the baked
  offline locations.
- Publishes a snapshot plus downsized cover thumbnails to the iOS App
  Group and Android SharedPreferences through a new update_reading_widget
  native-bridge command; refresh is debounced and driven by library and
  progress changes, TTS, and app backgrounding.
- Tapping a cover opens readest://book/{hash}, switching the reader in
  place when one is already open.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:03:16 +02:00

42 lines
1.3 KiB
Rust

use tauri_plugin_native_bridge::UpdateReadingWidgetRequest;
#[test]
fn deserializes_camel_case_payload() {
let json = r#"{
"books": [{"hash":"h1","title":"T","author":"A","percent":72,"coverPath":"/x/h1/cover.png"}],
"sectionTitle": "Continue reading",
"emptyTitle": "Your books will appear here"
}"#;
let req: UpdateReadingWidgetRequest = serde_json::from_str(json).unwrap();
assert_eq!(req.books.len(), 1);
assert_eq!(req.books[0].percent, 72);
assert_eq!(req.books[0].cover_path, "/x/h1/cover.png");
assert_eq!(req.section_title, "Continue reading");
assert!(req.tts.is_none());
}
#[test]
fn deserializes_tts_field_when_present() {
let json = r#"{
"books": [],
"sectionTitle": "S",
"emptyTitle": "E",
"tts": {"active": true, "playing": false}
}"#;
let req: UpdateReadingWidgetRequest = serde_json::from_str(json).unwrap();
let tts = req.tts.expect("tts should be Some");
assert_eq!(tts.active, true);
assert_eq!(tts.playing, false);
}
#[test]
fn tts_is_none_when_absent() {
let json = r#"{
"books": [],
"sectionTitle": "S",
"emptyTitle": "E"
}"#;
let req: UpdateReadingWidgetRequest = serde_json::from_str(json).unwrap();
assert!(req.tts.is_none());
}