forked from akai/readest
7da41a65ad
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>
42 lines
1.3 KiB
Rust
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());
|
|
}
|