cranpose_navigation/
saved_scroll.rs1use cranpose_core::remember;
14use cranpose_services::{SaveableRegistration, SaveableScope};
15use cranpose_ui::{
16 LazyGridState, LazyListState, LazyStaggeredGridState, PagerState, ScrollState, composable,
17};
18
19fn format_position((index, offset): (usize, f32)) -> String {
21 format!("{index} {offset}")
22}
23
24fn parse_position(stored: &str) -> Option<(usize, f32)> {
25 let (index, offset) = stored.split_once(' ')?;
26 Some((index.parse().ok()?, offset.parse().ok()?))
27}
28
29fn remember_saved<S, P>(
34 key: &'static str,
35 parse: fn(&str) -> Option<P>,
36 format: fn(P) -> String,
37 create: impl FnOnce(Option<P>) -> S,
38 read: fn(&S) -> Option<P>,
39) -> S
40where
41 S: Clone + 'static,
42 P: 'static,
43{
44 remember(move || {
45 let scope = SaveableScope::current();
46 let state = create(scope.restore(key).as_deref().and_then(parse));
47 let saved = state.clone();
48 let registration: SaveableRegistration =
49 scope.register(key, move || read(&saved).map(format));
50 (state, registration)
51 })
52 .with(|(state, _)| state.clone())
53}
54
55#[composable]
58pub fn rememberSaveableLazyListState(key: &'static str) -> LazyListState {
59 remember_saved(
60 key,
61 parse_position,
62 format_position,
63 |restored| {
64 let (index, offset) = restored.unwrap_or_default();
65 LazyListState::new(index, offset)
66 },
67 LazyListState::try_position,
68 )
69}
70
71#[composable]
75pub fn rememberSaveableLazyGridState(key: &'static str) -> LazyGridState {
76 remember_saved(
77 key,
78 parse_position,
79 format_position,
80 |restored| {
81 let state = LazyGridState::new();
82 if let Some((index, offset)) = restored {
83 state.scroll_to_item(index, offset);
84 }
85 state
86 },
87 LazyGridState::try_position,
88 )
89}
90
91#[composable]
93pub fn rememberSaveableLazyStaggeredGridState(key: &'static str) -> LazyStaggeredGridState {
94 remember_saved(
95 key,
96 parse_position,
97 format_position,
98 |restored| {
99 let (index, offset) = restored.unwrap_or_default();
100 LazyStaggeredGridState::new(index, offset)
101 },
102 LazyStaggeredGridState::try_position,
103 )
104}
105
106#[composable]
109pub fn rememberSaveablePagerState(key: &'static str, initial_page: usize) -> PagerState {
110 remember_saved(
111 key,
112 |stored| stored.parse().ok(),
113 |page: usize| page.to_string(),
114 |restored| PagerState::new(restored.unwrap_or(initial_page)),
115 PagerState::try_first_page,
116 )
117}
118
119#[composable]
122pub fn rememberSaveableScrollState(key: &'static str) -> ScrollState {
123 remember_saved(
124 key,
125 |stored| stored.parse().ok(),
126 |value: f32| value.to_string(),
127 |restored| ScrollState::new(restored.unwrap_or_default()),
128 ScrollState::try_value,
129 )
130}